General

Find Workstations That Don't Meet The Company "Standards"

Without standards, there are more variables to manage and the burden of IT can become overbearing.

Brian Scheewe

Monday, October 23, 2023

Find Workstations That Don't Meet The Company "Standards"

standard [ stan-derd ] noun

  • something set up and established by authority as a rule for the measure of quantity, weight, extent, value, or quality

Well-run IT teams have "standards". For example: we use Dell servers. We only install Fortinet firewalls. We use Duo for all MFA. We change passwords semi-annually. We don't store files on end-user devices. We don't make any infrastructure changes on Fridays. We don't install network equipment next to water sources, etc.

Without standards, there are more variables to manage and the burden of IT can become overbearing. When systems are similar, familiar, and predictable, then support costs drop. Hopefully your team has a long list of standards and these standards have become law in your organization.

It gets even better when the business leadership buys-in to the idea of standards. Once they get it, there's no longer a fight every time something needs to be improved. When leaders understand standards, they don't think in terms of "if" a project will be approved, but "when". Helping them understand the spectrum of risks associated with not sticking to standards will help them prioritize what projects to do first.

Even carnival rides have standards.
Even carnival rides have standards.

Some standards are policy driven, and require a human to check (hey this network rack is in the boiler room!). Other standards can be automated so that when a standard is breached a notification or remediation action can be triggered.

End-user devices should meet standards, and most if not all can be automated. Today we'll walk through a PowerShell script that will check for a variety of workstation standards that are commonly established by IT teams.

Baby's porridge is just right!
Baby's porridge is just right!

Windows OS version must be at least X

This will ensure that there aren't legacy unsupported operating systems in your environment.

copy
#Set the minimum OS build number. Windows 10 v1607 is build 14393 $DesktopOSMinimumVersion = 14393 #Get the OS version $OSVer = [System.Environment]::OSVersion.Version | Select-Object -ExpandProperty Build #Alert if the OS version is less than $DesktopOSMinimumVersion if ($OSVer -lt $DesktopOSMinimumVersion) { Write-Host "ALERT: Windows version is less than $DesktopOSMinimumVersion" }

Must have less than X pending Windows Updates

If a machine has a growing list of pending Windows updates, then it time to investigate!

copy
#Set the alert threshold for pending updates quantity $PendingUpdates = 15 #Check available Windows Updates $UpdateList = ((New-Object -ComObject Microsoft.Update.Session).CreateUpdateSearcher()).Search('IsInstalled=0 and IsHidden=0').updates $NumberPendingUpdates = $UpdateList.count if ($NumberPendingUpdates -gt $PendingUpdates) { Write-Host "ALERT: There are $NumberPendingUpdates pending updates that have not been installed." }

Windows must be activated

copy
#Check if Windows is activated $ActivationStatus = Get-CimInstance SoftwareLicensingProduct -Filter "Name like 'Windows%'" | where { $_.PartialProductKey } | select -ExpandProperty LicenseStatus if ($ActivationStatus = 0) { Write-Host "ALERT: Windows is not activated." }

Workstations must have at least X GB of memory

You probably have stacks of recovered RAM sitting around your office. Put it to good use and make sure everyone has equal access to Chrome's many tabs. 😉

copy
#Set the RAM minimum threshold in GB $RAM_Minimum = 8 #Verify RAM is greater than $RAM_Minimum $RAM = (Get-WmiObject Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum | select -ExpandProperty Sum) / 1GB if ($RAM -lt $RAM_Minimum) { Write-Host "ALERT: PC has too little RAM: $RAM GB." }

CPU must be at least X generation

One of the best indicators of a machine's age is the CPU. But aside from age, we also want to ensure that company devices are performant. Taking in CPU generation and model will ensure that no one has a slow machine.

