【问题标题】:How to execute a PS script that uses remoting from C#如何从 C# 执行使用远程处理的 PS 脚本
【发布时间】:2012-09-01 16:09:28
【问题描述】:

我有一系列功能齐全的 powershell 脚本,这些脚本利用了我希望能够从 C# WinForm 调用的远程处理。这是我到目前为止的代码

    private void button1_Click(object sender, EventArgs e)
    {
        _runspace = RunspaceFactory.CreateRunspace();
        _runspace.Open();
        _ps = PowerShell.Create();

        _ps.Runspace = _runspace;

        var output = new PSDataCollection<PSObject>();
        output.DataAdded += DataAdded;

        _ps.AddScript(@"C:\projects\Acme\trunk\PowerShell\deploy-qa-p5.ps1");
        _invokeResult = _ps.BeginInvoke<PSObject, PSObject>(null, output);

    }

当我运行此代码时,我看到脚本中旨在针对远程会话执行的任何 powershell 命令实际上都在我的本地 PC 上执行。

例如,当直接从 Powershell.exe 执行这段代码时,会从远程服务器上卸载应用程序。当从上面的 C# 代码运行时,同样的代码会在我的本地机器上卸载上述应用程序:

Invoke-Command -Session $remoteSession -scriptblock $uninstallScript -ArgumentList $applicationGuid

同样,我的 C# 代码中引用的完全相同的 PS 脚本,当直接从 powershell.exe 执行时,对远程服务器按预期工作。

通过谷歌搜索,我发现了如何从 C# 创建远程运行空间。但是,这将需要我大量重构我的 PS 脚本以提取任何远程处理代码,这些代码将移至 C#。由于我仍然需要能够以独立模式(即直接从 powershell.exe)运行我的 PS 脚本,因此这不是一个可行的解决方案。

任何人都可以提出一个不需要重新调整我的 PS 脚本来解决这个问题的方法吗?

【问题讨论】:

  • 从 C# 运行时检查是否有 $remoteSession。我在 C# 中使用 Invoke-Command,但使用 -ComputerName 而不是 -Session,它对我来说工作得很好

标签: c# powershell powershell-2.0 powershell-remoting


【解决方案1】:

当您创建Runspace 对象时,您需要将WSManConnectionInfo 对象传递给它以创建远程运行空间。这个MSDN article 有关于如何做到这一点的详细信息。与本主题中的示例不同,请确保使用 WSManConnectionInfo 构造函数,该构造函数接受允许您指定远程端点的参数,例如

_runspace = RunspaceFactory.CreateRunspace("http://ComputerName:5985/wsman");

对不起,我误读了这个问题。调用恰好执行远程处理的脚本应该与从 PowerShell 控制台调用时一样有效。以下稍作修改的版本在我的家庭工作组中非常适合我:

private void button1_Click(object sender, EventArgs e)
{
    _runspace = RunspaceFactory.CreateRunspace();
    _runspace.Open();
    _ps = PowerShell.Create();

    _ps.Runspace = _runspace;

    var output = new PSDataCollection<PSObject>();
    //output.DataAdded += DataAdded;

    var netCreds = new System.Net.NetworkCredential("Keith", Settings.Default.Password);
    var creds = new PSCredential(netCreds.UserName, netCreds.SecurePassword);

    _ps.AddScript("param($creds) Invoke-Command -cn Kids-PC -Scriptblock {hostname} -Credential $creds").AddArgument(creds);
    _invokeResult = _ps.BeginInvoke<PSObject, PSObject>(null, output);
    _invokeResult.AsyncWaitHandle.WaitOne();
    _ps.EndInvoke(_invokeResult);
    textBox1.Text = output[0].ToString();
}

顺便说一句,不确定您为什么将DataAdded 添加到脚本的输出集合中?我把它注释掉了。由于我在工作组而不是域中,因此我还必须传递凭据。

为了调试它,当它失败时,请查看调试器中的 _ps.Streams.Error 对象。滚动到底部并打开Results View

【讨论】:

  • 这种方法不会让我在 PS 脚本和 C# 代码中复制我的端点吗?如果可能的话,我希望避免这种情况。
猜你喜欢
  • 1970-01-01
  • 2014-01-09
  • 1970-01-01
  • 1970-01-01
  • 2019-07-28
  • 1970-01-01
  • 2017-12-25
  • 2019-04-19
  • 1970-01-01
相关资源
最近更新 更多