我从一个名为 vms.txt 的 txt 文件开始。
它包含 2 个服务器,如下所示:
server1
server2
当我运行下面所示的脚本时,调用来安装 VMware 工具的命令仅在 server2 上运行,而 server1 会被跳过。有人对如何修改此脚本以使其在 txt 文件中的两台服务器上运行有任何建议吗?将来我将不得不在数百个虚拟机上运行它,因此我正在尝试找到一种简单的方法来使其正确循环。
$cred = Get-Credential
$vms = Get-Content C:\Scripts\Tools\vms.txt
foreach($vm in $vms){
$sessions = New-PSSession -ComputerName $vm -Credential $cred
}
foreach($session in $sessions)
{
Invoke-Command -Session $session -ScriptBlock {
c:\users\jsmith\documents\VMware-tools-10.3.5.exe /v "/qn REBOOT=R Remove=AppDefense,VMCI”
}
}
最佳答案
在基于循环的方法中,问题在于变量分配:
# !! This only ever stores the *last* session created in $sessions,
# !! because the assignment is performed in *each iteration*.
foreach($vm in $vms){
$sessions = New-PSSession -ComputerName $vm -Credential $cred
}
立即修复是将作业移出循环:
# OK - captures *all* session objects created in $sessions
$sessions = foreach($vm in $vms){
New-PSSession -ComputerName $vm -Credential $cred
}
退后一步:
两者New-PSSession
-ComputerName
和 Invoke-Command
-Session
接受计算机名称/ session 的数组,因此不需要循环。
将多个 session /计算机名称传递给
Invoke-Command
具有操作运行的巨大优势>并行。注意:
Invoke-Command
具有内置限制,以避免一次针对太多计算机。默认为 32,但可以使用-ThrottleLimit
参数进行修改。- 来自目标计算机的输出将以不可预测的顺序到达,但输出对象用(除其他外)反射(reflect)原始计算机的
.PSComputerName
属性进行修饰 - 请参阅 this answer 的底部部分.
也就是说,您的代码可以简化为:
$cred = Get-Credential
$vms = Get-Content C:\Scripts\Tools\vms.txt
$sessions = New-PSSession -ComputerName $vms -Credential $cred
Invoke-Command -Session $sessions -ScriptBlock {
c:\users\jsmith\documents\VMware-tools-10.3.5.exe /v "/qn REBOOT=R Remove=AppDefense,VMCI”
}
重要:
- session 最终应使用
Remove-PSSession
进行清理当不再需要时。 - 但是,这会停止在这些 session 中运行的任何命令,因此,如果您通过
Invoke-Command
调用启动了异步操作,则需要确保这些操作首先已完成 - 请参阅下面有关VMware-tools-10.3.5.exe
应用程序可能异步执行的注释。
或者,更简单的是,如果您只需要在每台计算机上执行一个命令,在这种情况下不需要显式创建 session ,则传递所有计算机名称直接到 Invoke-Command
的 -ComputerName
参数:
$cred = Get-Credential
$vms = Get-Content C:\Scripts\Tools\vms.txt
# Note the use of -ComputerName
Invoke-Command -ComputerName $vms -Credential $cred -ScriptBlock {
# Note the use of | Write-Output to ensure synchronous execution.
c:\users\jsmith\documents\VMware-tools-10.3.5.exe /v "/qn REBOOT=R Remove=AppDefense,VMCI” | Write-Output
}
重要:
如果您的应用程序 (
VMware-tools-10.3.5.exe
) 异步运行,您必须确保其 同步执行,否则可能无法运行完成,因为当脚本 block 从给定计算机返回时,隐式创建的远程 session 将被丢弃。确保任何外部(GUI 子系统)可执行文件同步执行的一个简单技巧是将其通过管道传输到
Write-Output
,如上所示(或Wait-Process
,如果它不产生控制台输出) - 请参阅 this answer以获得解释。
关于powershell - 让 psessions 为 txt 文件中列出的多个服务器正确循环时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71773661/