copy
# Choose the minimum CPU generations $MinimumIntelGeneration = 7 #7th gen Intel core CPUs $MinimumAmdGeneration = 2000 #2000 series of Ryzen #Get the CPU make and model $cpuInfo = Get-WmiObject Win32_Processor | Select-Object -ExpandProperty Name $CPUManufacturer = Get-WmiObject Win32_Processor | Select-Object -ExpandProperty Manufacturer # Regular expression to extract specifically the model number $regex = [regex]::Match($cpuInfo, 'i\d{1,2}-\d{1,5}|Pentium|Atom|i3|E-2\d{3}|E3-\d{4}|E5-\d{4}|\d{4} |\d{4}.| \d{3} ') if ($regex.Success) { $cpuModel = $regex.Value } else { Write-Host "ALERT: Can't determine the CPU model/generation." } # Intel CPU check. if ($CPUManufacturer -like "GenuineIntel") { # Check for Core generation and model if ($cpuModel -match 'i\d{1,2}-\d{1,5}') { $generationMatch = $cpuModel -split '-' | Select-Object -Last 1 $generation = $generationMatch -replace '\D' # Extract and convert digits only #If model number is 5 digits long, then the first 2 digits make up the generation. i7-12700 is 12th gen if ($generation.Length -eq 5) { $generation = $generation.Substring(0, 2) } #If the model is 4 digits long, then the first digit is the generation. i5-7500 is 7th gen. else { $generation = $generation[0] } #This is where we check the Intel generation against the standard if ([int]$generation -lt $MinimumIntelGeneration) { Write-Host "ALERT: The CPU generation is too old." } } elseif ($cpuModel -match 'E5-\d{4}') { #Xeon E5 generation. Eventually move this into the elseif below } #Alert on low-powered CPUs elseif ($cpuModel -match 'i3|Pentium|Atom|E3-\d{4}| \d{3} ') { Write-Host "ALERT: CPU model type does not meet standards. (i3, Pentium, Xeon E3, etc)" } } # AMD CPU Check elseif ($CPUManufacturer -like "AuthenticAMD") { # Ryzen is the standard in this case for AMD if ($cpuInfo -match 'Ryzen') { # Remove non-numeric characters and convert to int $generationMatch = $cpuModel -replace '[^\d]', '' $generation = [int]$generationMatch #Compare the CPU to the standard if ($generation -lt $MinimumAmdGeneration) { Write-Host "ALERT: The AMD CPU generation is too old." } } else { Write-Host "ALERT: CPU model type does not meet standards for AMD CPUs." } } else { Write-Host "ALERT: Not an Intel or AMD CPU" }

Files are saved on a server and not locally

In order to ensure all data is centralized, governed, and backed-up, it must be on the server. If we see files piling up in the users' My Docs folder, then that's a great indicator that someone has a bad habit.

copy
#The file count threshold before generating an alert $FileLimitInMyDocs = 30 # Count the number of files in the My Docs folders and alert if they exceed a threshold ($FileLimitInMyDocs) $UserFolderList = Get-ChildItem c:\users\ | Where-Object { $_.Name -notin @("Public", "administrator") } foreach ($User in $UserFolderList.Name) { $MyDocs = "c:\users\$User\Documents" $FileCount = (Get-ChildItem -Recurse -File $MyDocs | Measure-Object).Count if ($FileCount -gt $FileLimitInMyDocs) { Write-Host "ALERT: $User appears to be saving $FileCount files in their local My Docs folder, and not on the server." } }

No spinning disks, only SSDs

copy
# Check if the disk is an SSD $DiskType = Get-PhysicalDisk | Where-Object { $_.DeviceID -eq "0" } | select -ExpandProperty MediaType if ($DiskType -notlike "SSD") { Write-Host "ALERT: The primary disk is not an SSD and is instead a $DiskType" }

Must be joined to the Active Directory domain

copy
#Check if joined to a domain $DomainJoined = (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain if (! $DomainJoined) { Write-Host "ALERT: Not joined to a domain." }

Screen/display resolution must be X resolution or higher

Sometimes monitors get handed down to the new guy/gal. This will ensure that even the newbie isn't stuck with something that cramps productivity.

