从.NET Core 3.0中的C#执行提升的powershell脚本

从.NET Core 3.0中的C#执行提升的powershell脚本,c#,powershell,networking,.net-core,C#,Powershell,Networking,.net Core,我正在从C代码调用一个自提升的powershell脚本。脚本将重置DNS设置。 该脚本在从不相关的powershell调用时工作正常,但在从C#代码调用时没有引发异常,因此无效。 我的执行策略暂时设置为“无限制”,我正在以管理员身份运行Visual Studio 有人知道怎么了吗 C: class Program { static void Main(string[] args) { var pathToScript = @"C:\Temp\test.p

我正在从C代码调用一个自提升的powershell脚本。脚本将重置DNS设置。 该脚本在从不相关的powershell调用时工作正常,但在从C#代码调用时没有引发异常,因此无效。 我的执行策略暂时设置为“无限制”,我正在以管理员身份运行Visual Studio

有人知道怎么了吗

C:

    class Program
{
    static void Main(string[] args)
    {

        var pathToScript = @"C:\Temp\test.ps1";
        Execute(pathToScript);

        Console.ReadKey();


    }
    public static void Execute(string command)
    {
        using (var ps = PowerShell.Create())
        {
            var results = ps.AddScript(command).Invoke();
            foreach (var result in results)
            {
                Console.WriteLine(result.ToString());
            }
        }
    }


}
# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);

# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;

# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole))
{
    # We are running as an administrator, so change the title and background colour to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
    $Host.UI.RawUI.BackgroundColor = "DarkBlue";
    Clear-Host;
}
else {
    # We are not running as an administrator, so relaunch as administrator

    # Create a new process object that starts PowerShell
    $newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";

    # Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
    $newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"

    # Indicate that the process should be elevated
    $newProcess.Verb = "runas";

    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);

    # Exit from the current, unelevated, process
    Exit;
}

# Run your code that needs to be elevated here...
Set-DnsClientServerAddress -InterfaceIndex 9 -ResetServerAddresses
脚本:

    class Program
{
    static void Main(string[] args)
    {

        var pathToScript = @"C:\Temp\test.ps1";
        Execute(pathToScript);

        Console.ReadKey();


    }
    public static void Execute(string command)
    {
        using (var ps = PowerShell.Create())
        {
            var results = ps.AddScript(command).Invoke();
            foreach (var result in results)
            {
                Console.WriteLine(result.ToString());
            }
        }
    }


}
# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);

# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;

# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole))
{
    # We are running as an administrator, so change the title and background colour to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
    $Host.UI.RawUI.BackgroundColor = "DarkBlue";
    Clear-Host;
}
else {
    # We are not running as an administrator, so relaunch as administrator

    # Create a new process object that starts PowerShell
    $newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";

    # Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
    $newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"

    # Indicate that the process should be elevated
    $newProcess.Verb = "runas";

    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);

    # Exit from the current, unelevated, process
    Exit;
}

# Run your code that needs to be elevated here...
Set-DnsClientServerAddress -InterfaceIndex 9 -ResetServerAddresses

正如您刚刚确定的,主要的问题是在您的系统上禁用了脚本执行,需要(至少)对PowerShell的进程级别进行更改,如下C#代码所示,它调用
调用脚本文件(
*.ps1
)之前,
-作用域进程-ExecutionPolicy旁路:

类程序
{
静态void Main(字符串[]参数)
{
var pathToScript=@“C:\Temp\test.ps1”;
执行(pathToScript);
Console.ReadKey();
}
公共静态void执行(字符串命令)
{
使用(var ps=PowerShell.Create())
{
//确保至少为启用了脚本执行
//目前的进程。
//为了更安全,您可以尝试保存和恢复
//执行脚本后先前生效的策略。
ps.AddCommand(“设置执行策略”)
.AddParameter(“范围”、“过程”)
.AddParameter(“ExecutionPolicy”、“Bypass”)
.Invoke();
//现在调用脚本并打印其成功输出。
var results=ps.AddScript(command.Invoke();
foreach(结果中的var结果)
{
Console.WriteLine(result.ToString());
}
//如果有非终止错误,也要报告。
foreach(ps.Streams.error中的var错误)
{
Console.Error.WriteLine(“Error:+Error.ToString());
}
}
}
}
请注意,代码还通过stderr(标准错误输出流)报告脚本可能报告的任何非终止错误

没有
Set ExecutionPolicy
调用,如果执行策略不允许(未签名)脚本执行,PowerShell将通过其错误流(
.Streams.error
)报告非终止错误,而不是引发异常

如果您首先选中了
.Streams.Error
,您就会更快地发现问题的具体原因

因此:

  • 使用PowerShell SDK时,除了依赖/捕获异常外,还必须检查
    .Streams.Error
    以确定是否发生了错误(至少在形式上不太严重)。

您的PowerShell脚本可能存在的问题:

    class Program
{
    static void Main(string[] args)
    {

        var pathToScript = @"C:\Temp\test.ps1";
        Execute(pathToScript);

        Console.ReadKey();


    }
    public static void Execute(string command)
    {
        using (var ps = PowerShell.Create())
        {
            var results = ps.AddScript(command).Invoke();
            foreach (var result in results)
            {
                Console.WriteLine(result.ToString());
            }
        }
    }


}
# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);

# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;

# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole))
{
    # We are running as an administrator, so change the title and background colour to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
    $Host.UI.RawUI.BackgroundColor = "DarkBlue";
    Clear-Host;
}
else {
    # We are not running as an administrator, so relaunch as administrator

    # Create a new process object that starts PowerShell
    $newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";

    # Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
    $newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"

    # Indicate that the process should be elevated
    $newProcess.Verb = "runas";

    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);

    # Exit from the current, unelevated, process
    Exit;
}

# Run your code that needs to be elevated here...
Set-DnsClientServerAddress -InterfaceIndex 9 -ResetServerAddresses
  • 在从PowerShell脚本返回之前,您不会等待提升的进程终止

  • 您没有捕获提升进程的输出,您必须通过实例的
    .RedirectStandardInput
    .RedirectStandardError
    属性捕获提升进程的输出,然后让脚本输出结果

  • 请参阅以了解如何做到这一点

下面的简化版代码解决了第一点,并通过
-ExecutionPolicy-Bypass
调用了
powershell.exe

  • 如果您使用的是Windows PowerShell SDK,则不必这样做(因为执行策略已在C#代码中更改),但如果您使用的是PowerShell[Core]SDK,则可能需要这样做,因为这两个PowerShell版本具有单独的执行策略设置

VS不会自动以管理员身份运行。代码将从.exe文件正确运行。要从VS运行,请创建VS的快捷方式。然后右键单击快捷方式并选择“以管理员身份运行”。我已以管理员身份运行。抱歉,忘了提及如果您连接到远程计算机,您需要本地和远程计算机上的管理员。然后,任何需要美元符号的路径,如//myserver/c$,c#和powershell之间的通信都是通过流进行的(请参阅:)。你计划如何进行沟通?你打算如何在c#等待PowerShell完成?请参阅:我只是通过在脚本之前添加“powershell-ExecutionPolicy Bypass-File”来实现这一点。无论如何谢谢你!