Improving Infrastructure Security by Leveraging PowerShell

15 Nov, 2022 | 4 minutes read

Importance of infrastructure security and patch management

Security should be one of the top priorities in your infrastructure. Patch management has the utmost importance when it comes to security (just google “Patch Tuesday, Exploit Wednesday”). Network security breaches are mostly caused by missing patches in operating systems, leading to software, data loss and identity theft. It’s important that you as a company make sure your systems are patched with the latest updates as quickly as possible. Other benefits of patch management include:

  • reducing the possibility of OS crashes and downtime
  • new features and functionality
  • meet compliance standards

Automation of system checking

Manually checking every system regarding OS patches can be a tedious task. The best and most direct way to check your infrastructure’s security status is by interacting with your systems directly and not using 3rd party applications that sometimes can produce outdated or incorrect reports. On top of that, there are different Windows Server Operating Systems and all of them have different Windows updates associated with them (Windows Update Codes – KB) each month. That’s why checking our internal systems should be automated to ensure there are no weak spots in our environment.

Using PowerShell to improve infrastructure security

You can always take advantage of the rich object-oriented language – PowerShell to pull up any information regarding the Windows OS in the form of objects and automate your tasks.

In that case, the following script will check every Windows Server system for the monthly (or any other given) patch individually and directly, regardless of what Operating System version it is, and let you know of any possible outdated systems in your infrastructure.

# Initial security precaution - Run script as administrator
#Requires -RunAsAdministrator

# This script allows us to do automatic checks after the monthly patching of the Windows servers.
# More explicitly Windows server 2008 R2, 2012 R2, 2016, 2019 and 2022

Write-Host
$credentials = Get-Credential -Message "Enter your Credentials - Username@Domainname and Password in the fields bellow"

$servers = Read-Host -Prompt "`nEnter the location of the .txt file where the servers are stored.`nExample: $HOME\Desktop\servers.txt"
$servers = Get-Content $servers

#######################################################
######EDIT THESE FIELDS WITH MONTHLY PATCH#############
#######################################################

# Fields are HARD CODED and should be changed monthly with the latest KB releases
$update2008 = "KB5018454"
$update2012 = "KB5018474"
$update2016 = "KB5018411"
$update2019 = "KB5018419"
$update2022 = "KB5018421"

# Initializing $update variable so no errors occur
$update = ""

# Create an empty array
$add_updates_and_servers = @()

# Iterate over all the servers
$add_updates_and_servers = foreach ($server in $servers) {
    Write-Host "Testing $server"

    try {
        # Get the Caption (OS Version) from the remote computer
        $os_version = Get-WMIObject win32_operatingsystem -Credential $credentials -ComputerName $server -ErrorAction Stop | Select Caption 

        try {
            # Get all installed HotFixes on the remote computer
            $server_updates = Invoke-Command -ComputerName $server -Credential $credentials -ScriptBlock { Get-HotFix | Select-Object -Property HotFixID } -HideComputerName
            
            # Run checks if HotFix is installed based on OS version before, if HotFix is not present, give the value of the HotFix to $update variable
            if ($os_version -like "*2019*") {
                $updates_from_os = $server_updates | Select-Object -Property HotFixID | Where-Object -Property HotFixID -EQ $update2019 | Select-Object -ExpandProperty HotFixID
                if (!$updates_from_os) {
                    $update = $update2019
                }
            } elseif ($os_version -like "*2016*") {
                $updates_from_os = $server_updates | Select-Object -Property HotFixID | Where-Object -Property HotFixID -EQ $update2016 | Select-Object -ExpandProperty HotFixID
                if (!$updates_from_os) {
                    $update = $update2016
                }
            } elseif ($os_version -like "*2012 R2*") {
                $updates_from_os = $server_updates | Select-Object -Property HotFixID | Where-Object -Property HotFixID -EQ $update2012 | Select-Object -ExpandProperty HotFixID
                if (!$updates_from_os) {
                    $update = $update2012
                }
            } elseif ($os_version -like "*2008 R2*") {
                $updates_from_os = $server_updates | Select-Object -Property HotFixID | Where-Object -Property HotFixID -EQ $update2008 | Select-Object -ExpandProperty HotFixID
                if (!$updates_from_os) {
                    $update = $update2008
                }
            } elseif ($os_version -like "*2022*") {
                $updates_from_os = $server_updates | Select-Object -Property HotFixID | Where-Object -Property HotFixID -EQ $update2022 | Select-Object -ExpandProperty HotFixID
                if (!$updates_from_os) {
                    $update = $update2022
                }
            } else {
                # Run this if the OS version is different than Windows 2008 R2, 2012 R2, 2016, 2019 or 2022 Server
                $update = "no update for this os version"
            }

        } catch {
            # Catch Exception if Invoke-Command returns an error
            Write-Host "Cannot connect to $server via Invoke-Command" -ForegroundColor Red
            $update = "check manually"
        }
    # Catch Exception if Get-WMIObject returns an error
    } catch {
        Write-Host "Cannot gather system info for $server" -ForegroundColor Red
        $update = "check manually"
    }
     # Create a new custom PowerShell object
        [PSCustomObject]@{
            # Add the names of the servers along with the missing patch. If patch is installed updates field will be empty
            "Servers" = $server
            "Updates" = $update
        
        }

        # Clearing value from variable $update so the next server does not bring the same value from the previous one.
        Clear-Variable -Name "update"
}

# Export the results to grid view and csv
$add_updates_and_servers | Out-GridView
$add_updates_and_servers | Export-Csv -Path $HOME\Desktop\MissingUpdates.csv -NoTypeInformation
Write-Host
Write-Host "The results are exported on the Desktop in MissingUpdates.cvs file." -ForegroundColor Green
 


Summary

By taking precautions such as checking monthly updates on operating systems we will make sure that our infrastructure is stable, secure, up-to-date, and compliance-standardized which will eliminate the risks and threats to our business. Also, task automation when possible, can lead to better productivity and efficiency at the workplace. We accomplish all of that here only by using the free Microsoft scripting and shell tool – PowerShell.