Reputation: 511
I am looking for equivalent to netstat -b
written in Powershell.
Microsoft writes:
Displays the executable involved in creating each connection or listening port. In some cases well-known executables host multiple independent components, and in these cases the sequence of components involved in creating the connection or listening port is displayed. In this case the executable name is in [] at the bottom, on top is the component it called, and so forth until TCP/IP was reached. Note that this option can be time-consuming and will fail unless you have sufficient permissions.
(https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/netstat)
For example the EventLog listening port is display with netstat -anb
like this, stating that the process name is svchost.exe
and the calling component is EventLog
.
TCP 0.0.0.0:49665 0.0.0.0:0 LISTENING
EventLog
[svchost.exe]
This Powershell function outputs all listening processes:
function Get-ListeningProcesses {
Get-NetTCPConnection -State Listen |
ForEach-Object {
$ProcessName = (Get-Process -Id $_.OwningProcess).ProcessName
[PSCustomObject]@{
LocalAddress = $_.LocalAddress
LocalPort = $_.LocalPort
OwningProcess = $_.OwningProcess
ProcessName = $ProcessName
}
}
}
The output will be:
LocalAddress LocalPort OwningProcess ProcessName
------------ --------- ------------- -----------
...
:: 49665 1412 svchost
...
But how can I get the component that started svchost.exe
?
Upvotes: 1
Views: 141
Reputation: 8868
We can take the desired output from netstat and parse it into objects.
$stats = netstat -anob | out-string
$statlist = [regex]::Matches($stats,'(?s)(TCP|UDP).+?(Can not.+?|])(?=\r?\n)').value
$results = foreach($entry in $statlist ){
switch -Regex ($entry -split '\r?\n'){
'(?<Protocol>TCP|UDP)\s+(?<LocalAddr>\S+?)\s+(?<ForeignAddr>\S+?)\s+(?<State>\S+)?\s+?(?<PID>\d+)$' {
if($current){
$current.Protocol += $matches.protocol
$current.LocalAddr += $matches.LocalAddr
$current.ForeignAddr += $matches.ForeignAddr
$current.State += $matches.State
$current.PID += $matches.PID
}
else{
$current = @{}
'Protocol', 'LocalAddr', 'ForeignAddr', 'State', 'Pid' | ForEach-Object{
$current.$_ = @()
$current.$_ += $matches.$_
}
$current.Parent = ''
$current.Executable = ''
}
}
'^\s{2}(?<Parent>[\S|^\.|^:]+)$' {
if($current.Parent){
$current.Parent = $current.Parent,$matches.parent -join ' -> '
}
else{
$current.Parent = $matches.parent
}
}
'^\s(\[(?<Exe>\S+)\]|(?<Exe>Can not obtain ownership information))'{
for($i = 0;$i -lt $current.Protocol.Count; $i++){
[PSCustomObject]@{
Protocol = $current.Protocol[$i]
LocalAddr = $current.LocalAddr[$i]
ForeignAddr = $current.ForeignAddr[$i]
Executable = $matches.Exe
Parent = $current.Parent
State = $current.State[$i]
ProcessId = $current.PID[$i]
}
}
$current = $null
}
}
}
You can view the data interactively
$results | Out-GridView
Export to csv
$results | Export-CSV path\to\csv
If you know the name of the parent you can filter
PS C:\> $results | Where-Object Parent -like '*TermService*' | Format-Table *
Protocol LocalAddr ForeignAddr Executable Parent State ProcessId
-------- --------- ----------- ---------- ------ ----- ---------
TCP 0.0.0.0:3389 0.0.0.0:0 svchost.exe TermService LISTENING 1612
TCP [::]:3389 [::]:0 svchost.exe TermService LISTENING 1612
UDP 0.0.0.0:3389 *:* svchost.exe TermService 1612
UDP [::]:3389 *:* svchost.exe TermService 1612
Upvotes: 1
Reputation: 511
Not exactly what I am was looking for but it serves my needs right now. But the following script lists all public listening processes including the command line.
function Get-ListeningProcesses {
Get-NetTCPConnection -State Listen | Where-Object {($_.LocalAddress -eq "::" -or $_.LocalAddress -eq "0.0.0.0")} |
ForEach-Object {
$ProcessId = $_.OwningProcess
$ProcessName = (Get-Process -Id $_.OwningProcess).ProcessName
$CommandLine = (Get-WmiObject Win32_process -filter "ProcessId = '$ProcessId'").CommandLine
[PSCustomObject]@{
LocalAddress = $_.LocalAddress
LocalPort = $_.LocalPort
RemoteAddress = $_.RemoteAddress
RemotePort = $_.RemotePort
OwningProcess = $_.OwningProcess
ProcessName = $ProcessName
CommandLine = $CommandLine
}
}
}
The script has to be run with elevated rights (as an Administrator).
Upvotes: 1