Script to check specific patches on Window 7 systems

Hi All,

I am trying to get a powershell script to test windows 7 systems for existence of certain patches in some OU and export the result of all systems which don’t have the patches to csv. I have got this far but dont get any output in the csv. I think also need to run Enable-PSRemoting on these systems.Can anyone help me please?

$systemsInOU = Get-ADComputer -Properties Name, OperatingSystem, OperatingSystemVersion, LastLogonDate -Filter { Enabled -eq $True } -SearchBase "OU=SomeOU,DC=Domain,DC=org,DC=uk" |
                Where-Object { Test-Connection $_.Name -Count 1 -Quiet } |
                Select-Object -Property Name, OperatingSystem, OperatingSystemVersion, canonicalName, LastLogonDate

foreach ($system in $systemsInOU) {
    try {
        $isPatched = Invoke-Command -ComputerName $system.Name -ErrorAction Stop -ScriptBlock {
            $patches = 'KB976373', 'KB980295', 'KB2481614', 'KB2491809', 'KB2494172', 'KB2736878', 'KB2835595' #Check Windows 7 Patches for dot1x

            if (Get-HotFix -Id $Patches -ErrorAction SilentlyContinue) {
                $true
            } else {
                $false
            }
        }
        
        if (-not $isPatched) {
            Get-CimInstance Win32_ComputerSystem -ComputerName $system.Name |
                Select-Object *,
                    @{Name="Model";     Expression={ $_.Model }},
                    @{Name="UserName";  Expression={ $_.UserName }},
                    @{Name="IPAddress"; Expression={ (Resolve-DnsName -Name $_.Name).IPAddress }},
                    @{Name="IsPatched"; Expression={ $isPatched }} |
                Export-Csv -Path C:\Scripts\NoDot1xpatches.csv -NoTypeInformation -Append
        }
    } catch {
        Write-Warning "Failed to connect to $($system.Name) ($($_.Exception.Message))"
    }
}

Well, I’m not able to run your script in my environment, but I can make some guesses.

Windows 7 may not enable WS-MAN - and therefore CIM - by default. This isn’t PSRemoting per se, but it’s similar. You might try using the legacy Get-WmiObject instead if Win7 is your only target.

Invoke-Command definitely requires PSRemoting to be enabled. You might consider reading “Secrets of PowerShell Remoting” for guidance on mass-setup of PSRemoting via GPO, if you’d like to go that route.

I’d also add some verbose or debug output so I could what was happening at each step, and what my variable contained. “Learn PowerShell Scripting in a Month of Lunches” has an excellent (if I do say so myself) chapter on debugging.

Thanks Don,

I did some research and tried doing one bit at a time and created my own logic. So far I got the small bits working but I need some help to put it all together.Here’s my logic.

Get all the windows 7 systems in a variable

$MachinesInOU = Get-ADComputer -SearchBase 'OU=SomeOU,DC=Domain,DC=ORG,dc=UK' -Filter { OperatingSystem -Like 'Windows 7 Enterprise' } -Properties OperatingSystem | Select Name

Next create a foreach loop to check for updates

$hotfixes = "KB976373", "KB980295", "KB2481614", "KB2491809", "KB2494172", "KB2736878", "KB2835595"  
$hotfix = Get-HotFix -computername $Machine | Where-Object {$hotfixes -contains $_.HotfixID} | Select-Object -property "HotFixID" 
if (Get-HotFix | Where-Object {$hotfixes -contains $_.HotfixID}) { "Found HotFix: " + $hotfix.HotFixID } 
else { "Did not Find HotFix" }	

If no updates are found then give me the system info

Get-WmiObject win32_operatingsystem -ComputerName $Machine |
                Select-Object @{Name="ComputerName";Expression={ $_.csname }},`
                              @{Name="Model";Expression={ (Get-WMIObject -ComputerName $Machine -class Win32_ComputerSystem).Model }},`
                              @{Name="UserName";Expression={ (Get-WMIObject -ComputerName $Machine -class Win32_ComputerSystem).UserName }},`
                              @{Name="IPAddress";Expression={ (Test-Connection $Machine -count 1).Ipv4Address }},`
                              @{Name="WindowsVersion";Expression={ $_.caption }}

Can anyone help me with this? Any suggestions are welcome.