copy
#Set the minimum screen resolution $MinimumHorizontalResolution = 1920 $MinimumVerticalResolution = 1080 #Check the monitor (display) resolution isn't lower than $MinimumHorizontalResolution or $MinimumVerticalResolution $monitorInfo = Get-CimInstance Win32_VideoController $CurrentVerticalResolution = $monitorInfo.CurrentVerticalResolution $CurrentHorizontalResolution = $monitorInfo.CurrentHorizontalResolution $VerticalResolution = [int]::MaxValue $HorizontalResolution = [int]::MaxValue #If the $monitor.CurrentXResolution is blank, then use the advertised resolution from $monitorInfo.VideoModeDescription. This can happen if the monitor goes to sleep. if (($null -eq $CurrentVerticalResolution) -or ($null -eq $CurrentHorizontalResolution )) { $videoModeDescription = $monitorInfo.VideoModeDescription $resolutions = $videoModeDescription | Select-String -Pattern '(\d+) x (\d+)' if ($resolutions) { $resolutionMatches = $resolutions.Matches[0].Groups $CurrentHorizontalResolution = [int]$resolutionMatches[1].Value $CurrentVerticalResolution = [int]$resolutionMatches[2].Value } } else { # Otherwise, if there is more than one monitor, then get the lowest resolution of them all. foreach ($monitor in $monitorInfo) { if ($monitor.CurrentVerticalResolution -lt $verticalResolution) { $verticalResolution = $monitor.CurrentVerticalResolution } if ($monitor.CurrentHorizontalResolution -lt $horizontalResolution) { $horizontalResolution = $monitor.CurrentHorizontalResolution } } } #Compare the resolution with $MinimumHorizontalResolution and $MinimumVerticalResolution if (($horizontalResolution -lt $MinimumHorizontalResolution) -or ($verticalResolution -lt $MinimumVerticalResolution) ) { Write-Host "ALERT: Screen resolution is ($horizontalResolution x $verticalResolution) which is less than ($MinimumHorizontalResolution x $MinimumVerticalResolution)" }

Microsoft Outlook is at least X version

Yes this specifically checks Outlook, but this alone is a good clue about the age of all the Office apps. At the time of writing, Outlook 2013 is end-of support, so that's an easy line to draw in the sand.

copy
#Chose the minimum allowed version $MinimumOutlookVersion = 16 #Outlook 2016, 2019, Outlook 365 and above show as version 16 #Check that the Outlook version installed isn't lower than $MinimumOutlookVersion. $OutlookRegistryData = reg query "HKEY_CLASSES_ROOT\Outlook.Application\CurVer" 2>$null # Outlook 2016, 2019, Outlook 365 and above show as version 16 :shrug: #If the registry value is empty, then Outlook is not installed. if ($null -ne $OutlookRegistryData) { [int]$OutlookVersion = [regex]::Match($OutlookRegistryData, '\.(\d+)').Groups[1].Value if ($OutlookVersion -lt $MinimumOutlookVersion ) { Write-Host "ALERT: Outlook version ($OutlookVersion) is less than or equal to version $MinimumOutlookVersion" } } else { write-host "Outlook not installed. Moving on..." }

Putting it all together

There's no reason why all these checks can't be put into a single script, and we've done just that here: Audit Workstation Standards

Additionally, this combined version will tally up the alerts and send a helpful output to the console. The easiest way to run this on all devices is to use Level! In the Level app go to Scripts add a new script and paste the script from GitHub.

Scripts are easy to create and save.
Scripts are easy to create and save.

This script can either be run on demand (for a (v)CIO audit of workstations), or it can be setup as a monitor for continuous checking. If using this for (v)CIO purposes to create workstation replacement schedules, export the script results by clicking "Download Results" at the top right. This will provide a CSV that can be used for finer reporting.

Yikes, replace this device! 😬
Yikes, replace this device! 😬

Is a workstation standard missing? Please let us know, or contribute on our community script repo: https://github.com/levelsoftware/scripts

Level: Simplify IT Management

At Level, we understand the modern challenges faced by IT professionals. That's why we've crafted a robust, browser-based Remote Monitoring and Management (RMM) platform that's as flexible as it is secure. Whether your team operates on Windows, Mac, or Linux, Level equips you with the tools to manage, monitor, and control your company's devices seamlessly from anywhere.

Ready to revolutionize how your IT team works? Experience the power of managing a thousand devices as effortlessly as one. Start with Level today—sign up for a free trial or book a demo to see Level in action.