我创建了一个脚本来输出Get-NetTCPConnection
数据,但另外还显示了Process Name和Username。该脚本确实有效,但我希望有任何提示可以简化或使其更具规范性。
我想知道是否有更有效的方法将ProcessName
和Username
添加到输出,而无需将值预加载到自定义PSObject($obj
数组)。我担心自定义e={($obj |? PID -eq $_.OwningProcess | select -ExpandProperty UserName)}}
表达式过于复杂。
$obj=@()
Foreach($p In (Get-Process -IncludeUserName | where {$_.UserName} | `
select Id, ProcessName, UserName)) {
$properties = @{ 'PID'=$p.Id;
'ProcessName'=$p.ProcessName;
'UserName'=$p.UserName;
}
$psobj = New-Object -TypeName psobject -Property $properties
$obj+=$psobj
}
Get-NetTCPConnection | where {$_.State -eq "Established"} | select `
RemoteAddress, `
RemotePort, `
@{n="PID";e={$_.OwningProcess}}, @{n="ProcessName";e={($obj |? PID -eq $_.OwningProcess | select -ExpandProperty ProcessName)}}, `
@{n="UserName";e={($obj |? PID -eq $_.OwningProcess | select -ExpandProperty UserName)}} |
sort -Property ProcessName, UserName |
ft -auto
这是一个带有一些示例输出的屏幕截图:
模式:
$a = @()
foreach ($x in Get-Thing|..) {
$z = ..
$a += $z
}
并不是一个伟大的,因为数组上的+=
会将所有内容复制到新数组中,所以它可能会非常慢。 foreach() {}
有时可以比| ForEach-Object {}
运行得更快,但是如果你在()部分内部有一个管道并且数组添加正在进行,那么它可能不会产生很大的不同。典型替代品:
$a = foreach ($x in Get-Thing|..) {
$z = $x...
$z
}
要么
$a = Get-Thing | .. | ForEach-Object {
$_..
}
脚本的前半部分几乎没有任何内容:
原始:数组中的进程对象。
结果:调整了数组中的进程对象,但是根据您使用它们的方式进行了更改,但没有任何意义。
所以你可以放弃所有这些只是$obj = Get-Process -IncludeUsername
,它会工作相同。
|
之后,以及数组中的逗号之后,包括select
属性数组。这很好,因为如果后面有任何空格,则反引号会断开,很难看到。但是,如果您希望预处理使脚本的其余部分更好,请使用哈希表,然后第二部分中的查找变得更短更清晰:
# Make a lookup table by process ID
$Processes = @{}
Get-Process -IncludeUserName | ForEach-Object {
$Processes[$_.Id] = $_
}
Get-NetTCPConnection |
Where-Object { $_.State -eq "Established" } |
Select-Object RemoteAddress,
RemotePort,
@{Name="PID"; Expression={ $_.OwningProcess }},
@{Name="ProcessName"; Expression={ $Processes[[int]$_.OwningProcess].ProcessName }},
@{Name="UserName"; Expression={ $Processes[[int]$_.OwningProcess].UserName }} |
Sort-Object -Property ProcessName, UserName |
Format-Table -AutoSize
无论如何,现在这和@avvi的答案一样,我不得不停止写它但是因为我看不到他们的答案而无法使它工作 - Get-Process将Id作为数字和Get-NetTCPConnection返回将OwningProcess作为字符串返回,因此需要对哈希表查找进行转换。
无论如何都要发布关于循环/数组构建的讨论。
我在Code Review中找不到问题,所以我暂时在这里发布答案。
使用字典(哈希表)简化了表达式并改善了每个pid的查找时间。
$dict=@{}
Foreach($p In (Get-Process -IncludeUserName | where {$_.UserName -ne $null} | `
select Id, ProcessName, UserName)) {
$properties = @{ 'PID'=$p.Id;
'ProcessName'=$p.ProcessName;
'UserName'=$p.UserName;
}
$psobj = New-Object -TypeName psobject -Property $properties
$dict[$p.Id] = $psObj
}
Get-NetTCPConnection | where {$_.State -eq "Established"} | select `
RemoteAddress, `
RemotePort, `
@{n="PID";e={$_.OwningProcess}},
@{n="ProcessName";e={ $dict[[int]$_.OwningProcess].ProcessName }}, `
@{n="UserName"; e={ $dict[[int]$_.OwningProcess].UserName }} |
sort -Property ProcessName, UserName | ft -auto
get-nettcpconnection | select local*,remote*,state,@{Name="Process";Expression={(Get-Process -Id $_.OwningProcess).ProcessName}}
我不能相信这个解决方案,我在这里找到了:https://superuser.com/questions/1215093/powershell-one-liner-to-show-process-on-same-line-as-port-using-netstat-issue/1215237
Get-NetTCPConnection|
Select LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess
, @{n="ProcessName";e={(Get-Process -Id $_.OwningProcess).ProcessName}}
, @{n="UserName";e={(Get-Process -Id $_.OwningProcess -IncludeUserName).UserName}}|
Where {$_.State -eq"Established"}
|FT -autosize -Force
比清洁更干净。在每一行的末尾添加后面的勾号(`)或删除回车并放一行。这里的反引号似乎抛弃了格式化,你必须添加两个反引号(``)来保持格式。