How to build a vulnerability scanner with PowerShell

What do you do if there's a zero-day threatening your organization? When you need to act fast, use PowerShell to uncover vulnerabilities hiding in your environment.

When there's no patch for a pressing security issue, you can use a PowerShell vulnerability scanner to hunt down these threats in your Windows Server infrastructure to get a jump on mitigation work.

One of the most challenging tasks for any organization is to identify vulnerabilities within applications and operating systems. This can be particularly difficult with emerging threats that are not easily remediated, such as the Log4Shell vulnerability. When time is of the essence, a custom PowerShell script can assist with these scenarios.

PowerShell's capabilities as a configuration tool are well known but it also works well to identify potential vulnerabilities within systems such as Windows Server. As a native Windows tool, PowerShell can access core operating system functionality and .NET classes to query and identify security threats. You can load a .NET DLL in PowerShell to call functions or types within the component. For example, you can load the System.Net.dll file to resolve names to IP addresses.

$url =
$ip = [System.Net.dll]::Resolve($name).AddressList
$ip | Select-Object -ExpandProperty IPAddressToString

The combination of PowerShell's core capabilities with enhancements such as .NET components, downloaded scripts or installable add-ons makes it the ideal tool.

Why is a PowerShell vulnerability scanner useful?

With vulnerability scanning, you use a structured approach to identify, analyze and report security issues within the network. A scan can mimic how malicious actors attempt to access your environment, whether it's a server or another device. The results often can show the path a malicious actor might take and the data they could steal, which can help the IT and security team with ongoing hardening efforts.

PowerShell's flexibility through its scripting language is one of its strengths. It is much easier to modify a script than to wait for an update of an antivirus application or the release a new vulnerability definition. As a native tool, PowerShell can access the lowest layers of the Windows OS and access much of the data required for a complete scan.

How to use PowerShell to find a list of vulnerabilities

Using PowerShell to retrieve current common vulnerabilities and exposures (CVEs) and scan servers and clients is a straightforward and robust approach.

To identify vulnerabilities, you need to retrieve a list of the latest CVEs. The Microsoft Security Response Center offers a website called the Security Update Guide used to find details on these CVEs with security updates or mitigations. Microsoft also provides a PowerShell module to retrieve this information.

To use PowerShell to retrieve the CVEs, install the MSRCSecurityUpdates module.

Install-Module -Name MSRCSecurityUpdates -Force
Import-Module MSRCSecurityUpdates

After the module loads, you can request a specific month of CVEs.

$file = "C:\Training\March2022.html"
$month= '2022-Mar'
$download = Get-MsrcCvrfDocument -ID $month -Verbose | Get-MsrcSecurityBulletinHtml -Verbose
$download | Out-File $file

The downloaded file contains the CVE ID, description, severity rating, vulnerability impact and the affected software. You extract mitigations and workarounds by using filters within the query with 0 for workarounds or 1 for mitigations.

$month= '2022-Mar'
$document = Get-MsrcCvrfDocument -ID $month
$document.Vulnerability.Remediations | Where Type -EQ 0
$document.Vulnerability.Remediations | Where Type -EQ 1

PowerShell can iterate the values as part of the scanning task. You must adjust the commands if you need to get a list of the affected systems.

$month= '2022-Mar'
$document = Get-MsrcCvrfDocument -ID $month
Get-MsrcCvrfAffectedSoftware `
	-Vulnerability $document.Vulnerability `
	-ProductTree $document.ProductTree
product details screenshot
Use PowerShell to gather details of systems affected by vulnerabilities from the specified month.

To identify the security updates a specific CVE appears within, the query must change to go one step further.

$cve = "CVE-2022-24526"
Get-MsrcSecurityUpdate -Vulnerability $cve

After we download the list of the current CVEs, affected systems and the updates they belong to, we can use the output to iterate the Windows Server systems.

How to use PowerShell to scan files for vulnerabilities

Over the past few years, more attacks have used vulnerabilities within specific applications or files, such as the Apache Log4j vulnerability, commonly known as Log4Shell. Many applications use the Log4j logging framework to track activities in software applications or online services. When reports of a zero-day vulnerability in Log4j became public, it required quick action to find and protect vulnerable systems from breach attempts and ransomware attacks.  

The following steps explain how to build a Log4j PowerShell scanner, which many administrators were doing before security tools had been updated and patches were available. Because it was not a Windows-based threat, finding and neutralizing the vulnerable Java library required a more inventive solution. If a similar situation occurs in the future, administrators can construct their own vulnerability scanner in PowerShell.

To resolve and mitigate Log4Shell, scan for specific file types and then assign one of the following CVEs:

Depending on the identified version of the targeted file, we can then assign the CVE. The vulnerability involves identifying specific file formats, versions and the vulnerable JndiLookup class.  

The first step is to connect to the machine's operating system and iterate the disk drives and files, looking for file types such .jar and .war files, which are Java archive and zipped file types.

$extensions = @('*.JAR', '*.WAR')
$disks = (Get-WmiObject `
-Class Win32_LogicalDisk `
-Filter "DriveType ='3'").DeviceID

foreach ($disk in $disks) {
$disk = "$disk\"
$files = Get-ChildItem $disk `
-Recurse -ErrorVariable DriveError `
-Include $extensions `
-ErrorAction SilentlyContinue  

After finding a match, each file needs further exploration to find the log4j class. Add a second loop in the foreach loop for the retrieved files and pass each identified file to a scanning function.

foreach ($disk in $disks) {
$disk = "$disk\"
$files = Get-ChildItem $disk `
-Recurse -ErrorVariable DriveError `
-Include $extensions `
-ErrorAction SilentlyContinue 
foreach ($file in $files) {
$scanned += [pscustomobject](Check-File $file)

Check each file for the name JndiLookup.class, and log4j nested within the retrieved file type archives or the root folders. There are many PowerShell examples of techniques to search the identified files online for specific names and properties, such as the Log4jSherlock scanner.

The scanning function should check for the class and match it against the CVE. If any files match the criteria, you should use another PowerShell function to remove them or at least flag them for manual remediation.

As you can see, PowerShell is an excellent tool for scanning Windows server and client systems for specific files, folders and even vulnerabilities.

Dig Deeper on IT operations and infrastructure management

Cloud Computing
Enterprise Desktop
Virtual Desktop