2011-05-08 49 views
2

我喜欢PSList,并使用CPU和Elapsed时间来标识需要终止的进程。我想换它在返回管道值的PowerShell的函数,这样我可以做类似如下:想要在Powershell函数中使用管道值包装PSList

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 

} 

以道格·芬克的建议,这是令人愉快的简洁,这里是我的小幅调整后的版本,它与管道的值效果很好。

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 

谢谢大家!

+0

你的函数缺少右大括号,否则很难说什么是不是在你的代码 – 2011-05-08 12:07:41

回答

0

要返回一个一个传递给管道的值的数组,您只需要在函数中返回多个值。例如:

 
function get-remoteproc { 
param ($hostname) 
    $results = pslist "\\$hostname" 
    for ($i= 3; $i -le $results.length; $i++) { 

    # your staff to $obj 

    # output $obj 
    $obj 
    } 
} 

函数结果是$obj阵列。当连接到管道时,数组将被注册,并且所有值将被逐个传递给流。

+0

要罚款为了输出对象行'$ obj'是很不够。使用'$ objs'在这里是无效的(对于这样的数组,'+ ='是一个非常慢的操作,仅供参考)。 – 2011-05-08 16:18:16

+0

$ objs不会有效,但我相信,$ objs会。 – mjolinor 2011-05-08 16:24:37

+0

@罗曼:我不这么认为。功能与过滤器有不同的作用在这里函数必须返回一个数组,以便它可以在后续的管道中处理。 – 2011-05-08 17:31:11

1

正如empo指出的那样,您需要将$ obj发送回管道。这是将plist文本处理到PowerShell对象的另一种方法。

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 CPUHours {$this.CPUTime.Split(":")[0]} | 
      Add-Member -PassThru ScriptProperty CPUMinutes {$this.CPUTime.Split(":")[1]} | 
      Add-Member -PassThru ScriptProperty CPUSeconds {$this.CPUTime.Split(":")[2]} 

    } 
}