使用Invoke-Command并行执行时,如何按服务器名生成唯一输出文件?
解决Invoke-Command并行执行后按服务器名导出结果的问题
你遇到的问题核心是:并行执行时本地上下文无法直接关联每一条返回结果对应的服务器,但Invoke-Command有个默认特性——它返回的所有对象都会自动带上PSComputerName属性,这个属性就是执行命令的远程服务器名称,我们可以利用这个特性实现按服务器名导出文件。
下面是两种可行的实现方式:
方法一:利用默认的PSComputerName属性分组导出
这种方法不需要修改脚本块内的逻辑,直接借助Invoke-Command自动添加的属性分组处理:
# 先确保输出目录存在 if (-not (Test-Path C:\temp)) { New-Item C:\temp -ItemType Directory | Out-Null } # 并行执行远程命令,收集所有结果 Invoke-Command -ComputerName (Get-Content c:\temp\servers.txt) ` -ErrorAction SilentlyContinue ` -ThrottleLimit 15 ` -ScriptBlock { # 替换成你实际的信息收集命令 $A = Get-Service | Select-Object -First 5 $B = Get-ChildItem C:\ -Directory | Select-Object -First 3 $C = Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version # 将多个信息合并为字符串输出 "$A`n`n$B`n`n$C" } | # 按服务器名分组,然后导出到对应文件 Group-Object -Property PSComputerName | ForEach-Object { $_.Group | Out-File "C:\temp\$($_.Name).txt" -Encoding UTF8 }
方法二:在脚本块中返回包含服务器名的自定义对象
这种方式更直观,你可以明确控制返回的内容结构:
# 确保输出目录存在 if (-not (Test-Path C:\temp)) { New-Item C:\temp -ItemType Directory | Out-Null } Invoke-Command -ComputerName (Get-Content c:\temp\servers.txt) ` -ErrorAction SilentlyContinue ` -ThrottleLimit 15 ` -ScriptBlock { # 收集信息 $A = Get-Service | Select-Object -First 5 $B = Get-ChildItem C:\ -Directory | Select-Object -First 3 $C = Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version # 返回包含服务器名和所有信息的自定义对象 [PSCustomObject]@{ ServerName = $env:COMPUTERNAME InfoA = $A InfoB = $B InfoC = $C } } | ForEach-Object { # 将对象内容格式化为字符串后导出 @" === 服务器 $($_.ServerName) 信息 === --- 服务信息 --- $($_.InfoA) --- 目录信息 --- $($_.InfoB) --- 系统信息 --- $($_.InfoC) "@ | Out-File "C:\temp\$($_.ServerName).txt" -Encoding UTF8 }
原代码失效的原因
你原来的代码中,$server变量在本地上下文不存在,而且并行返回的结果是无序混合的,直接管道到Out-File会把所有服务器的结果都写入同一个文件,无法区分归属。通过上述方法,我们把每个结果和对应的服务器名绑定,既能精准导出到对应文件,又保留了并行执行的效率。
内容的提问来源于stack exchange,提问作者Johnny Cakes
相关产品推荐
相关产品推荐

