Run/deposit C# 中的 Powershell 脚本

Run/deposit a Powershell Script in C#

我正在尝试从 c#

中的资源文件夹中 运行 一个 ps1 脚本

感谢Yevhen Cherkes

.NET Get embedded Resource File

离我更近了。

改变

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

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();
        }
    }

这只会引发整个 ps 脚本的异常 - 不称为 cmdlet - 虽然它确实读取了它但 addcommand 运行 之前的脚本。现在只是简单的 AddScript 还是我仍然在接近它?

提前致谢

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();
        }
    }

是我的问题的解决方案。 我包含了上述线程的解决方案并将 AddCommand 更改为 AddScript(我知道为什么 addcommand 可以从本地文件读取它,但在这种情况下却没有)

让我添加一些背景信息 :

注意:您的问题归结为必须从 .AddCommand() 切换到脚本-file 执行 (.ps1) 到 .AddScript() 用于 source-code string 执行(来自资源)。下面主要关注脚本-file执行时,什么时候使用.AddCommand() vs. .AddScript()

  • .AddCommand() 是调用 脚本文件的正确 PowerShell SDK 方法 (.ps1) 和其他 命令形式 ,即 cmdlet、函数和外部程序。

    • 一个潜在的问题是 有效的 PowerShell execution policy 可能 阻止 脚本文件的执行 。在原始机器 运行 Windows desktop 版本中,script-file 执行默认完全禁用 (Restricted),而 RemoteSigned 服务器 机器上。

    • 假设有效的执行策略不会阻止 script-file 通过 GPO 执行 (组策略对象),您可以通过 SDK为当前 PowerShell 会话(仅)设置执行策略来解决此问题; RemoteSigned(browser-downloaded 文件必须具有有效签名)通常是安全的选择:

      // 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);
      // ...
      
      • 如果 GPO-controlled 执行策略阻止您设置会话的执行策略(或者您只是想避免显式设置会话执行策略),您可以使用 .AddScript() 作为 解决方法,如下所述 - 但请注意它具有 限制 副作用 .
  • 名称有点令人困惑的 .AddScript() 方法用于调用 直接作为字符串 [=103= 提供的 PowerShell 源代码],可以说,脚本文件的 内容,或者,在您的情况下,从程序集中嵌入的资源中检索到的一段 PowerShell 代码。

    • 因此,只要给定脚本文件的内容(代码)不(直接或间接[1])调用其他脚本文件,你可以使用.AddScript()绕过 PowerShell的执行策略(只适用于脚本文件).

    • 也就是说,如您的回答所示,您可以将 .ps1 文件的内容 读入内存中的字符串 前面,并将该字符串传递给 .AddScript();最简单的打点方法是使用 System.IO.File.ReadAllText:

      ps.AddScript(File.ReadAllText(skriptpath));
      // Call ps.AddParameter() as needed.
      
    • 警告:此技术的副作用是script-file主体以这种方式调用将不知道脚本文件的原始文件名位置


[1] 请注意,某些模块在导入期间会自动执行 .ps1 文件,并且模块导入本身可能会自动发生。