如何从C#运行PowerShell脚本

Laj*_*pad 5 c# registry powershell impersonation

我正在尝试使用C#运行PowerShell脚本,但是没有任何成功。这是我的功能:

private void ExecutePowerShellCommand(string scriptfile)
{
    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
    runspace.Open();

    RunspaceInvoke scriptInvoker = new RunspaceInvoke();
    scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

    Pipeline pipeline = runspace.CreatePipeline();

    //Here's how you add a new script with arguments
    Command myCommand = new Command(scriptfile);
    //CommandParameter testParam = new CommandParameter("key", "value");
    //myCommand.Parameters.Add(testParam);

    pipeline.Commands.Add(myCommand);

    // Execute PowerShell script
    pipeline.Invoke();
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

拒绝访问注册表项'HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ PowerShell \ 1 \ ShellIds \ Microsoft.PowerShell'。

我该如何解决这个问题?我已经看到过模仿的想法,但是似乎没有找到任何好的模仿例子。我想以管理员身份运行此脚本。

我做了以下声明:

[DllImport("advapi32.dll")]
private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr handle);

public delegate void IncognitoDelegate(params object[] args);
Run Code Online (Sandbox Code Playgroud)

我创建了以下用于模拟的功能:

public static void Impersonate(IncognitoDelegate incognitoDelegate, params object[] args)
{
    System.IntPtr token = new IntPtr();
    WindowsIdentity wi;
    if (LogonUser("myusername", "", "mypassword", 8, 0, ref token))
    {
        wi = new WindowsIdentity(token);
        WindowsImpersonationContext wic = wi.Impersonate();

        incognitoDelegate(args);

        wic.Undo();
    }
    CloseHandle(token);
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个用作委托的函数:

private static void GIncognito(params object[] args)
{
    RunspaceInvoke scriptInvoker = new RunspaceInvoke();
    scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
}
Run Code Online (Sandbox Code Playgroud)

而且我修改了我的方法:

private void ExecutePowerShellCommand(string scriptfile)
{
    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
    runspace.Open();

    Impersonate(new Util.IncognitoDelegate(GIncognito));
    //RunspaceInvoke scriptInvoker = new RunspaceInvoke();
    //scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

    Pipeline pipeline = runspace.CreatePipeline();

    //Here's how you add a new script with arguments
    Command myCommand = new Command(scriptfile);
    //CommandParameter testParam = new CommandParameter("key", "value");
    //myCommand.Parameters.Add(testParam);

    pipeline.Commands.Add(myCommand);

    // Execute PowerShell script
    pipeline.Invoke();
}
Run Code Online (Sandbox Code Playgroud)

结果是...

...非常严重的错误,告诉我我无法访问注册表项。

Jar*_*ger 1

默认Set-ExecutionPolicy命令尝试设置机器范围的值。您只想在 C# 应用程序范围内更改设置,因此您应该将该-Scope Process选项添加到命令中。

使用Get-Help Set-ExecutionPolicy -detailed揭示了这些信息:

注意:要更改默认 (LocalMachine) 范围的执行策略,请使用“以管理员身份运行”选项启动 Windows PowerShell。

...它还描述了该-Scope选项。

这样做的优点是影响从 C# 应用程序运行的脚本的执行策略,并且不会不必要地更改默认 PowerShell 行为的执行策略。(所以它更安全,特别是如果您可以保证应用程序运行的脚本的有效性。)