从C#运行Powershell脚本

14

我正在尝试从C#代码运行PowerShell脚本,但是我遇到了一些(可能是环境)问题:

在我尝试运行它的机器上,发生以下情况:

  1. PowerShell以管理员身份启动并加载
  2. PowerShell窗口立即关闭(显然)且没有出现错误

注意事项:

  • 该脚本可正常工作。当我从ISE中运行它时,它可以无错误地运行。
  • 如果我右键单击该脚本并选择“使用PowerShell运行”,即使在脚本中没有更改执行策略,我也会收到执行策略错误。

Set-ExecutionPolicy:Windows PowerShell已成功更新您的执行策略,但该设置被更具体范围定义的策略覆盖。由于覆盖,您的 shell 将保留其当前有效的执行策略 RemoteSigned。键入“Get-ExecutionPolicy -List”查看您的执行策略设置。有关详细信息,请参见“Get-Help Set-ExecutionPolicy”。 在第 1 行第 46 个字符处: + if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : PermissionDenied: (:) [Set-ExecutionPolicy],SecurityException + FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand

  • Get-ExecutionPolicy -List

     Scope                ExecutionPolicy
     -----                ---------------
 MachinePolicy              Unrestricted
    UserPolicy                 Undefined
       Process                    Bypass
   CurrentUser              Unrestricted
  LocalMachine              Unrestricted
  • 我相信这是环境问题,因为:

    • 几天前它可以正常运行
    • 在其他电脑上也能正常运行
  • 这是我用来调用脚本的代码:

    if (File.Exists("Start.ps1"))
    {
        string strCmdText = Path.Combine(Directory.GetCurrentDirectory(), "Start.ps1");
    
        var process = System.Diagnostics.Process.Start(@"C:\windows\system32\windowspowershell\v1.0\powershell.exe ", strCmdText);
        process.WaitForExit();
    }
    
    脚本本身并不重要,因为我已将其更改为简单的

    Write-Host "Hello"
    $d=Read-Host
    

    我有同样的问题。


    你试过这些开关吗:-NoProfile -ExecutionPolicy UnRestricted - bot_insane
    1
    @AramKocharyan 他已经设置了机器策略,无法执行。 - Vesper
    将GP更改为无限制以避免混淆。 - Ioana Nicu
    嗯,将脚本更改为Copy-Item调用怎么样?这样你就可以跟踪它是否真的有作用了。不幸的是,我无法测试C#代码,但我可以在Powershell中模拟它。编辑:已经模拟过了,在我的电脑上,Powershell-> Powershell使用一个测试脚本是有效的,也就是说,它会等待Read-Host提供数据。 - Vesper
    请发布如何设置执行策略的精确代码,无论是C#还是Powershell代码,以及如何调用它。如果您将策略设置为更严格的策略,则可能会忽略错误。 - Vesper
    @Vesper 我从不在代码中设置策略。我有一个先决条件,即策略至少设置为远程签名。C#和PowerShell代码都在帖子底部。 - Ioana Nicu
    3个回答

    18

    问题出在脚本的路径上。在这台特定的机器上,路径中有空格,而我没有处理好。

    窗口关闭得太快,无法看到任何错误,但可以通过设置

    process.StartInfo.RedirectStandardOutput = true;
    

    帮助我抓住它。

    执行策略与我的错误无关。

    为了修复它,我像这里所解释的那样,在c#代码中更改了路径:在带有“路径中存在非法字符”的位置从CMD.EXE中执行Powershell脚本

    完整代码:

    if (File.Exists("Start.ps1"))
                {
                    File.GetAttributes("Start.ps1");
                    string strCmdText =   Path.Combine(Directory.GetCurrentDirectory(), "Start.ps1");
                    var process = new Process();
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.FileName = @"C:\windows\system32\windowspowershell\v1.0\powershell.exe";
                    process.StartInfo.Arguments = "\"&'"+strCmdText+"'\"";
    
                    process.Start();
                    string s = process.StandardOutput.ReadToEnd();
                    process.WaitForExit();
    
                    using (StreamWriter outfile = new StreamWriter("StandardOutput.txt", true))
                    {
                        outfile.Write(s);
                    }
    
                }
    

    1
    首先,更高效、灵活的一种执行 PowerShell 代码的替代方法是使用 PowerShell SDK 从 .NET 可执行文件中执行 PowerShell 代码,这种方法允许进行进程内执行并支持完整的 .NET 类型。请参见this answer以获取示例。

    虽然你自己的答案提供了一个有效的解决方案,但还有一个更简单的方法,也适用于包含'字符的脚本文件路径:

    为了通过powershell.exe(Windows PowerShell CLI)执行.ps1文件,请使用其-File参数,这只需要在嵌入的"..."中括起脚本文件路径,如果您使用.Arguments(.NET Framework)/将脚本文件路径原样传递给.ArgumentList.Add()(.NET(Core)),则允许您指定任何传递参数作为文字(带有嵌入的双引号),如果需要的话:

    # ... 
    string strCmdText = Path.Combine(Directory.GetCurrentDirectory(), "Start.ps1");
    var process = new Process();
    process.StartInfo.UseShellExecute = false;
    # ...
    process.StartInfo.FileName = @"C:\windows\system32\windowspowershell\v1.0\powershell.exe";
    // Use '-File' with embedded "..." quoting.
    process.StartInfo.Arguments = string.Format("-File \"{0}\"", strCmdText);
    // In a .NET Core / .NET 5+ application you can alternatively use:
    //   process.StartInfo.ArgumentList.Add("-File");
    //   process.StartInfo.ArgumentList.Add(strCmdText);
    # ...
    

    注意:

    • 如果未指定 -Filepowershell.exe 将假定 -Command 为目标参数,然后将所有后续参数中的(未转义的)" 剥离后,将它们解释为 PowerShell 代码 - 有关详细信息,请参见 this answer

    • 有关 PowerShell CLI 的全面概述,请参见 this answer


    -1

    由于你列出了一些策略,显然有一个群组策略应用在你的计算机上(即使它不在域中,仍然会有本地群组策略生效),它会将位于所有本地设置策略之上的MachinePolicy更改为“RemoteSigned”,这是比“Unrestricted”更强的代码执行策略。如果你的电脑在域中,你可以以本地管理员的身份运行 "Resultant Set of Policy (Logging)" 并获取影响你的电脑的域策略。如果没有,就从控制面板/管理工具运行本地安全策略,并导航到"计算机配置-管理模板-Windows 组件-Windows PowerShell",检查那里的策略值(从本地化翻译大概意思是“启用方案执行”);如果需要,可以在那里改变值。更改后,重新加载 Powershell。


    我设置了机器策略,希望它能解决问题。这就是我注意到右键单击运行脚本会进行隐藏绕过的方式。将其设置为无限制并不能解决它。 - Ioana Nicu

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接