Taking what you’ve done here, this would be my approach at the same task

    Clear-Host
    # Grab an computer OU from AD and get the DistinguishedName as input for the SearchBase
    # Filter for a OS type and get the NetBIOS name of the computers
    $SearchBase = (Get-ADOrganizationalUnit -Filter *).DistinguishedName[0]

    # Set pacth list to check 
    $HotfixList = "KB976373", "KB980295", "KB2481614", "KB2491809", "KB2494172", "KB2736878", "KB2835595"

    # Filter for a OS type and get the NetBIOS name of the computers
    $TargetHosts = (Get-ADComputer -SearchBase $SearchBase -Filter {OperatingSystem -Like '*server*'}).Name

    ForEach ($TargetHost  in $TargetHosts )
    {
        "`nProcessing validation on $TargetHost ********* `n"
        $HotfixCounter = 0

        ForEach ($Hotfix in $HotfixList)
        {
            #"`nValidating hotfix $Hotfix on host"

            If (Get-HotFix $TargetHost -ErrorAction SilentlyContinue)
            {"Hotfix $Hotfix is present"}
            Else 
            {
                Write-Warning -Message "Hotfix $HotFix not on host"
                $HotfixCounter ++
            }
        }
   
        "$TargetHost has a missing hotfix count of $HotfixCounter. Displaying host details"

        Get-WmiObject win32_operatingsystem -ComputerName $TargetHost |
        Select-Object @{Name="ComputerName";Expression={ $TargetHost.Name }},`
                        @{Name="Model";Expression={ (Get-WMIObject -ComputerName $TargetHost -class Win32_ComputerSystem).Model }},`
                        @{Name="UserName";Expression={ (Get-WMIObject -ComputerName $TargetHost -class Win32_ComputerSystem).UserName }},`
                        @{Name="IPAddress";Expression={ (Test-Connection $TargetHost -count 1).Ipv4Address }},`
                        @{Name="WindowsVersion";Expression={ $TargetHost.caption }}
    }


    Results 

    Processing validation on DC01 ********* 

    WARNING: Hotfix KB976373 not on host
    WARNING: Hotfix KB980295 not on host
    WARNING: Hotfix KB2481614 not on host
    WARNING: Hotfix KB2491809 not on host
    WARNING: Hotfix KB2494172 not on host
    WARNING: Hotfix KB2736878 not on host
    WARNING: Hotfix KB2835595 not on host
    DC01 has a missing hotfix count of 7. Displaying host details


    ComputerName   : 
    Model          : HVM...
    UserName       : 
    IPAddress      : 192.168...
    WindowsVersion : 


Again, this is quick edit effort, and I have no Win7 anywhere in my environment, but the premise should be the same.

Thank you very much. This exactly what I wanted. I have modified it to my needs and works very well.

Clear-Host
    # Grab an computer OU from AD and get the DistinguishedName as input for the SearchBase
    # Filter for a OS type and get the NetBIOS name of the computers
    $SearchBase = (Get-ADOrganizationalUnit -Filter *).DistinguishedName[48]

    # Set patch list to check 
    $HotfixList = "KB976373", "KB980295", "KB2481614", "KB2491809", "KB2494172", "KB2736878", "KB2835595"

    # Filter for a OS type and get the NetBIOS name of the computers
    $TargetHosts = (Get-ADComputer -SearchBase $SearchBase -Filter {OperatingSystem -Like 'Windows 7 Enterprise'}).Name

    ForEach ($TargetHost  in $TargetHosts )
    {
        "`nProcessing validation on $TargetHost ********* `n"
        $HotfixCounter = 0

        ForEach ($Hotfix in $HotfixList)
        {
            #"`nValidating hotfix $Hotfix on host"

            If (Get-HotFix -computername $TargetHost -ErrorAction SilentlyContinue)
            {"Hotfix $Hotfix is present"}
            Else 
            {
                Write-Warning -Message "Hotfix $HotFix not on host"
                $HotfixCounter ++
            }
        }
   
        "$TargetHost has a missing hotfix count of $HotfixCounter. Displaying host details"

        $CustomResult = Get-WmiObject win32_operatingsystem -ComputerName $TargetHost |
                            Select-Object @{Name="ComputerName";Expression={ (Get-WMIObject -ComputerName $TargetHost -class Win32_operatingsystem).PSComputerName }},`
                                @{Name="Model";Expression={ (Get-WMIObject -ComputerName $TargetHost -class Win32_ComputerSystem).Model }},`
                                @{Name="UserName";Expression={ (Get-WMIObject -ComputerName $TargetHost -class Win32_ComputerSystem).UserName }},`
                                @{Name="IPAddress";Expression={ (Test-Connection $TargetHost -count 1).Ipv4Address }},`
                                @{Name="WindowsVersion";Expression={ (Get-WMIObject -ComputerName $TargetHost -class win32_operatingsystem).caption }},`
                                @{Name="MissingPatches";Expression={[string]$HotfixCounter}} 
        $CustomResult | Export-CSV "C:\\scripts\NoDot1xpatches.csv" -NoTypeInformation -Append -Encoding UTF8
          
    }