PowerShell自动化:如何从Runspace提取PSSession对象?
从现有Runspace实例提取PSSession实现Copy-Item远程文件复制
我在开发C#应用时,已经通过以下代码创建了可执行远程命令的Runspace:
var connectionInfo = new WSManConnectionInfo() { Scheme = WSManConnectionInfo.HttpsScheme, Port = 5986, SkipCACheck = true, SkipCNCheck = true, ComputerName = Address, OperationTimeout = (int) TimeSpan.FromMinutes(4).TotalMilliseconds, OpenTimeout = (int) TimeSpan.FromMinutes(1).TotalMilliseconds, Credential = new PSCredential(_userName, _password) }; var runspace = RunspaceFactory.CreateRunspace(connectionInfo); runspace.Open();
并通过以下方法使用该Runspace执行命令:
public List<PSObject> Run(Command command) { using (var powershell = PowerShell.Create()) { powershell.Runspace = Runspace; powershell.Commands.AddCommand(command); var output = powershell.Invoke(); ThrowOnError(powershell); return output.ToList(); } }
目前这个Runspace能正常执行远程命令和脚本,但现在我想通过Copy-Item的远程会话功能实现本地到远程的文件复制,对应的PowerShell命令是:
Copy-Item -FromSession $remoteSession C:\TEMP\test.txt -Destination C:\TEMP\test.txt
这个命令需要传入$remoteSession对象,但我现在只有已创建好的Runspace实例。虽然可以在本地Runspace中调用New-PSSession创建新会话,但Runspace和PSSession关系密切,能不能直接从现有Runspace实例中提取出PSSession对象?
结论:无法直接从现有Runspace提取PSSession
Runspace和PSSession是PowerShell不同层级的对象:
- 你通过
WSManConnectionInfo创建的Runspace是直接连接到远程主机的执行环境,它本身就代表了与远程的连接,但它和PowerShell会话层的PSSession不是同一对象,没有直接的提取路径。 PSSession是PowerShell在本地维护的远程会话抽象,依赖本地Runspace来管理生命周期,和你当前的远程Runspace属于不同的对象模型。
两种替代方案
方案1:直接用现有远程Runspace实现文件上传
既然已经有了连接到远程的Runspace,不需要依赖Copy-Item -FromSession,直接在远程Runspace中执行写入文件的命令即可:
// 读取本地文件字节内容 byte[] fileBytes = File.ReadAllBytes(@"C:\TEMP\test.txt"); // 构建Set-Content命令,在远程主机写入文件 Command writeFileCmd = new Command("Set-Content") { Parameters = { {"Path", @"C:\TEMP\test.txt"}, {"Value", fileBytes}, {"Encoding", "Byte"} } }; // 用现有Runspace执行命令 Run(writeFileCmd);
方案2:复用连接信息创建PSSession
如果一定要用Copy-Item -FromSession,可以复用已有的WSManConnectionInfo参数在本地Runspace创建PSSession,PowerShell会复用底层的WSMan连接,不会重复建立新连接:
using (var localPowerShell = PowerShell.Create()) { // 构建New-PSSession命令,复用原连接的参数 Command newSessionCmd = new Command("New-PSSession") { Parameters = { {"ComputerName", connectionInfo.ComputerName}, {"Port", connectionInfo.Port}, {"UseSSL", connectionInfo.Scheme == WSManConnectionInfo.HttpsScheme}, {"Credential", connectionInfo.Credential}, {"SkipCACheck", connectionInfo.SkipCACheck}, {"SkipCNCheck", connectionInfo.SkipCNCheck} } }; // 创建并获取PSSession var psSession = localPowerShell.AddCommand(newSessionCmd).Invoke().FirstOrDefault(); if (psSession == null) throw new Exception("创建PSSession失败"); // 执行Copy-Item localPowerShell.Commands.Clear(); localPowerShell.AddCommand("Copy-Item") .AddParameter("FromSession", psSession) .AddParameter("Path", @"C:\TEMP\test.txt") .AddParameter("Destination", @"C:\TEMP\test.txt"); localPowerShell.Invoke(); ThrowOnError(localPowerShell); // 清理PSSession localPowerShell.Commands.Clear(); localPowerShell.AddCommand("Remove-PSSession").AddParameter("Session", psSession); localPowerShell.Invoke(); }
内容的提问来源于stack exchange,提问作者Alberto Chiesa
相关产品推荐
相关产品推荐

