Automating Inventory of Authorized and Unauthorized Software

With this article I intend to help you all to understand not only the importance of the CIS Critical Security Control: Inventory of authorized and unauthorized software, but also the importance of automation. Trust me, automation makes the job easy. But, to do so I want to share my own experience and how I ended up learning the importance of both.

Before I ever got into the security domain I was working as a software engineer and used to love writing scripts. I started in security because of my interest and passion for it but there was always this question “How or What ?“. When I was doing my internship as a security analyst I was still struggling with “what should I do in security“, “where do I start” or “what do I learn” and these are all valid questions because Information security is like an ocean. It is VAST ! and to struggle with these questions is normal. There are so many things in it that one can explore and specialize in.

So I used to ask my supervisor at the company again and again the same set of questions and his reply always used to be “start with the Critical Security Controls“. After reading them at first I thought “hmmm !  20 different points, pretty straight forward”. But I still couldn’t relate to them as much because I was still learning and had no prior security experience other than just knowing a few tools like nmap, nessus, or wireshark. This was the pdf I was reading at that time.

My supervisor then pulled a Mr. Miyagi on me one day and gave me an excel file which had about 1000 IP Addresses.

He told me to start by manually checking each IP for what’s running on them and fill in the excel file with the data using whatever tools you can.

1000 IP Addresses + Manual checking + no idea how = WASTE OF TIME & MONEY

So I decided to use nmap and see what results does the scan provide me. One by one I started discovering services, which when searched online for version number were old and had vulnerabilities. Soon I came across machines which did not have software such as McAfee or any other installed on them.

This is when the part of critical security control 2 made more sense to me i.e. Inventory of Authorized and Unauthorized Software.

According to the control:

Actively manage (inventory, track, and correct) all software on the network so that only authorized software is installed and can execute, and unauthorized and unmanaged software is found and prevented from installation or execution.

You CAN NOT protect what you don’t know. Part of what I learnt in penetration testing was that an attacker would continuously scan target organizations looking for vulnerable versions of software that can be remotely exploited. A well equipped attacker may use zero-day exploits, taking advantage of previously unknown vulnerabilities for which their may not exist a patch by the software vendor. Without proper knowledge or control of the software deployed in an organization, defenders cannot properly secure their assets. An organization that does not have a complete software inventory would not be able find systems running vulnerable or malicious software to mitigate problems or root out attackers.

But now the problem at hand was that 1000 IP addresses to be checked manually was a tedious task and time consuming.  Having an automation background and a knack to automate my tasks I researched and found out that nmap also stores results in an XML format which is easy to parse because of its structure and format. I quickly took a course on Udemy for PowerShell and wrote a basic PowerShell script which can complete the same task overnight instead of two weeks.

The script can do the following:

  • Perform nmap on a list IP Addresses provided as input
  • Stores the output in an excel file
  • Stores a list of IP Addresses it was not able to parse , and
  • Once the parsing is complete the script emails the excel file and the text file to the email address you provide as the input.

There are plenty commercial tools out there which can do inventory management for you, and it was later that I found out that the organization where I was doing my internship had similar tools already in place but my supervisor wanted me to go through this exercise to see whether I understood one of the security controls or not and what more I could come up with given my previous coding background. The main idea was to give me a start and how to move forward in this domain. Feel free to use this script and further customize it to add more functionalities as per your requirements.

Automation in security is the next big thing. If you can get the results fast, the better you will be able to up your defensive strategy. This goes the other way around as well. You can also automate your attacking tools when performing penetration testing.

Always use internships as a way to learn. The supervisor who kept hammering these controls on me is none other than Pablo Delgado, the founder of

Below is the script. Give it a try and give me your feedback so that I can improve it further. For better readability copy the script on notepad++. I will soon post a github link here for the script.

