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 оператор берет все 4s:

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
Другие вопросы по тегам