Powershell one-liner для отображения процесса на той же строке, что и порт, используя проблему netstat
Во-первых, я просто хочу убедиться, что пользователь Erik Bitemo получает кредит на оригинальный код, который я здесь использую. Вывод - это то, что я ищу за одним исключением: один из портов исчезает, и на его месте появляется "System System5", и я не могу понять, почему это происходит.
Цель: Показать все порты TCP (прослушивание) и UDP и процесс, связанный с каждым на одной линии.
Один используемый вкладыш:
$nets = netstat -bano|select-string 'LISTENING|UDP'; foreach ($n in $nets) { $p = $n -replace ' +',' '; $nar = $p.Split(' '); $pname = $(Get-Process -id $nar[-1]).ProcessName; $n -replace "$($nar[-1])","$($ppath) $($pname)"; }
Пример вывода:
TCP 0.0.0.0:135 0.0.0.0:0 СЛУШАТЬ svchost
TCP 0.0.0.0: System System5 0.0.0.0:0 СЛУШАТЬ систему
TCP 0.0.0.0:623 0.0.0.0:0 LISTENING LMS
Порт, который он меняет, - 445, но я понятия не имею, почему он меняет только тот, когда остальные порты работают как положено. Почему скрипт меняет 445 на "System5"?
Использование других инструментов, к сожалению, невозможно, поэтому я ограничен использованием встроенных инструментов Windows.
3 ответа
$p
может быть что-то вроде TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
а также $nar[-1]
это строка 4
так -replace
оператор берет все 4
s:
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
↑↑ ↑
Принудительная замена только последнего появления $nar[-1]
с помощью привязки конца строки (экранированный $
):
$p -replace "$($nar[-1])`$","$ppath $pname"
Прочтите также ответ Мэтта на " Замена последнего появления подстроки в строке при стеке потока".
КСТАТИ:
$ppath
не определено…- …а также
netstat -ano
должно быть достаточно (обратите внимание, что-b
Эта опция может занять много времени и потерпит неудачу, если у вас нет достаточных разрешений).
Ответ JosefZ отлично объясняет вашу проблему. Вы используете регулярное выражение, и оно делает именно то, о чем вы его просили, возможно, заменяя больше, чем вы ожидали.
Примечание: вы спрашиваете netstat
в
отображает исполняемый файл, участвующий в создании каждого соединения или порта прослушивания
с переключателем b. Однако вы бросаете это с select-string
поскольку этот процесс появляется в отдельной строке после других данных. Это не конец света, а потому что вы можете использовать такие вещи, как -Context
из Select-String
чтобы получить это, но это нужно будет рассмотреть более внимательно в другой раз.
Я хотел бы предложить другие предложения относительно того, что вы можете сделать в этой ситуации.
Использование других инструментов, к сожалению, невозможно, поэтому я ограничен использованием встроенных инструментов Windows.
Забавно, у вас есть хотя бы Windows 8? Если вы это сделаете, вы можете просто использовать Get-NetTCPConnection
командлет, который по существу netstat
в форме объекта.
Таким образом, вы можете сделать это, что должно получить ту же информацию без хлопот
get-nettcpconnection | select local*,remote*,state,@{Name="Process";Expression={(Get-Process -Id $_.OwningProcess).ProcessName}}
У вас нет Windows 8+? Ну, тогда мы могли бы улучшить ваш скрипт разбора. Если сделать еще один шаг для создания объекта, это предотвратит проблему с соответствием регулярному выражению.
netstat -ano | Where-Object{$_ -match 'LISTENING|UDP'} | ForEach-Object{
$split = $_.Trim() -split "\s+"
[pscustomobject][ordered]@{
"Proto" = $split[0]
"Local Address" = $split[1]
"Foreign Address" = $split[2]
# Some might not have a state. Check to see if the last element is a number. If it is ignore it
"State" = if($split[3] -notmatch "\d+"){$split[3]}else{""}
# The last element in every case will be a PID
"Process Name" = $(Get-Process -Id $split[-1]).ProcessName
}
}
Если бы вы были ограничены PowerShell v2, вам нужно было бы изменить psobject и упорядочить приведение типов.
netstat -ano | Where-Object{$_ -match 'LISTENING|UDP'} | ForEach-Object{
$split = $_.Trim() -split "\s+"
New-Object -Type pscustomobject -Property @{
"Proto" = $split[0]
"Local Address" = $split[1]
"Foreign Address" = $split[2]
# Some might not have a state. Check to see if the last element is a number. If it is ignore it
"State" = if($split[3] -notmatch "\d+"){$split[3]}else{""}
# The last element in every case will be a PID
"Process Name" = $(Get-Process -Id $split[-1]).ProcessName
}
} | Select "Proto", "Local Address", "Foreign Address", "State", "Process Name"
Последний select
оператор гарантирует порядок свойств, который был бы перетасован в противном случае, и является функциональным эквивалентом [ordered]
Так что это даст вам результат, как это...
Proto Local Address Foreign Address State Process Name
----- ------------- --------------- ----- ------------
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING svchost
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING System
TCP 0.0.0.0:1279 0.0.0.0:0 LISTENING PlexDlnaServer
TCP 0.0.0.0:2869 0.0.0.0:0 LISTENING System
Затем вы можете обращаться с ними так же, как с любым объектом и фильтром PowerShell, по своему усмотрению или выводом в CSV или с тем, что вам нужно сделать. Это структурировано сейчас.
В зависимости от вашей версии PowerShell вы также можете использовать Convert-FromString
которая принимает строки из одной строки и конвертирует их в объекты. Что-то еще, чтобы искать.
Более простой...
filter timestamp {"$(Get-Date -Format G): $_"};netstat -abno 1 | Select-String -Context 0,1 -Pattern LISTENING|timestamp