简体   繁体   中英

Run/deposit a Powershell Script in C#

Im trying to run a ps1 script out of the resource Folder in c#

Thanks to Yevhen Cherkes

.NET Get embedded Resource File

Load C# Embedded Resource Path into PowerShell Command Class

Got me closer.

Changing

private void button1_Click_1(object sender, EventArgs e)
        {
            PowerShell ps = PowerShell.Create();
            string skriptpfad = $@"C:\Users\username\Desktop\1Tool_Final\WinformsTool\bin\Debug\zuordnung.ps1";
            ps.AddCommand(skriptpfad);
            ps.AddParameter("Source", folderBrowserDialog1.SelectedPath);
            ps.AddParameter("Destination", folderBrowserDialog2.SelectedPath);
            ps.Invoke();
        }

to

private void button1_Click_1(object sender, EventArgs e)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var resourceName = "zuordnung_test.Resources.zuordnung.ps1";

        using (Stream stream = assembly.GetManifestResourceStream(resourceName))
        using (StreamReader reader = new StreamReader(stream))
        {
            string skriptpfad = reader.ReadToEnd();
            PowerShell ps = PowerShell.Create();
            //string skriptpfad = $@"C:\zuordnung.ps1";
            ps.AddCommand(skriptpfad);
            ps.AddParameter("Source", folderBrowserDialog1.SelectedPath);
            ps.AddParameter("Destination", folderBrowserDialog2.SelectedPath);
            ps.Invoke();
        }
    }

This only throws an exception with the whole ps script - not known as cmdlet - though, it does read it but addcommand ran the script before. Is it simply AddScript now or am i still approaching it wrong?

Thanks in Advance

private void button1_Click_1(object sender, EventArgs e)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var resourceName = "%projectname%.Resources.%script.ps1%";

        using (Stream stream = assembly.GetManifestResourceStream(resourceName))
        using (StreamReader reader = new StreamReader(stream))
        {
            string skriptpath = reader.ReadToEnd();
            PowerShell ps = PowerShell.Create();
            ps.AddScript(skriptpath);
            //ps.AddParameter...
            ps.Invoke();
        }
    }

is the solution for my question. I included the solutions of the mentioned above threads and changed AddCommand to AddScript ( idk why addcommand worked with reading it from the local file and doesnt in this case )

Let me add some background information to your own (effective) answer :

Note: Your problem came down to having to switch from .AddCommand() for script- file execution ( .ps1 ) to .AddScript() for source-code string execution (from a resource). The following focuses mainly on when to use .AddCommand() vs. .AddScript() for script- file execution.

  • .AddCommand() is the right PowerShell SDK method for invoking script files ( .ps1 ) and other command forms , namely cmdlets, functions, and external programs.

    • A potential problem is that the effective PowerShell execution policy may prevent execution of script files . On pristine machines running Windows desktop editions, script-file execution is by default disabled altogether ( Restricted ), whereas it is RemoteSigned on server machines.

    • Assuming the effective execution policy doesn't prevent script-file execution via GPOs (Group Policy Objects), you can solve this problem by setting the execution policy for the current PowerShell session (only) , via the SDK ;RemoteSigned (browser-downloaded files must have a valid signature) is usually the safe choice:

       // Create an initial default session state. var iss = InitialSessionState.CreateDefault2(); // Set its script-file execution policy (for the current session only). iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned; // Create a PowerShell instance with a runspace based on the // initial session state. PowerShell ps = PowerShell.Create(iss); //... // Now, .AddCommand() should work fine. ps.AddCommand(skriptpfad); //...
      • If a GPO-controlled execution policy prevents you from setting the session's execution policy (or you simply want to avoid having to set the session execution policy explicitly), you can use .AddScript() as workaround , as discussed next - but do note that is has limitations and side effects .
  • The somewhat confusingly named .AddScript() method is for invoking PowerShell source code provided directly as a string , the content of a script file, so to speak, or, as in your case, a piece of PowerShell code retrieved from a resource embedded in an assembly.

    • Therefore, as long as a given script file's content (code) doesn't (directly or indirectly [1] ) invoke other script files, you can use .AddScript() to bypass PowerShell's execution policies (which apply only to script files ).

    • That is, as shown in your answer, you can read a .ps1 file's content into a string in memory up front, and pass that string to .AddScript() ; the simplest way to dot that is to use System.IO.File.ReadAllText :

       ps.AddScript(File.ReadAllText(skriptpath)); // Call ps.AddParameter() as needed.
    • Caveat : A side effect of this technique is that the script-file body invoked this way will be unaware of the script file's original file name and location .


[1] Note that some modules automatically execute .ps1 files during their import, and that the module import itself may happen automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM