PowerShell Invoke-Command批量卸载软件效率优化:如何实现多主机同时执行?
I've written a PowerShell script that reads a list of target computers from a text file and uninstalls an application on each machine. The script works, but each uninstall takes 2-3 minutes, so running it sequentially is slow. I want to know if I can run the uninstall on all target computers simultaneously to improve efficiency.
Here's my current script:
$computers = Get-Content C:\Computernames.txt foreach($Computer in $computers){ Invoke-Command -ComputerName $Computer -ScriptBlock{ $application = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Appname%'" #uninstall the app if it exists if($application){ $application.Uninstall() Write-Output "Application uninstalled successfully.." } else{ Write-Output "Application not found.." } } }
Can I avoid the loop and use Invoke-Command -ComputerName $Computers directly to run the uninstall on all machines at the same time?
Absolutely! Your intuition is spot-on — Invoke-Command natively supports parallel execution when you pass an array of computer names directly to the -ComputerName parameter. By default, it runs against up to 32 computers at once (you can tweak this with the -ThrottleLimit parameter if needed), which will slash your total runtime compared to the sequential loop you’re using now.
Here’s the modified script to run in parallel:
$computers = Get-Content C:\Computernames.txt Invoke-Command -ComputerName $computers -ScriptBlock { # Note: Win32_Product has hidden overhead (triggers MSI consistency checks) # See the note below for a faster alternative $application = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Appname%'" if ($application) { $uninstallResult = $application.Uninstall() # Verify success using the MSI return code (0 = successful) if ($uninstallResult.ReturnValue -eq 0) { Write-Output "[$env:COMPUTERNAME] Application uninstalled successfully." } else { Write-Output "[$env:COMPUTERNAME] Uninstall failed with code: $($uninstallResult.ReturnValue)" } } else { Write-Output "[$env:COMPUTERNAME] Application not found." } }
Key optimizations and tips:
- Ditch
Win32_Productfor speed: This class forces a full check of all installed MSI packages every time it’s called, which adds unnecessary delay. A better approach is to query the Windows registry directly:# Query 64-bit application registry path (adjust for 32-bit if needed) $app = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object { $_.DisplayName -like '%Appname%' } if ($app) { # Add silent uninstall parameters (adjust based on your app's requirements) $uninstallCommand = $app.UninstallString.Replace('"', '') + " /qn" Start-Process -FilePath "msiexec.exe" -ArgumentList $uninstallCommand -Wait -NoNewWindow Write-Output "[$env:COMPUTERNAME] Uncompleted successfully." } - Adjust parallelism limit: If you have dozens of machines and your network can handle it, add
-ThrottleLimit 64toInvoke-Commandto increase the number of simultaneous connections. - Handle errors gracefully: Add
-ErrorAction SilentlyContinueto skip unreachable machines, or wrap the logic in atry/catchblock to log failures explicitly. You can also use-AsJobto run the uninstalls as background jobs if you need to work on other tasks while they run.
This parallel approach will run the uninstallation on all your target machines at the same time, cutting your total wait time from hours to just a few minutes.
内容的提问来源于stack exchange,提问作者MF-

