PowerShell属性表达式将执行时间增加4-5倍

向下滚动以获取TL; DR

我需要尽快为每个进程获取以下属性,最好是5秒,最多10秒: ID,名称,描述,路径,公司,用户名,会话ID,StartTime,内存,CPU(百分比,而不是时间)

要获取此数据,我整理了以下(我认为)功能完善的代码段:

$ProcessCPU = Get-Wmiobject Win32_PerfFormattedData_PerfProc_Process | Select-Object IDProcess,PercentProcessorTime
$Processes  = Get-Process -Includeusername | 
                Select-Object `
                    @{Name='Id';Expression={[int]$_.Id}},@{Name='Name';Expression={[string]$_.Name}},@{Name='Description';Expression={[string]$_.Description}},@{Name='Path';Expression={[string]$_.Path}},@{Name='Company';Expression={[string]$_.Company}},@{Name='username';Expression={[string]$_.username}},@{Name='SessionId';Expression={[string]$_.SessionId}},@{Name='StartTime';Expression={[string](($_.StartTime).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))}},@{Name='MemoryMB';Expression={[int]([math]::Round($_.WorkingSet/1MB,2))}},@{Name='CPUPercent';Expression={
                        [int]($ProcessCPU | ?{'IDProcess' -eq $_.Id}).PercentProcessorTime
                    }}

问题在于,此行导致执行此操作需要18-22秒(这大约需要16秒):

@{Name='CPUPercent';Expression={
     [int]($ProcessCPU | ?{'IDProcess' -eq $_.Id}).PercentProcessorTime
}}
PS C:\Windows\system32> Measure-Command -Expression {
    $ProcessCPU = Get-Wmiobject Win32_PerfFormattedData_PerfProc_Process | Select-Object IDProcess,PercentProcessorTime
    $Processes  = Get-Process -Includeusername | 
                    Select-Object `
                        @{Name='Id';Expression={[int]$_.Id}},@{Name='CPUPercent';Expression={
                            [int]($ProcessCPU | ?{'IDProcess' -eq $_.Id}).PercentProcessorTime
                        }}
}

TotalSeconds      : 19.061206

当我删除上面提到的慢属性表达式并保留WMI查询时,执行大约需要4.5秒:

Measure-Command -Expression {
    $ProcessCPU = Get-Wmiobject Win32_PerfFormattedData_PerfProc_Process | Select-Object IDProcess,2))}}
}

TotalSeconds      : 4.5202906

我认为,通过在单个查询中获取所有必需的数据并返回到$ProcessCPU数组会很快-但我很欣赏我正在遍历{{1 }}。

TL; DR:

是否有更高效的方法将两个对象连接到一个公共属性,而不是像上面那样使用迭代?即$Processes

我尝试了以下代码块来测试$ProcessCPU.IDProcess on $Processes.Id,它仅用了3秒钟就执行了,但是输出是不可接受的:

$Output = $ProcessCPU + $Processes | Group-Object -Property Id

{{0}}

freekoo 回答:PowerShell属性表达式将执行时间增加4-5倍

  • 使用CIM建立哈希表,该哈希表首先将进程ID(PID)映射到其CPU百分比。

  • 然后使传递给Select-Object的计算所得属性查询该哈希表以进行有效查找:

Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
  ForEach-Object -Begin   { $htCpuPctg=@{} } `
                 -Process { $htCpuPctg[$_.IdProcess] = $_.PercentProcessorTime }       #`

Get-Process -IncludeUserName | 
  Select-Object Id,Name,Description,Path,Company,UserName,SessionId,@{Name='StartTime';Expression={[string](($_.StartTime).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))}},@{Name='MemoryMB';Expression={[int]([math]::Round($_.WorkingSet/1MB,2))}},@{Name='CPUPercent';Expression={ $htCpuPctg[[uint32] $_.Id] }}

注意:

    使用
  • Get-CimInstance而不是Get-WimObject,因为CIM cmdlet取代了PowerShell v3(于2012年9月发行)中的WMI cmdlet。因此,应避免使用WMI cmdlet,这尤其是因为将来所有精力都会投入的PowerShell Core ,甚至不再拥有。有关更多信息,请参见this answer

  • 通常无需使用诸如@{Name='Id';Expression={[int]$_.Id}}之类的计算属性即可按原样提取属性-只需使用属性的 name -Id-作为Select-Object -Property的参数(但是您已经澄清了您正在使用计算所得的属性,因为您希望对属性的数据类型进行显式控制,以便通过JSON将数据发送到IoT网关)。

  • 请注意,CIM将PID作为[uint32]类型的值报告,而Get-Process使用[int]值-因此需要在哈希表查找中强制转换为[uint32]

本文链接:https://www.f2er.com/3106202.html

大家都在问