Help with Leveraging Jobs

Hi everyone,

The background: I’m a PoSH enthusiast, but far from being an expert. I have a very simple PS script I run against a server that returns to me the server name, OS, last reboot time and the presence of two patches (via Get-Hotfix -id KBxxxxxxx).

I’d now like to run this script against a very large number of servers, with the names contained in a text file. I’ve managed to accomplish this by way of a foreach loop, but it can take a very long time to serially query each server. I’d like to query each server in parallel which brings me to Jobs.

The question: I can start each job, but when I receive them, it’s full of a bunch of null values. I suspect this has to do with the script writing the information to the screen (lots of Write-Hosts going on), but I’m not sure how to go about fixing it. Can anyone give me a nudge in the right direction?

Ben
welcome back to the forums.

Without seeing the actual script it would be sophisticated guessing. Please post your code.
What I can tell already from your description - if you have a lot of Write-Host in it, you’re doing something wrong. :wink:

And just out of curiosity …

… about how many servers are we talking about?

Thanks Olaf!

I’m away from my desk for a bit, but will post the code once I get back there. Basically, I declare a few variables, use a getWMI command using them and then write-host the results, if that’s any help.

There are roughly 450-500 servers.

There’s an old post of mine you may use as an inspiration. I’d bet it is slightly faster than your approach. :wink:

This old thing is missing the information about patches and has a lot of information you’re actually not interested in. So you should remove everything what’s not needed and add

Get-CimInstance Win32_QuickFixEngineering

to get the information about the patches you’re after. :wink:

Hi Olaf,

Sorry for the delay. Here’s the code I have right now. Please, no laughing. :wink:

$comps = Get-Content C:\a\comps.txt
foreach ($i in $comps){
    Start-Job {

$OperatingSystem = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $i
Write-Host ""
Write-Host $I.ToUpper()
Write-Host "==============="
Write-Host "Last Rebooted:   "$OperatingSystem.ConvertToDateTime($OperatingSystem.LastBootUpTime)
Write-Host "Operating System:"$OperatingSystem.caption $OperatingSystem.BuildNumber
Write-Host ""

#Windows Server 2012
if ($operatingSystem.BuildNumber -eq "9200") {
    if (Get-HotFix -ID KB5001401 -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001401 is installed (May 2021 Servicing Stack Update)" -ForegroundColor Green}
        else {Write-Host "KB5001401 is not installed (May 2021 Servicing Stack Update)" -ForegroundColor Red}
       if (Get-HotFix -ID KB5001383  -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001383 is installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Green}
        else {Write-Host "KB5001383 is not installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Red}
    Write-Host ""
}
#Windows Server 2012 R2
if ($OperatingSystem.BuildNumber -eq "9600") {
    if (Get-HotFix -ID KB5001403 -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001403 is installed (May 2021 Servicing Stack Update)" -ForegroundColor Green}
        else {Write-Host "KB5001403 is not installed (May 2021 Servicing Stack Update)" -ForegroundColor Red}
    if (Get-HotFix -ID KB5001393 -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001393 is installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Green}
        else {Write-Host "KB5001393 is not installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Red}

    Write-Host ""
}

#Windows Server 2019
if ($OperatingSystem.BuildNumber -eq "17763") {
    if (Get-HotFix -ID KB5001404 -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001404 is installed (May 2021 Servicing Stack Update)" -ForegroundColor Green}
        else {Write-Host "KB5001404 is not installed (May 2021 Servicing Stack Update)" -ForegroundColor Red}
       if (Get-HotFix -ID KB5001342  -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001342 is installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Green}
        else {Write-Host "KB5001342 is not installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Red}

    Write-Host ""
}

#Windows Server 2016
if ($OperatingSystem.BuildNumber -eq "14393") {
    if (Get-HotFix -ID KB5001402 -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001402 is installed (April 2021 Servicing Stack Update)" -ForegroundColor Green}
        else {Write-Host "KB5001402 is not installed (April 2021 Servicing Stack Update)" -ForegroundColor Red}
    if (Get-HotFix -ID KB5001347  -ComputerName $I -ErrorAction SilentlyContinue)
        {Write-Host "KB5001347 is installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Green}
        else {Write-Host "KB5001347 is not installed (April 2021 Security Only Quality Rollup)" -ForegroundColor Red}


    Write-Host ""
}
}
}

Ben,
as I already mentioned using Write-Host is not considered as a good style.

I prefer a little “cleaner” style like this:

$ComputerList = Get-Content -Path 'C:\a\comps.txt'

$ResultList =
foreach ($ComputerName in $ComputerList) {
    $CimSession = New-CimSession -ComputerName $ComputerName
    $OS         = Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession
    $Patches    = Get-CimInstance -ClassName Win32_QuickFixEngineering -CimSession $CimSession

    [PSCustomObject]@{
        ComputerName   = $ComputerName
        OS             = $OS.Caption
        BuildNumber    = $OS.BuildNumber
        LastBootUpTime = $OS.LastBootUpTime
        KB5001401      = $Patches.HotFixID.Contains('KB5001401')
        KB5001383      = $Patches.HotFixID.Contains('KB5001383')
        KB5001403      = $Patches.HotFixID.Contains('KB5001403')
        KB5001393      = $Patches.HotFixID.Contains('KB5001393')
        KB5001404      = $Patches.HotFixID.Contains('KB5001404')
        KB5001342      = $Patches.HotFixID.Contains('KB5001342')
        KB5001402      = $Patches.HotFixID.Contains('KB5001402')
        KB5001347      = $Patches.HotFixID.Contains('KB5001347')
    }
}
$ResultList

The output is not as verbose as yours but I’d bet it’s going to be faster than yours even without adding a complexity level with using jobs. This way you can use the output an export it to a CSV file for later use for example or even pipe it to further cmdlets to filter only the desired information.