想要将 PSList 包装在 Powershell 函数中以使用管道值
我喜欢 PSList,并使用 CPU 和运行时间来识别需要终止的进程。我想将它包装在一个返回管道值的 powershell 函数中,以便我可以执行如下操作:
get-remoteprocess server1 | where {$_.CPUMinutes -gt 4}
我陷入了从函数返回值 - 我理解它需要是一个数组的物体。
这是我的第一个版本的样子:
function get-remoteproc {
param ($hostname)
$results = pslist "\\$hostname"
for ($i= 3; $i -le $results.length; $i++) {
$strline = $results[$i]
$StrWithPrefix = " "+$results[$i]
$trimmedline = $StrWithPrefix -replace '\s+', " ";
$Splitline = $trimmedline.Split(" ")
$ProcessName = $Splitline[1]
.
.
$ProcessCPUTime = ":"+[string]$Splitline[7]
$SplitCpuTime = $ProcessCPUTime.Split(":")
$CpuHours = $SplitCpuTime[1]
$CpuMinutes = $SplitCpuTime[2]
$CpuSeconds = $SplitCpuTime[3]
.
.
.
$obj = New-Object PSObject
$obj | Add-Member Noteproperty -Name "Name" -Value $Name
$obj | Add-Member Noteproperty -Name "PPid" -Value $Ppid
$obj | Add-Member Noteproperty -Name "Pri" -Value $Pri
}
采用 Doug Finke 的建议,该建议非常简洁,这是我稍微修改的版本,它与管道值配合得很好。
function get-remoteproc {
param ($hostname=$env:COMPUTERNAME)
$results = PsList "\\$hostname"
foreach($record in $results[3..($results.Count)]) {
# Remove spaces
while ($record.IndexOf(" ") -ge 0) {
$record = $record -replace " "," "
}
$Name,$Processid,$Pri,$Thd,$Hnd,$Priv,$CPUTime,$ElapsedTime = $record.Split(" ")
$properties = @{
Name = $Name
Pid = $Processid
Pri = $Pri
Thd = $Thd
Hnd = $Hnd
Priv = $Priv
CPUTime = $CPUTime
ElapsedTime = $ElapsedTime
}
New-Object PSObject -Property $properties |
Add-Member -PassThru ScriptProperty CPUH {[int]$this.CPUTime.Split(":")[0]} |
Add-Member -PassThru ScriptProperty CPUM {[int]$this.CPUTime.Split(":")[1]} |
Add-Member -PassThru ScriptProperty CPUS {[int]$this.CPUTime.Split(":")[2]} |
Add-Member -PassThru ScriptProperty ElaH {[int]$this.ElapsedTime.Split(":")[0]} |
Add-Member -PassThru ScriptProperty ElaM {[int]$this.ElapsedTime.Split(":")[1]} |
Add-Member -PassThru ScriptProperty ElaS {[int]$this.ElapsedTime.Split(":")[2]}
}
}
以及对该函数的调用,这表明对象已正确展开以供管道使用:
get-remoteproc "Server1" | where {(($_.CPUM * $_.CPUS) -gt 60) -and ($_.name -notmatch "Idle" )}|
ft name, pid, pri, thd, hnd, priv, CPUH, cpuM, cpuS, ElaH, ElaM, ElaS -auto
谢谢大家!
I like PSList, and use the CPU and Elapsed times to indentify processes that need to be killed. I would like to wrap it in a powershell function that returns pipeline values so that I could do something like the following:
get-remoteprocess server1 | where {$_.CPUMinutes -gt 4}
I get stuck in returning values from the function - which I understand would need to be an array of objects.
Heres what my first version looks like:
function get-remoteproc {
param ($hostname)
$results = pslist "\\$hostname"
for ($i= 3; $i -le $results.length; $i++) {
$strline = $results[$i]
$StrWithPrefix = " "+$results[$i]
$trimmedline = $StrWithPrefix -replace '\s+', " ";
$Splitline = $trimmedline.Split(" ")
$ProcessName = $Splitline[1]
.
.
$ProcessCPUTime = ":"+[string]$Splitline[7]
$SplitCpuTime = $ProcessCPUTime.Split(":")
$CpuHours = $SplitCpuTime[1]
$CpuMinutes = $SplitCpuTime[2]
$CpuSeconds = $SplitCpuTime[3]
.
.
.
$obj = New-Object PSObject
$obj | Add-Member Noteproperty -Name "Name" -Value $Name
$obj | Add-Member Noteproperty -Name "PPid" -Value $Ppid
$obj | Add-Member Noteproperty -Name "Pri" -Value $Pri
}
Taking Doug Finke's suggestion, which is pleasingly terse, here is my slightly adapted version, which works well with pipeline values.
function get-remoteproc {
param ($hostname=$env:COMPUTERNAME)
$results = PsList "\\$hostname"
foreach($record in $results[3..($results.Count)]) {
# Remove spaces
while ($record.IndexOf(" ") -ge 0) {
$record = $record -replace " "," "
}
$Name,$Processid,$Pri,$Thd,$Hnd,$Priv,$CPUTime,$ElapsedTime = $record.Split(" ")
$properties = @{
Name = $Name
Pid = $Processid
Pri = $Pri
Thd = $Thd
Hnd = $Hnd
Priv = $Priv
CPUTime = $CPUTime
ElapsedTime = $ElapsedTime
}
New-Object PSObject -Property $properties |
Add-Member -PassThru ScriptProperty CPUH {[int]$this.CPUTime.Split(":")[0]} |
Add-Member -PassThru ScriptProperty CPUM {[int]$this.CPUTime.Split(":")[1]} |
Add-Member -PassThru ScriptProperty CPUS {[int]$this.CPUTime.Split(":")[2]} |
Add-Member -PassThru ScriptProperty ElaH {[int]$this.ElapsedTime.Split(":")[0]} |
Add-Member -PassThru ScriptProperty ElaM {[int]$this.ElapsedTime.Split(":")[1]} |
Add-Member -PassThru ScriptProperty ElaS {[int]$this.ElapsedTime.Split(":")[2]}
}
}
And a call to the function, which shows that the objects are unrolled correctly for consumption by the pipeline:
get-remoteproc "Server1" | where {(($_.CPUM * $_.CPUS) -gt 60) -and ($_.name -notmatch "Idle" )}|
ft name, pid, pri, thd, hnd, priv, CPUH, cpuM, cpuS, ElaH, ElaM, ElaS -auto
Thanks, everyone!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如 empo 指出的那样,您需要将 $obj 发送回管道。这是将 plist 文本处理为 PowerShell 对象的另一种方法。
As empo points out, you need to emit the $obj back to the pipeline. Here is another way to work the plist text into PowerShell objects.
要返回一一传递给管道的值数组,只需在函数中返回多个值即可。例如:
函数结果是
$obj
数组。当连接到管道时,数组将被注册,所有值将一一传递到流中。To return an array of values passed to the pipeline one by one, you just need to return multiple values in your function. For example:
The function result is an array of
$obj
. When connected to a pipeline the array will be enrolled, and all the values will be passed to the stream one by one.