[Parameter(mandatory = $true)]
[Parameter(mandatory = $true)]
    #Function opens a dialogue box to select input file
    Function Get-FileName($initialDirectory){   
        [System.Reflection.Assembly]::LoadWithPartialName("") |
        $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
        $OpenFileDialog.initialDirectory = $initialDirectory
        $OpenFileDialog.filter = "All files (*.*)| *.*"
        $OpenFileDialog.ShowDialog() | Out-Null
    $nmapInputFile = Get-FileName
    If (-Not($nmapInputFile)){ #If no file is selected, the Script ends
    write-host "---CHECKING FILE PATH---`n"
    write-host "path: "$nmapInputFile "`n"
    write-host "`n------------Starting NMAP scan------------`n"
    nmap -O -sV -oX scanOutput.xml -iL $nmapInputFile  
    $inputFile = ".\scanOutput.xml"  

    Function outputToCSV{
            $tempOS = $ -replace ‘[,]’,""
            New-Object -TypeName PsObject -Property @{IP_Address=$foundIpAddress;MAC_Address=$foundMacAddress;HOSTNAME=$;Endpoint_Security=$McAfeeResult; Operating_System=$}
            "$foundIpAddress, $foundMacAddress, $tempHost, $McAfeeResult, $tempOS" | Out-File -FilePath .\Output\Discovery_Results.csv -Append -Encoding ASCII  
    write-host "`n`n`n------------Starting XML parsing------------ `n" 
    # to get the data from the XML file
    $xdocAssetList= [xml] (Get-Content $inputFile)                          
    $assetList = $xdocAssetList.SelectNodes("//host")
    "IP_Address, MAC_Address, HOSTNAME, Endpoint_Security, Operating_System " | Out-File -FilePath .\Output\Discovery_Results.csv -Encoding ASCII
    #Loop Begins
    foreach ($asset in $assetList){   
        $foundMacAddress = $asset.SelectSingleNode("./address[@addrtype=""mac""]")
        $foundIpAddress = $asset.SelectSingleNode("./address[@addrtype=""ipv4""]")
        $foundIpAddress = $foundIpAddress.Attributes["addr"].Value
        $foundIpAddress | Out-File -FilePath Temp.txt -Append -Encoding utf8
        $foundHostName = $asset.SelectSingleNode("./hostnames/hostname")
        # This next section checks if a particular Agent is running on a specific port on the machine
        # In this case the script is checking for the McAfee Agent on the Host.
        $foundOSName = $asset.SelectSingleNode("./os/osmatch") | Select-Object -First 1
        $Url = "http://"+$foundIpAddress+":port"   #Enter a port number here like 5678 or 7896
            $InfoPage = Invoke-Webrequest -Uri $Url
            $temp= $InfoPage.links.innerHTML |select -First 1    
            $McAfeeResult = $temp + " Installed"
            $McAfeeResult="McAfee Agent UNAVAILABLE"
        If ($foundMacAddress -eq $null){
            If ($foundHostName -eq $null){
                    $hostentry = [System.Net.Dns]::GetHostEntry($foundIpAddress)               
                    write-host "for ip " $foundIpAddress "dns accessed" $hostDNS   
                        $hostDNS= "[N/A]"
                $tempOS = $ -replace ‘[,]’,""
                New-Object -TypeName PsObject -Property @{IP_Address=$foundIpAddress;MAC_Address=$foundMacAddress;HOSTNAME=$hostDNS;Endpoint_Security=$McAfeeResult; Operating_System=$}
                "$foundIpAddress, $foundMacAddress, $hostDNS, $McAfeeResult, $tempOS" | Out-File -FilePath .\Output\Discovery_Results.csv -Append -Encoding ASCII
        $foundMacAddress = $foundMacAddress.Attributes["addr"].Value
        $foundIpAddress = $asset.SelectSingleNode("./address[@addrtype=""ipv4""]").Attributes["addr"].Value
        If ($foundHostName -eq $null){
                $hostentry = [System.Net.Dns]::GetHostEntry($foundIpAddress)               
                write-host "for ip " $foundIpAddress "dnsq accessed" $hostDNS   
                    $hostDNS= "[N/A]"
            Write-Host "Case entered"
            $tempOS = $ -replace ‘[,]’,""
            New-Object -TypeName PsObject -Property @{IP_Address=$foundIpAddress;MAC_Address=$foundMacAddress;HOSTNAME=$hostDNS;Endpoint_Security=$McAfeeResult; Operating_System=$}
            "$foundIpAddress, $foundMacAddress, $hostDNS, $McAfeeResult, $tempOS" | Out-File -FilePath .\Output\Discovery_Results.csv -Append -Encoding ASCII
    #Loop Ends  
    compare-object -referenceobject $(get-content .\IP_Address_InputFile.txt) -differenceobject $(get-content .\Temp.txt) | Out-File -FilePath .\Output\IP_Address_notParsed.txt -Append -Encoding utf8
    send-mailmessage -to $emailID_TO -from $emailID_From -subject "Inventory script execution complete" -Attachments '.\Output\Discovery_Results.csv','.\Output\IP_Address_notParsed.txt' -Body "PFA: Discovery_Results.csv,IP_Address_notParsed.txt" -SmtpServer server_name  #Enter the server name here
 }catch {
    send-mailmessage -to $emailID_TO -from $emailID_From -subject "Script Execution failed : CONTACT IT" -Body "Script Execution failed : CONTACT IT" -SmtpServer server_name #Enter the server name here 
How to execute the script ?

Create a file with the .ps1 extension and copy the script in it. Once done with that please create a folder which has the script in it as shown below in the screenshot 1. The script name in my case was nmapScript.

Then create a shortcut “Run_me” which has the target set as “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -Sta -File nmapScript.ps1” . This will make it easy for you to execute your script. Also create a folder “Output“.

screenshot 1

Next create a “IP_Address_InputFile” text file in the same folder and enter all the IP addresses you want to scan in the way shown below.

screenshot 2

Once you execute the script, it will ask for the sender’s email address and the receiver’s email address.

screenshot 3

Once you have provided the details, it will ask for the input file which has the IP Addresses to be scanned. Below is the screenshot.

screenshot 4

Once the execution is complete you should see the files in the output folder and also in your inbox.


Hope you enjoyed the article.

2 thoughts on “Automating Inventory of Authorized and Unauthorized Software

Add yours

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Create a website or blog at

Up ↑

%d bloggers like this: