PowerShell: Convert WiSpy CSV to KML for Google Maps

I present to you a PowerShell script to convert the CSV output from WiSpy into a KML for use in Google Maps.

Configuration:

  • Update $csvFile and point it to your CSV path\file
  • Update $outputFolder and point it to your output path, including the trailing slash
  • Update $excludeNetworks to excluding any WiFi networks you don't want added to the KML file

Then just run it. Once complete, you can import the created KML files into Google Maps. Google Maps limits you to 2000 points per overlay, so the script breaks up the data into segments of such. You'll need to import each KML into a separate overlay in Google Maps.

If you'd rather download the script than copy and paste, the link is below:

# Convert WiSpy Captures in CSV format to KML for use in Google Maps
# Created by Archi @ FrontRunnerTek.com (not an email address)

# CSV file from WiSpy / Wardriver to process
$csvFile = "C:\WiSpy_Captures\wd3-1.csv"

# Specify folder for output files (include trailing slash)
$outputFolder = "C:\WiSpy_Captures\Output\" 

# Drop specific wifi networks (your own)
$excludeNetworks = @('homeNet','workNet')

Clear-Host

# Import data from CSV
$data = Get-Content -Path $csvFile | Select-Object -Skip 1 | ConvertFrom-Csv -Delimiter ','
Write-Host "Total DataPoints: $($data.Count)" -ForegroundColor Yellow

# Filter the data to only what we want
# WIFI only
$data = $data | Where-Object {$_.Type -eq "WIFI"}

# Drop certain SSIDs - exclude networks
$data = $data | Where-Object { $excludeNetworks -notcontains $_.SSID}

# Drop any entries with no info for Lat / Lon - can't map what we don't know
$data = $data | Where-Object { -not [string]::IsNullOrEmpty($_.CurrentLatitude) -and -not [string]::IsNullOrEmpty($_.CurrentLongitude) }

# Name used for - Google Map / Overlay / File (must be filename friendly)
$overlayName = "WiSpy $(Get-Date -Format "yyyy-MM-dd HH-mm-ss")"

# Misc Infos
# Coordinates =  Longitude, Latitude and Optional Altitude
# Description = info in 'ballon' attached to placemark
<#
name  | characters
----- | ------
<     | &lt;
>     | &gt;
&     | &amp;
"     | &quot;
'     | &apos;
#>

$i = 0
$ip = 0
$fileNum = 0
$xmlBody = ""
Write-Host "Clean DataPoints: $($data.Count)" -ForegroundColor Green
# Process each data point
ForEach ($dataPoint in $data ) {

    # XML / KML placemarks / body - cleanup / encode characters for KML web usage
    $xmlBody += @"

    <Placemark>
    <name>$(If($dataPoint.SSID){$dataPoint.SSID -replace '&','&amp;' -replace '<','&lt;' -replace '>','&gt;' -replace '"','&quot;' -replace "'","&apos;" }Else{"N/A"})</name>
    <styleUrl>$(If ([string]::IsNullOrEmpty($dataPoint.AuthMode)) {"#highlightPlacemark"} Else {"#normalPlacemark"})</styleUrl>
    <description><![CDATA[
    MAC: $($dataPoint.MAC) <br>
    AuthMode: $($dataPoint.AuthMode) <br>
    FirstSeen: $($dataPoint.FirstSeen) <br>
    Channel: $($dataPoint.Channel) <br>
    RSSI $($dataPoint.RSSI) <br>
    Accuracy $($dataPoint.AccuracyMeters) <br>
    Type: $($dataPoint.Type)]]>
    </description>
    <Point>
      <coordinates>$($dataPoint.CurrentLongitude),$($dataPoint.CurrentLatitude),$( If($dataPoint.AltitudeMeters){$dataPoint.AltitudeMeters}Else{0}  )</coordinates>
    </Point>
    </Placemark>

"@

    $i ++
    $ip ++
    Write-Host "Processed $ip of $($data.Count). Working on file $fileNum" -ForegroundColor Cyan
    # Google Maps has a limit of 2000 points per overlay file, so we need to break up points beyond that
    If ($i -ge 1999 -or $ip -eq $data.Count) {
      
      Write-Host "Outputting Data to file" -ForegroundColor Yellow


# XML / KML Header
$xmlFileHeader = @"
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>$overlayName - $fileNum</name>
<description>$overlayName - $fileNum</description>
<Style id="highlightPlacemark">
  <IconStyle>
    <Icon>
      <href>http://maps.google.com/mapfiles/kml/paddle/red-stars.png</href>
    </Icon>
  </IconStyle>
</Style>
<Style id="normalPlacemark">
  <IconStyle>
    <Icon>
      <href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>
    </Icon>
  </IconStyle>
</Style>
<Folder><name>$overlayName - $fileNum</name>

"@

# XML / KML Footer
$xmlFooter = @"

</Folder>
</Document>
</kml>
"@

        # Combine the XML / KML bits to create one output file
        $xmlOut = $xmlFileHeader + $xmlBody + $xmlFooter
        $fileName = "$outputFolder$($overlayName) - $($fileNum).kml"
        # Output file
        Set-Content -Path $fileName -Value $xmlOut -Force
        $xmlBody = ""
        $i = 0
        $fileNum ++

    } # end if -ge 1999 output kml file and start new data for new file

} # end for Each datapoint