在本文中,将探讨如何在Windows 7机器上通过执行PowerShell脚本远程管理Windows Server 2008 R2服务器。将这个过程分为几个步骤,包括启用远程PowerShell执行、在C#代码中执行PowerShell命令,以及如何解析执行结果。以下是详细的步骤和示例代码。
为了在远程主机上执行PowerShell脚本,需要在远程主机和本地客户端上启用PS远程执行。以下是启用步骤:
首先,确保在远程主机和本地客户端上安装了PowerShell 4.0或更高版本。虽然4.0不是强制要求,但2.0+版本也可以使用。实际上,Windows Server 2008 R2和Windows 7默认都安装了PowerShell 2.0。
接下来,将Windows账户添加到远程主机和本地客户端的管理员组中。如果两台机器处于同一域中,可以使用域账户;如果它们处于WORKGROUP中,可以在每台机器上创建一个同名同密码的账户,并将它们都添加到管理员组中。
在远程主机上运行以下命令:
winrm quickconfig
。这个命令会自动分析并配置WinRM服务,这是远程PowerShell执行的核心服务。
请注意,winrm quickconfig
命令仅适用于实验环境的快速设置。对于生产环境,应该根据相关文档仔细配置权限和防火墙。
在启用PowerShell远程执行时,可能会遇到一些问题。可以参考相关文档找到解决方案。
要在C#代码中执行PowerShell命令,需要在项目中引用以下DLL:
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中工作。可以有多个Runspaces同时连接到不同的远程主机。
以下代码片段展示了如何创建一个本地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();
注意:Runspace和PowerShell类都实现了IDisposable接口。因此,在使用完毕后不要忘记关闭或释放它们的实例。
Runspace和PowerShell的大多数重要方法都有同步和异步形式,例如Runspace.Open和OpenAsync,Runspace.Close和CloseAsync,PowerShell.Invoke和BeginInvoke等。
PowerShell.Invoke的返回值类型是Collection<PSObject>。每个PSObject实例都以键值对的形式反映了实际对象的属性和方法。
可以使用PSObject.Members来访问实例属性,使用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 ...
以上代码片段适用于本地和远程场景。Value是Object类型。它可能是一个装箱值类型。可以调用进程的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 ...