Skip to content

Instantly share code, notes, and snippets.

@SweetAsNZ
Created December 2, 2025 21:32
Show Gist options
  • Select an option

  • Save SweetAsNZ/ed1cb515c055a1c682c2ba7fad953815 to your computer and use it in GitHub Desktop.

Select an option

Save SweetAsNZ/ed1cb515c055a1c682c2ba7fad953815 to your computer and use it in GitHub Desktop.
Gets a list of deduplicated IP's or Ports that hit the Computer using the output of Get-NetworkConnectionLog.ps1
function Get-NetworkConnectionLogDedupedData {
<#
.SYNOPSIS
Get deduplicated network connection log data with flexible property selection and time filtering.
.DESCRIPTION
Parses network connection log CSV files and returns unique combinations of selected properties.
Supports time-based filtering (last N minutes or hours) and flexible property selection for deduplication.
.PARAMETER FilePath
Path to the network connection log CSV file. If not specified, searches for the most recent log file
in the default location: $ENV:USERPROFILE\Documents\WindowsPowerShell\SCRIPTS\Network\Get-NetworkConnectionLog\
.PARAMETER Protocol
Include Protocol in deduplication.
.PARAMETER LocalAddress
Include LocalAddress in deduplication.
.PARAMETER LocalPort
Include LocalPort in deduplication.
.PARAMETER RemoteAddress
Include RemoteAddress in deduplication.
.PARAMETER RemotePort
Include RemotePort in deduplication.
.PARAMETER State
Include State in deduplication.
.PARAMETER OwningProcess
Include OwningProcess in deduplication.
.PARAMETER IgnoreIPv6
Exclude IPv6 addresses from results. Default is True (IPv6 addresses are excluded).
.PARAMETER ForLastMinutes
Filter log entries from the last N minutes. Takes precedence over ForLastHours.
.PARAMETER ForLastHours
Filter log entries from the last N hours.
.PARAMETER IncludeTimestamp
Include the earliest timestamp for each unique combination.
.PARAMETER OutputToCSV
Export results to CSV file. Creates filename based on original file with _Deduped_<Properties> inserted before timestamp.
.PARAMETER ResolveIPsInDNS
Attempt to resolve IP addresses to DNS A Records. Adds ResolvedLocalAddress and ResolvedRemoteAddress columns to results.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -RemoteAddress -OutputToCSV -ResolveIPsInDNS
Returns unique RemoteAddress, exports to CSV, and resolves IPs to DNS names.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -State -Protocol -ForLastHours 2
Returns unique State and Protocol combinations from the last 2 hours.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -RemoteAddress -IncludeTimestamp
Returns unique RemoteAddress values with the earliest timestamp for each.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -FilePath "C:\Logs\connections.csv" -LocalPort -State
Returns unique LocalPort and State combinations from the specified file.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -ForLastHours 1
Returns all unique property combinations (default: all properties) from the last hour.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -RemoteAddress -IgnoreIPv6:$false
Returns unique RemoteAddress values including IPv6 addresses.
.EXAMPLE
Get-NetworkConnectionLogDedupedData -RemoteAddress -RemotePort -State -OutputToCSV
Exports unique combinations to CSV with filename like: Get-NetworkConnectionLog_Deduped_RemoteAddress-RemotePort-State_AKL0EX804_20251201_160132.csv
.EXAMPLE
Get-NetworkConnectionLogDedupedData -RemoteAddress -ResolveIPsInDNS
Returns unique RemoteAddress values with DNS names resolved for each IP address.
.NOTES
Author: Tim West
Company: Sweet As Chocolate Ltd
Created: 2025-12-03
Updated: 2025-12-03
Status: Production
Version: 1.0.2
Use with the output of Get-NetworkConnectionLog.ps1
.CHANGELOG
2025-12-03: Initial version - flexible property deduplication with time filtering
2025-12-03: Split Properties parameter into individual switch parameters for easier usage
2025-12-03: Added IgnoreIPv6 parameter (default: $true) to filter out IPv6 addresses
2025-12-03: Added OutputToCSV parameter to export results with descriptive filename
2025-12-03: Added ResolveIPsInDNS parameter to resolve IP addresses to DNS A Records
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true,HelpMessage="Defaults to latest log file in \Network\Get-NetworkConnectionLog")]
[string]$FilePath,
[Parameter()]
[switch]$Protocol,
[Parameter()]
[switch]$LocalAddress,
[Parameter()]
[switch]$LocalPort,
[Parameter()]
[switch]$RemoteAddress,
[Parameter()]
[switch]$RemotePort,
[Parameter()]
[switch]$State,
[Parameter()]
[switch]$OwningProcess,
[Parameter()]
[bool]$IgnoreIPv6 = $true,
[Parameter()]
[int]$ForLastMinutes,
[Parameter()]
[int]$ForLastHours,
[Parameter()]
[switch]$IncludeTimestamp,
[Parameter()]
[switch]$OutputToCSV,
[Parameter()]
[switch]$ResolveIPsInDNS
)
begin {
Write-Verbose "Starting Get-NetworkConnectionLogDedupedData"
# Determine file path
if (-not $FilePath) {
$DefaultPath = "$ENV:USERPROFILE\Documents\WindowsPowerShell\SCRIPTS\Network\Get-NetworkConnectionLog"
if (Test-Path $DefaultPath) {
$LatestFile = Get-ChildItem -Path $DefaultPath -Filter "*.csv" -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($LatestFile) {
$FilePath = $LatestFile.FullName
Write-Verbose "Using latest file: $FilePath"
} else {
Write-Warning "No CSV files found in $DefaultPath"
return
}
} else {
Write-Warning "Default path not found: $DefaultPath"
return
}
}
# Validate file exists
if (-not (Test-Path $FilePath)) {
Write-Warning "File not found: $FilePath"
return
}
Write-Verbose "Processing file: $FilePath"
}
process {
try {
# Import CSV data
$Data = Import-Csv -Path $FilePath -ErrorAction Stop
Write-Verbose "Loaded $($Data.Count) records"
# Calculate time cutoff if specified
$Cutoff = $null
if ($ForLastMinutes) {
$Cutoff = (Get-Date).AddMinutes(-$ForLastMinutes)
Write-Verbose "Filtering for last $ForLastMinutes minutes (after $Cutoff)"
} elseif ($ForLastHours) {
$Cutoff = (Get-Date).AddHours(-$ForLastHours)
Write-Verbose "Filtering for last $ForLastHours hours (after $Cutoff)"
}
# Filter by time if cutoff specified
if ($Cutoff) {
$Data = $Data | Where-Object {
try {
$Timestamp = [DateTime]::Parse($_.Timestamp)
$Timestamp -ge $Cutoff
} catch {
$false
}
}
Write-Verbose "After time filter: $($Data.Count) records"
}
# Filter out IPv6 addresses if requested
if ($IgnoreIPv6) {
$Data = $Data | Where-Object {
$_.LocalAddress -notmatch ':' -and $_.RemoteAddress -notmatch ':'
}
Write-Verbose "After IPv6 filter: $($Data.Count) records"
}
# Filter out blank IP addresses and localhost (127.0.0.1)
$Data = $Data | Where-Object {
-not [string]::IsNullOrWhiteSpace($_.LocalAddress) -and
-not [string]::IsNullOrWhiteSpace($_.RemoteAddress) -and
$_.LocalAddress -ne '127.0.0.1' -and
$_.RemoteAddress -ne '127.0.0.1'
}
Write-Verbose "After localhost/blank filter: $($Data.Count) records"
# Build property list for selection based on switches
$SelectProperties = @()
if ($IncludeTimestamp) {
$SelectProperties += 'Timestamp'
}
# Add properties based on switch parameters
$PropertiesToInclude = @()
if ($Protocol) { $PropertiesToInclude += 'Protocol' }
if ($LocalAddress) { $PropertiesToInclude += 'LocalAddress' }
if ($LocalPort) { $PropertiesToInclude += 'LocalPort' }
if ($RemoteAddress) { $PropertiesToInclude += 'RemoteAddress' }
if ($RemotePort) { $PropertiesToInclude += 'RemotePort' }
if ($State) { $PropertiesToInclude += 'State' }
if ($OwningProcess) { $PropertiesToInclude += 'OwningProcess' }
# If no properties specified, include all
if ($PropertiesToInclude.Count -eq 0) {
$PropertiesToInclude = @('Protocol', 'LocalAddress', 'LocalPort', 'RemoteAddress', 'RemotePort', 'State', 'OwningProcess')
Write-Verbose "No properties specified, using all properties"
}
$SelectProperties += $PropertiesToInclude
# Select and deduplicate
$Results = $Data |
Select-Object -Property $SelectProperties |
Sort-Object -Property $SelectProperties -Unique
Write-Verbose "Deduplicated to $($Results.Count) unique combinations"
# Resolve IP addresses to DNS names if requested
if ($ResolveIPsInDNS -and $Results) {
Write-Verbose "Resolving IP addresses to DNS names..."
$Results = $Results | ForEach-Object {
$Record = $_
$ResolvedLocal = $null
$ResolvedRemote = $null
# Resolve LocalAddress if present and not empty
if ($Record.LocalAddress -and $Record.LocalAddress -ne '') {
try {
$DnsResult = Resolve-DnsName -Name $Record.LocalAddress -ErrorAction SilentlyContinue -Type PTR
if ($DnsResult -and $DnsResult.NameHost) {
$ResolvedLocal = $DnsResult.NameHost
}
} catch {
$ResolvedLocal = "Unable to resolve"
}
}
# Resolve RemoteAddress if present and not empty
if ($Record.RemoteAddress -and $Record.RemoteAddress -ne '') {
try {
$DnsResult = Resolve-DnsName -Name $Record.RemoteAddress -ErrorAction SilentlyContinue -Type PTR
if ($DnsResult -and $DnsResult.NameHost) {
$ResolvedRemote = $DnsResult.NameHost
}
} catch {
$ResolvedRemote = "Unable to resolve"
}
}
# Add resolved properties to record
$Record | Add-Member -MemberType NoteProperty -Name ResolvedLocalAddress -Value $ResolvedLocal -Force
$Record | Add-Member -MemberType NoteProperty -Name ResolvedRemoteAddress -Value $ResolvedRemote -Force
$Record
}
Write-Verbose "DNS resolution completed"
}
# Export to CSV if requested
if ($OutputToCSV -and $Results) {
# Build property string for filename
$PropertyString = $PropertiesToInclude -join '-'
# Parse original filename to insert deduped marker
$OriginalFileName = [System.IO.Path]::GetFileNameWithoutExtension($FilePath)
$FileDirectory = [System.IO.Path]::GetDirectoryName($FilePath)
# Create new filename: OriginalName_Deduped_Properties_Timestamp.csv
$NewFileName = "{0}_Deduped_{1}.csv" -f $OriginalFileName, $PropertyString
$OutputPath = Join-Path -Path $FileDirectory -ChildPath $NewFileName
# Export to CSV
$Results | Export-Csv -Path $OutputPath -NoTypeInformation -ErrorAction Stop
Write-Host "\nExported $($Results.Count) unique combination(s) to:" -ForegroundColor Green
Write-Host $OutputPath -ForegroundColor White
}
# Output results
if ($Results) {
Write-Host "`nFound $($Results.Count) unique combination(s):" -ForegroundColor Green
$Results | Format-Table -AutoSize
# Return objects for pipeline
$Results
} else {
Write-Host "No records found matching criteria" -ForegroundColor Yellow
}
} catch {
$Err = $PSItem.Exception.Message
Write-Warning "Error processing file: $Err"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment