![Powershell 单行显示使用 netstat 问题与端口在同一行上的进程](https://linux22.com/image/1531782/Powershell%20%E5%8D%95%E8%A1%8C%E6%98%BE%E7%A4%BA%E4%BD%BF%E7%94%A8%20netstat%20%E9%97%AE%E9%A2%98%E4%B8%8E%E7%AB%AF%E5%8F%A3%E5%9C%A8%E5%90%8C%E4%B8%80%E8%A1%8C%E4%B8%8A%E7%9A%84%E8%BF%9B%E7%A8%8B.png)
首先,我只想确保用户 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:系统 System5 0.0.0.0:0 正在监听系统
TCP 0.0.0.0:623 0.0.0.0:0 正在监听 LMS
它更改的端口是 445,但我不知道为什么它只更改了那个端口,而其余端口都按预期工作。为什么脚本将 445 更改为“System System5”?
不幸的是,无法使用其他工具,所以我只能使用内置的 Windows 工具。
答案1
$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"
另请阅读 Matt 的回答替换字符串中最后一次出现的子字符串在 stackoverflow。
顺便提一句:
$ppath
没有定义…- ...
netstat -ano
应该足够了(请注意,该-b
选项可能很耗时,并且除非您有足够的权限,否则将会失败)。
答案2
JosefZ 的回答完美地解释了您的问题。您正在使用正则表达式,它正在执行您要求它执行的操作,只是替换的内容可能超出了您的预期。
附注是,你netstat
要求
显示创建每个连接或监听端口所涉及的可执行文件
使用 b 开关。但是,您要删除 with,select-string
因为该进程出现在其他数据之后的单独一行中。这不是世界末日,而是因为您可以使用-Context
of 之类的东西Select-String
来获得它,但这必须在另一个时间更仔细地研究。
我想就您在这种情况下可以做什么提供其他建议。
不幸的是,无法使用其他工具,所以我只能使用内置的 Windows 工具。
有趣的是,你至少有 Windows 8 吗?如果你有,你可以使用Get-NetTCPConnection
cmdlet 本质上是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
它接受单行字符串并将其转换为对象。还有其他需要查找的内容。
答案3
更简单...
filter timestamp {"$(Get-Date -Format G): $_"};netstat -abno 1 | Select-String -Context 0,1 -Pattern LISTENING|timestamp