PoshCode Archive  Artifact [c527f557cd]

Artifact c527f557cd80b5f52bedcff6f3b996a4fb6a635c5ac08ea548386455685f3956:

  • File Parse-nmap-XML-output.ps1 — part of check-in [f00f82240f] at 2018-06-10 12:56:36 on branch trunk — A PowerShell script into which one or more nmap XML output file objects can be piped, then the script emits synthetic objects representing port-scanned hosts from the XML file(s). Get Windows and Linux versions of the nmap scanner for free from http://nmap.org. Get a sample nmap XML file to play with and see some examples of using the script at https://blogs.sans.org/windows-security/2009/06/11/powershell-script-to-parse-nmap-xml-output/ (user: Jason Fossen size: 5555)

# encoding: ascii
# api: powershell
# title: Parse nmap XML output
# description: A PowerShell script into which one or more nmap XML output file objects can be piped, then the script emits synthetic objects representing port-scanned hosts from the XML file(s).  Get Windows and Linux versions of the nmap scanner for free from http://nmap.org.  Get a sample nmap XML file to play with and see some examples of using the script at https://blogs.sans.org/windows-security/2009/06/11/powershell-script-to-parse-nmap-xml-output/
# version: 2.0
# type: script
# author: Jason Fossen 
# license: CC0
# x-poshcode-id: 1179
# x-archived: 2017-04-30T13:01:40
# x-published: 2010-06-27T07:04:00
#
#
####################################################################################
#  Script: parse-nmap.ps1
# Purpose: Parse the XML output file of the nmap port scanner and emit custom 
#          objects with properties containing data from XML file.
# Example: dir *.xml | .\parse-nmap.ps1 
#  Author: Jason Fossen (www.EnclaveConsulting.com)
# Version: 2.0
# Updated: 15.Jun.2009
#   Notes: Pipe one or more file objects into script.  Don't pipe file contents.
#          Script is slow, e.g., a 20MB XML log with 65k entries requires 103 seconds
#          to process on a 2.16GHz T2600 Intel CPU (about 630 entries per second).
#   LEGAL: PUBLIC DOMAIN.  SCRIPT PROVIDED "AS IS" WITH NO WARRANTIES OR GUARANTEES OF 
#          ANY KIND, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY AND/OR FITNESS FOR
#          A PARTICULAR PURPOSE.  ALL RISKS OF DAMAGE REMAINS WITH THE USER, EVEN IF
#          THE AUTHOR, SUPPLIER OR DISTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF
#          ANY SUCH DAMAGE.  IF YOUR STATE DOES NOT PERMIT THE COMPLETE LIMITATION OF
#          LIABILITY, THEN DELETE THIS FILE SINCE YOU ARE NOW PROHIBITED TO HAVE IT.
####################################################################################


if ($args -ne $null) { 
    "`nThis script takes no arguments, please pipe one or more files into it."
    "Example: dir *.xml | .\parse-nmap.ps1 | export-csv -path c:\file.csv`n"
    exit 
}

# Set $ShowProgress to $false if you do not want progress info sent to StdErr.
$ShowProgress = $true



ForEach ($file in $input) {
    If ($ShowProgress) { [Console]::Error.WriteLine("[" + (get-date).ToLongTimeString() + "] Starting $file" ) }

    $xmldoc = new-object System.XML.XMLdocument
    $xmldoc.Load($file)
    $i = 1  #Counter for <host> nodes processed.

    # Process each of the <host> nodes from the nmap report.
    $xmldoc.nmaprun.host | foreach-object { 
        $hostnode = $_   # $hostnode is a <host> node in the XML.

        # Init variables, with $entry being the custom object for each <host>. 
        $service = " " #service needs to be a single space.
        $entry = ($entry = " " | select-object FQDN, HostName, Status, IPv4, IPv6, MAC, Ports, OS) 

        # Extract state element of status:
        $entry.Status = $hostnode.status.state.Trim() 
        if ($entry.Status.length -eq 0) { $entry.Status = "<no-status>" }

        # Extract fully-qualified domain name(s).
        $hostnode.hostnames | foreach-object { $entry.FQDN += $_.hostname.name + " " } 
        $entry.FQDN = $entry.FQDN.Trim()
        if ($entry.FQDN.Length -eq 0) { $entry.FQDN = "<no-fullname>" }

        # Note that this code cheats, it only gets the hostname of the first FQDN if there are multiple FQDNs.
        if ($entry.FQDN.Contains(".")) { $entry.HostName = $entry.FQDN.Substring(0,$entry.FQDN.IndexOf(".")) }
        elseif ($entry.FQDN -eq "<no-fullname>") { $entry.HostName = "<no-hostname>" }
        else { $entry.HostName = $entry.FQDN }

        # Process each of the <address> nodes, extracting by type.
        $hostnode.address | foreach-object {
            if ($_.addrtype -eq "ipv4") { $entry.IPv4 += $_.addr + " "}
            if ($_.addrtype -eq "ipv6") { $entry.IPv6 += $_.addr + " "}
            if ($_.addrtype -eq "mac")  { $entry.MAC  += $_.addr + " "}
        }        
        if ($entry.IPv4 -eq $null) { $entry.IPv4 = "<no-ipv4>" } else { $entry.IPv4 = $entry.IPv4.Trim()}
        if ($entry.IPv6 -eq $null) { $entry.IPv6 = "<no-ipv6>" } else { $entry.IPv6 = $entry.IPv6.Trim()}
        if ($entry.MAC  -eq $null) { $entry.MAC  = "<no-mac>" }  else { $entry.MAC  = $entry.MAC.Trim() }


        # Process all ports from <ports><port>, and note that <port> does not contain an array if it only has one item in it.
        if ($hostnode.ports.port -eq $null) { $entry.Ports = "<no-ports>" } 
        else 
        {
            $hostnode.ports.port | foreach-object {
                If ($_.service.name -eq $null) { $service = "unknown" } else { $service = $_.service.name } 
                $entry.Ports += $_.state.state + ":" + $_.protocol + ":" + $_.portid + ":" + $service + " " 
            }
            $entry.Ports = $entry.Ports.Trim()
        }


        # Extract fingerprinted OS type and percent of accuracy.
        $hostnode.os.osmatch | foreach-object {$entry.OS += $_.name + " <" + ([String] $_.accuracy) + "%-accuracy> "} 
        $entry.OS = $entry.OS.Trim()
        if ($entry.OS -eq "<%-accuracy>") { $entry.OS = "<no-os>" }


        # Emit custom object from script.
        $entry
        $i++  #Progress counter...
    }

If ($ShowProgress) { [Console]::Error.WriteLine("[" + (get-date).ToLongTimeString() + "] Finished $file, processed $i entries." ) }
}