Powershell one-liner para mostrar o processo na mesma linha que a porta usando o problema netstat

3

Primeiro, quero apenas garantir que o usuário Erik Bitemo receba crédito pelo código original que estou usando aqui. A saída é o que estou procurando com uma exceção: uma das portas desaparece e "System System5" aparece em seu lugar e não consigo entender por que isso está acontecendo.

Objetivo: Mostrar todas as portas TCP (Listening) e UDP e o processo associado a cada uma na mesma linha.

Um liner sendo usado:

$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)";     }

Exemplo de saída:

TCP 0.0.0.0:135 0.0.0.0:0 LISTENING svchost
TCP 0.0.0.0: System System5 0.0.0.0:0 LISTENING System
TCP 0.0.0.0:623 0.0.0.0:0 LISTENING LMS

A porta que ele muda é 445, mas não tenho idéia de por que ele está mudando apenas quando o resto das portas estão funcionando como pretendido. Por que o script está alterando 445 para "System System5"?

Infelizmente, não é possível usar outras ferramentas, por isso estou limitado a usar ferramentas do Windows incorporadas.

    
por Ric 01.06.2017 / 17:48

3 respostas

3

$p pode ser algo como TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4 e $nar[-1] é string 4 então -replace operator pega all 4 s:

TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
            ↑↑                      ↑

Forçar a substituição apenas da última ocorrência de $nar[-1] usando fim de linha âncora (escape $ ):

$p -replace "$($nar[-1])'$","$ppath $pname"

Leia também a resposta de Matt para Substituir a última ocorrência de substring em string em stackoverflow.

BTW:

  • $ppath não está definido…
  • … e netstat -ano devem ser suficientes (observe que a opção -b pode ser demorada e falhará, a menos que você tenha permissões suficientes).
por 02.06.2017 / 00:35
2

A resposta do JosefZ explica perfeitamente o seu problema. Você está usando o regex e está fazendo exatamente o que você está pedindo para fazer, talvez substituindo mais do que o esperado.

Uma nota secundária é que você está pedindo netstat a

displays the executable involved in creating each connection or listening port

com o comutador b. No entanto, você está descartando isso com select-string , pois esse processo aparece em sua própria linha após os outros dados. Esse não é o fim do mundo, mas porque você pode usar coisas como -Context de Select-String para conseguir isso, mas isso terá que ser examinado mais de perto em outro momento.

Eu gostaria de oferecer outras sugestões sobre o que você pode fazer nessa situação.

Using other tools is unfortunately not possible so I'm limited to using built-in Windows tools.

Coisa engraçada sobre isso, você tem pelo menos o Windows 8? Se preferir, use o cmdlet Get-NetTCPConnection que é essencialmente netstat em forma de objeto.

Então você pode fazer isso, o que deve te dar a mesma informação sem o incômodo

get-nettcpconnection | select local*,remote*,state,@{Name="Process";Expression={(Get-Process -Id $_.OwningProcess).ProcessName}}

Não tem o Windows 8+? Bem, então poderíamos melhorar seu script de análise. Dar um passo além para criar um objeto evitará problemas com a correspondência de expressões regulares.

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
    }
}

Se você estivesse limitado ao PowerShell v2, precisaria alterar o psobject e os casts ordenados

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" 

A última instrução select garante a ordem da propriedade, que seria embaralhada de outra forma, e é o equivalente funcional a [ordered]

Então isso te renderá assim ...

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  

Que você pode tratar como qualquer outro objeto do PowerShell e filtrar como quiser ou enviar para o CSV ou o que for necessário. Está estruturado agora.

Dependendo da sua versão do PowerShell, você também pode usar Convert-FromString , que utiliza strings de linha única e as converte em objetos também. Algo mais para procurar.

    
por 02.06.2017 / 05:34
0

Mais simples ...

filter timestamp {"$(Get-Date -Format G): $_"};netstat -abno 1 | Select-String -Context 0,1 -Pattern LISTENING|timestamp
    
por 12.02.2018 / 21:21