65.9K
CodeProject 正在变化。 阅读更多。
Home

在 C# 中启用远程 PowerShell 执行

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (19投票s)

2014年6月4日

CPOL

4分钟阅读

viewsIcon

82637

downloadIcon

2129

讨论在 PowerShell 控制台中远程执行 PowerShell 脚本;还描述了如何在 C# 代码中执行相同的操作。

引言

本文介绍了如何在 PowerShell 控制台中启用远程执行 PowerShell 脚本。它还描述了如何在 C# 代码中本地或远程执行 PowerShell 脚本。

所有介绍的方法都基于我的实际工作,我的目的是通过在 Windows 7 机器上执行 PowerShell 脚本来管理远程 Windows Server 2008 R2 服务器。我将远程 Windows Server 2008 R2 服务器称为远程主机,将 Windows 7 机器称为客户端

示例代码展示了如何本地或远程执行 PowerShell 命令。在远程执行 PowerShell 命令之前,您必须先在远程主机和本地客户端上启用 PS remoting。

启用 PowerShell 远程

为了启用远程 PowerShell 执行,我执行了以下步骤:

  1. 远程主机本地客户端上安装PowerShell 4.0。4.0 不是强制的。2.0+ 即可。实际上,Windows Server 2008 R2 和 Windows 7 都默认安装了 PowerShell 2.0。
  2. 将我的 Windows 帐户添加到远程主机本地客户端管理员组。如果两台机器都在同一域中,您可以使用您的域帐户;如果都在 WORKGROUP 中,您可以在每台机器上创建一个同名同密码的帐户,并都将其添加到管理员组。
  3. 远程主机上运行以下命令:winrm quickconfig。此命令会自动分析和配置 WinRM 服务,这是远程 PowerShell 执行的核心服务。

winrm quickconfig 命令仅用于实验环境的快速设置。对于生产环境,您应根据[2][3] 仔细配置权限和防火墙。

请注意,在执行 winrm quickconfig 或其他启用 PowerShell remoting 的 cmdlet 时,您可能会遇到几个问题。您可以参考[4] 查找最常见的三种问题的解决方案

在 C# 中执行 PowerShell 脚本

要在 C# 代码中执行 PowerShell 命令,您需要引用项目中的“C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll”。注意:如果您的本地 PowerShell 版本低于 3.0,System.Management.Automation.dll 可能在不同的文件夹中。

您可能需要使用以下两个命名空间

using System.Management.Automation; 
using System.Management.Automation.Runspaces;    

您可以直接使用PowerShell实例,但更好的方法是创建一个Runspace实例每个PowerShell实例都在一个Runspace中工作。您可以拥有多个 Runspace 来同时连接到不同的远程主机。

以下代码段展示了如何创建一个本地Runspace并通过PowerShell实例执行命令:

Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{ 
    ps.Runspace = runspace;
    ps.AddScript("Get-Process"); 
    var results = ps.Invoke();
    // Do something with result ... 
}  
runspace.Close(); 

以下代码演示了如何远程执行命令

WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.ComputerName = machineAddress;
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{ 
    ps.Runspace = runspace;
    ps.AddScript("Get-Service"); 
    var results = ps.Invoke();
    // Do something with result ... 
}  
runspace.Close(); 

注意:RunspacePowerShell类都实现了IDisposable。因此,在使用完它们之后,请不要忘记关闭或释放它们的实例。

RunspacePowerShell的大多数重要方法都有同步和异步形式,例如Runspace.OpenOpenAsyncRunspace.CloseCloseAsyncPowerShell.InvokeBeginInvoke等。

在 C# 中解析结果

PowerShell.Invoke的返回值类型是Collection<PSObject>。每个PSObject实例反映了实际对象属性和方法,以键值对的形式存储在PSObject.Members中。您还可以使用PSObject.Properties访问实例属性,使用PSObject.Methods访问实例方法。注意:如果命令是在本地执行的,PSObject.BaseObject可能是实际对象。

让我们以Get-Process命令为例。当您像前面的代码段所示使用ps.Invoke()执行Get-Process时,您将获得一个Collection<PSObject>。每个PSObject实例代表一个进程。然后您可以使用以下代码检索进程成员:

// Execute Get-Process and get results ...
foreach (var result in results)
{ 
    Console.WriteLine(result.Members["Id"].Value);
    Console.WriteLine(result.Members["ProcessName"].Value);
    Console.WriteLine(result.Members["PrivateMemorySize64"].Value);
    result.Methods["Kill"].Invoke();
}
// Clean up code ...  

上面的代码段适用于本地和远程场景。 ValueObject类型。它可能是一个装箱的值类型。您可以调用进程的Kill方法,如果有适当的权限,它将成功。

如果您的代码在本地执行,您可以将PSObject.BaseObject强制转换为确切的类型实例,如下面的代码段所示:

// Code to execute Get-Process and get results ... 
foreach (var result in results) 
{ 
    var process = (System.Diagnostics.Process)result.BaseObject;
    Console.WriteLine(process.Id);
    Console.WriteLine(process.ProcessName);
    Console.WriteLine(process.PrivateMemorySize64);
    process.Kill();
}
// Clean up code ... 

如果您通过PowerShell.AddScriptPowerShell.Invoke(或BeginInvoke)执行一个大的 PS 脚本,返回值将仅包含脚本中最后一个执行的命令的结果。

更多详细信息,请参阅[1]

参考文献

大部分知识可以在以下链接中找到

© . All rights reserved.