Search code examples
performancepowershellpowershell-3.0remote-serverpowershell-remoting

Powershell Script Running Slowly


I'm writing a script to check the version on about 15 remote servers and the script is taking much longer to execute than I would expect.

$listServers = @("compName1", "compName2", "compName3", ... "compName15")

"" | Out-File C:\temp\javaVersion.txt
"" | Out-File C:\temp\javaVersionLog.txt
$cred = Get-Credential

ForEach ($server in $listServers) 
{
     Measure-Command {$javaVersion = Invoke-Command -ComputerName $server -Credential $cred -Authentication Kerberos -ScriptBlock {Get-WmiObject -Class Win32_Product -Filter "Name like 'Java [0-9]%'" | Select -ExcludeProperty Version}} -ErrorAction SilentlyContinue -ErrorVariable errorOutput
     $errorOutput | Out-File C:\temp\javaVersionLog.txt -Append
     $server + $javaVersion | Out-File C:\temp\javaVersion.txt -Append
 }

This takes about 21 seconds to complete according to the Measure-Command output. Is there a reason I'm missing that the script is taking so long to complete?

Edit:

After being distracted by other issues, I finally finished the script.

Start-Transcript C:\temp\javaVersion.txt
$listServers = @("compName1", "compName2", "compName3", ... "compName15")
$javaVersVerbose = ""

Invoke-Command -ComputerName $listServers -ScriptBlock {
    $registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $_);
    $javaKey = $registry.OpenSubKey('SOFTWARE\JavaSoft\Java Runtime Environment');
    $javaVers = $javaKey.GetValue('CurrentVersion');
    $javaVersVerbose = $javaKey.GetValue('Java' + $javaVers.Substring(2, 1) + 'FamilyVersion');
    $nameKey = $registry.OpenSubKey('SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName');
    $name = $nameKey.GetValue('ComputerName');
    $name + " " + $javaVersVerbose | echo
} -ErrorAction SilentlyContinue -ErrorVariable errorOutput

$errorOutput | echo

Write-Host -NoNewLine 'Press any key to continue...'
$null = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')

Solution

  • You don't need to do this in a loop, nor serially. invoke-command takes a collection of ComputerNames, and can run the requests in parallel.

    $listServers = @("compName1", "compName2", "compName3", ... "compName15")
    Invoke-Command -throttlelimit 4 -ComputerName $listServers -Credential $cred -Authentication Kerberos -ScriptBlock {Get-WmiObject -Class Win32_Product -Filter "Name like 'Java [0-9]%'" | Select -ExcludeProperty Version}} -ErrorAction SilentlyContinue -ErrorVariable errorOutput
    

    However, as was pointed out by Tim Ferrell, you can use Get-WMIObject to ping the servers remotely, and if you do it as a job, it will run multiple requests in parallel.

    Get-WMIObject Win32_Product  -Filter "Name like 'Java [0-9]%'" -computername $listServers -throttlelimit 4 -asjob |select -excludeproperty version
    

    Then use the Job cmdlets to receive the results.