The client abandons the "scripts" in the environment. How to embed * .ps1 in a C # application?

I have the following sample Powershell script that is built into my C # application.

Powershell Code

$MeasureProps = "AssociatedItemCount", "ItemCount", "TotalItemSize" $Databases = Get-MailboxDatabase -Status foreach($Database in $Databases) { $AllMBStats = Get-MailboxStatistics -Database $Database.Name $MBItemAssocCount = $AllMBStats | %{$_.AssociatedItemCount.value} | Measure-Object -Average -Sum $MBItemCount = $AllMBStats | %{$_.ItemCount.value} | Measure-Object -Average -Sum New-Object PSObject -Property @{ Server = $Database.Server.Name DatabaseName = $Database.Name ItemCount = $MBItemCount.Sum } } 

Visual Studio offers me the following implementation options:

enter image description here

Each PowerShell sample that I saw (MSDN on Exchange , and MSFT Dev Center ) required me to split the Powershell command into "bits" and send it through the parser.

I don’t want to leave a lot of PS1 files with my application, I need to have one binary file without another β€œsupporting” PS1 file.

How can I do this, so myapp.exe is the only thing my client sees?

+4
source share
6 answers

Many customers are not inclined to deviate from a policy of limited execution, because they really do not understand this. This is not a safety frontier - it's just an extra hoop to jump so you don't shoot in the leg. If you want to run ps1 scripts in your own application, just use your own working environment and use a basic authorization administrator who does not pay attention to the system execution policy:

 InitialSessionState initial = InitialSessionState.CreateDefault(); // Replace PSAuthorizationManager with a null manager which ignores execution policy initial.AuthorizationManager = new System.Management.Automation.AuthorizationManager("MyShellId"); // Extract psm1 from resource, save locally // ... // load my extracted module with my commands initial.ImportPSModule(new[] { <path_to_psm1> }); // open runspace Runspace runspace = RunspaceFactory.CreateRunspace(initial); runspace.Open(); RunspaceInvoke invoker = new RunspaceInvoke(runspace); // execute a command from my module Collection<PSObject> results = invoker.Invoke("my-command"); // or run a ps1 script Collection<PSObject> results = invoker.Invoke("c:\temp\extracted\my.ps1"); 

Using the zero authorization manager, the execution policy is completed, ignored. Remember, this is not a β€œhack,” because the execution policy is something to protect users from themselves. This is not to protect against malicious third parties.

http://www.nivot.org/nivot2/post/2012/02/10/Bypassing-Restricted-Execution-Policy-in-Code-or-in-Script.aspx

+5
source

First of all, you should try to remove client aversion to scripts. Check out the script signature, execution policy, etc.

Having said that, you can have the script as a multi-line string in the C # code itself and execute it. Since you only have one simple script, this is the easiest approach.

You can use AddScript, ethos, which takes a script as a string (not a script path)

http://msdn.microsoft.com/en-us/library/dd182436(v=vs.85).aspx

+3
source

You can embed it as a resource and retrieve it through reflection at runtime. Here is a link from MSDN . The article retrieves embedded images, but the principle is the same.

+1
source

You kind of prompted the answer yourself. By adding it as content, you can access it at runtime (see Application.GetResourceStream). You can then save this as a temporary file and execute, or figure out how to call powershell without using files.

+1
source

Keep your POSH scripts as embedded resources, then run them as needed, using something like code this MSDN stream :

 public static Collection<PSObject> RunScript(string strScript) { HttpContext.Current.Session["ScriptError"] = ""; System.Uri serverUri = new Uri(String.Format("http://exchangsserver.contoso.com/powershell?serializationLevel=Full")); RunspaceConfiguration rc = RunspaceConfiguration.Create(); WSManConnectionInfo wsManInfo = new WSManConnectionInfo(serverUri, SHELL_URI, (PSCredential)null); using (Runspace runSpace = RunspaceFactory.CreateRunspace(wsManInfo)) { runSpace.Open(); RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace); scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); PowerShell posh = PowerShell.Create(); posh.Runspace = runSpace; posh.AddScript(strScript); Collection<PSObject> results = posh.Invoke(); if (posh.Streams.Error.Count > 0) { bool blTesting = false; string strType = HttpContext.Current.Session["Type"].ToString(); ErrorRecord err = posh.Streams.Error[0]; if (err.CategoryInfo.Reason == "ManagementObjectNotFoundException") { HttpContext.Current.Session["ScriptError"] = "Management Object Not Found Exception Error " + err + " running command " + strScript; runSpace.Close(); return null; } else if (err.Exception.Message.ToString().ToLower().Contains("is of type usermailbox.") && (strType.ToLower() == "mailbox")) { HttpContext.Current.Session["ScriptError"] = "Mailbox already exists."; runSpace.Close(); return null; } else { HttpContext.Current.Session["ScriptError"] = "Error " + err + "<br />Running command " + strScript; fnWriteLog(HttpContext.Current.Session["ScriptError"].ToString(), "error", strType, blTesting); runSpace.Close(); return null; } } runSpace.Close(); runSpace.Dispose(); posh.Dispose(); posh = null; rc = null; if (results.Count != 0) { return results; } else { return null; } } } 
+1
source

The client simply cannot see the PowerShell script in what you are deploying, right? You can do whatever you want at runtime. So write it to a temporary directory β€” even try a named pipe if you want some fantasy and avoid files β€” and just start the PowerShell process.

You can even try connecting it directly to stdin. This is probably what I will try first, actually. Then you do not have a record that it is somewhere on the computer. The Process class is versatile enough to do such things without directly touching the Windows API.

0
source

Source: https://habr.com/ru/post/1395865/


All Articles