当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 这里发生了一些事情

作者:精品下载站 日期:2024-12-14 07:41:36 浏览:14 分类:玩电脑

这里发生了一些事情


[玩转系统] 这里发生了一些事情

PS C:\> get-process chrome

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName                   
-------  ------    -----      ----- -----   ------     -- -----------                              
    177      26    35564      35104   203     1.61   1976 chrome                                   
    197      45    98676     107984   263    57.55   3016 chrome                                   
    179      25    26872      20500   187     0.36   5956 chrome                                   
    261      33    78456     103908   413   165.72   6260 chrome                                   
    187      26    39656      39980   198    21.00   7744 chrome                                   
    180      32    88896      85836   263    58.20   7828 chrome                                   
   1610      92   119076     178436   492   286.77   8276 chrome                                   
    192      38    87136      91124   257    13.98   9140 chrome                                   
    193      39    73280      82288   245   122.19   9284 chrome                                   
    194      27    57264      50276   204    15.20   9932 chrome                                   
    201      32    22936      26780   264    34.91  10076 chrome

现在,我真正想要的是一个总数。我可以使用 Measure-Object 轻松获得单个属性的值。

PS C:\> get-process chrome | measure vm -sum

Count    : 11
Average  :
Sum      : 3151364096
Maximum  :
Minimum  :
Property : VM

PS C:\> (get-process chrome | measure vm -sum).sum/1mb
3000.12890625

但理想情况下,我希望获得通过 Get-Process 看到的所有属性的总计。因此,我编写了一个名为 Get-ProcessTotal 的高级 PowerShell 函数。

#requires -version 3.0


Function Get-ProcessTotal {

<#
.SYNOPSIS
Get total values for multiple instances of same process

.DESCRIPTION
This command is designed to get the total value of common process properties:
Handles,NPM,PM,WS,VM, and CPU. The default behavior is to get the sum total
of these properties for processes that might have multiple instances such as
svchost. Although you can also use a wildcard for the process name and get 
totals for a group of processes.  As an alternative to the sum, you can get the
average of these properties.

The command writes a custom object to the pipeline and uses a custom format view
so that the output looks like what you get with Get-Process. This command will 
create a format ps1xml file on-the-fly called ProcessTotal.Format.ps1xml and
store it in the windowsPowerShell folder under Documents. After the file has been
created this command will simply load it into your PowerShell session.

The command writes a custom object that will include the total number of 
processes as well as a property that contains the original processes.

.PARAMETER Name
The name of the process you want to measure. You can use a wildcard. See 
the examples.

.EXAMPLE
PS C:\> get-processtotal chrome

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s) ProcessName                                   
-------  ------    -----      ----- -----   ------ -----------                                   
   4801     612  1120888    1282976  4444  2153.59 chrome    

.EXAMPLE
PS C:\> get-processtotal chrome -average | select *


Handles      : 300
NPM          : 39135
PM           : 71778048
WS           : 82160640
VM           : 291475200
CPU          : 134.6279296875
ProcessName  : chrome
Computername : JH-WIN81-ENT
Total        : 16
Processes    : {System.Diagnostics.Process (chrome), System.Diagnostics.Process (chrome), 
               System.Diagnostics.Process (chrome), System.Diagnostics.Process (chrome)...}
Measure      : Average

.EXAMPLE
PS C:\> get-processtotal vm* -comp chi-hvr2

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s) ProcessName                                   
-------  ------    -----      ----- -----   ------ -----------                                   
   3193     205   110904     166300   873        0 vm*     

CPU values are not available for remote computers.

.EXAMPLE
PS C:\> invoke-command {mkdir $env:userprofile\Documents\WindowsPowerShell | out-null} -comp chi-hvr2

PS C:\> invoke-command $(get-item Function:\Get-ProcessTotal).Scriptblock -comp chi-hvr2 -arg VM*

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s) ProcessName             PSComputerName        
-------  ------    -----      ----- -----   ------ -----------             --------------        
   3198     206   111012     166352   874 10178.39 VM*                     chi-hvr2

The first command creates the WindowsPowerShell folder on the remote computer.
The second command invokes the Get-ProcessTotal command on the remote computer
which creates the format ps1xml file also remotely. 

.NOTES
Last Updated: 2/21/2014
Version     : 0.9

Learn more:
 PowerShell in Depth: An Administrator's Guide
 PowerShell Deep Dives 
 Learn PowerShell 3 in a Month of Lunches 
 Learn PowerShell Toolmaking in a Month of Lunches 
 
   ****************************************************************
   * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
   * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *
   * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
   * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *
   ****************************************************************

.LINK
https://jdhitsolutions.com/blog/2014/02/theres-sum-thing-happening-here

.LINK
Get-Process
Measure-Object

.INPUTS
String

.OUTPUTS
Custom object
#>


[cmdletbinding(DefaultParameterSetName="Sum")]
Param(
[Parameter(Position=0, Mandatory=$True,
HelpMessage = "Enter the name of a process")]
[ValidateNotNullorEmpty()]
[Alias("processname")]
[string]$Name,

[Parameter(ParameterSetName="Sum")]
[switch]$Sum,

[Parameter(ParameterSetName="Average")]
[switch]$Average,

[ValidateNotNullorEmpty()]
[string]$Computername=$env:COMPUTERNAME
)

Begin {
    Write-Verbose -Message "Starting $($MyInvocation.Mycommand)"
    Write-Verbose -Message "Querying processes on $computername"
    if ($Average) {
        $measure="Average"
    }
    else {
        $measure="Sum"
    }
    Write-Verbose -Message "Measuring the $measure"
    #update format data if not found
    if (-Not (Get-FormatData -TypeName "My.ProcessTotal")) {
      
      $formatXML=Join-Path -path "$env:USERPROFILE\Documents\WindowsPowerShell" -ChildPath "ProcessTotal.format.ps1xml"
      
      #test if ps1xml file exists and if not create the file
      if (-Not (Test-Path -path $formatXMl)) {
      #the format xml. The Here string must be left justified to start and finish
      $xml=@'
<?xml version="1.0" encoding="utf-8" ?>
<!-- *******************************************************************
This was copied from the DotNetType.format.ps1xml file and modified
to fit my needs.
******************************************************************** -->
<Configuration>
    <ViewDefinitions>
      <View>
            <Name>process</Name>
            <ViewSelectedBy>
                <TypeName>My.ProcessTotal</TypeName>
            </ViewSelectedBy>
            <TableControl>
                <TableHeaders>
                    <TableColumnHeader>
                        <Label>Handles</Label>
                        <Width>7</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>NPM(K)</Label>
                        <Width>7</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>PM(K)</Label>
                        <Width>8</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>WS(K)</Label>
                        <Width>10</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>VM(M)</Label>
                        <Width>5</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>CPU(s)</Label>
                        <Width>8</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader />
                </TableHeaders>
                <TableRowEntries>
                    <TableRowEntry>
                        <TableColumnItems>
                            <TableColumnItem>
                                <ScriptBlock>[int]$_.Handles</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>[int]($_.NPM / 1024)</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>[int]($_.PM / 1024)</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>[int]($_.WS / 1024)</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>[int]($_.VM / 1048576)</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>
if ($_.CPU -ne $()) 
{ 
   [math]::Round($_.CPU,2)
}
else {
   "NA"
}
				</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>ProcessName</PropertyName>
                            </TableColumnItem>
                        </TableColumnItems>
                    </TableRowEntry>
                </TableRowEntries>
            </TableControl>
        </View>
    </ViewDefinitions>
</Configuration>
'@
        Try {
            $xml | Out-File -FilePath $formatXML -Encoding ascii -ErrorAction Stop
           
        }
        Catch {
            Write-Warning "Failed to create format xml file $formatXML"
            Write-Warning $_.Exception.Message
        } 
      } #if not test path for format xml file

       #update format data
       Write-Verbose -Message "Adding a custom format view from $formatxml."
       Update-FormatData -AppendPath $formatXML -ErrorAction Stop
    } #if not get-formatdata

    #define a hashtable of parameters to splat to Measure-Object so we 
    #can get either -Sum or -Average
    $measureParams=@{$Measure=$True;Property=$Null}
} #begin

Process {

Try {
    Write-Verbose -Message "Getting processes for $Name"
    $processes = Get-Process $Name -Computername $computername -ErrorAction Stop
}
Catch {
    Write-Warning "Failed to find process $name on $computername"
    #bail out
    Return
}

If ($processes) {
    Write-Verbose -message "Defining a hash table of property values"
    $properties="Handles","NPM","PM","WS","VM","CPU"
    #initialize the ordered hash table
    $propertyHash=[ordered]@{}
    #add each property to the hash table getting the sum or average
    foreach ($property in $properties) {
       Write-Verbose -message "Adding $property"
       $measureParams.Property = $property
       $value = $processes | Measure-Object @measureParams | Select -ExpandProperty $measure
       $propertyHash.Add($property,$value)
    } #foreach property

    Write-Verbose -message "Adding remaining properties"
    $propertyHash.Add("ProcessName",$Name)
    $propertyHash.Add("Computername",$processes[0].MachineName)
    $propertyHash.Add("Total",$processes.count)
    $propertyHash.Add("Processes",$processes)
    $propertyHash.Add("Measure",$Measure)

    #create a custom object
    Write-Verbose -Message "Creating object from hashtable"
    $obj = New-Object -TypeName psobject -Property $propertyHash 

    #add a type name
    Write-Verbose -Message "Adding type name"
    $obj.psobject.TypeNames[0]="My.ProcessTotal"

    #write the object to the pipeline
    $obj

} #if $processes
} #process

End {
    Write-Verbose -Message "Ending $($MyInvocation.Mycommand)"
} #end
} #end function

#add an optional alias
Set-Alias -Name gpt -Value Get-ProcessTotal

该函数的主要部分获取流程的所有实例,然后创建一个具有多个属性总和的自定义对象。

$properties="Handles","NPM","PM","WS","VM","CPU"
    #initialize the ordered hash table
    $propertyHash=[ordered]@{}
    #add each property to the hash table getting the sum or average
    foreach ($property in $properties) {
       Write-Verbose -message "Adding $property"
       $measureParams.Property = $property
       $value = $processes | Measure-Object @measureParams | Select -ExpandProperty $measure
       $propertyHash.Add($property,$value)
    } #foreach property

输出还包括计算机名称(如果您正在查询远程计算机)、总数以及原始进程对象(如果您需要对它们执行其他操作)。

$propertyHash.Add("ProcessName",$Name)
    $propertyHash.Add("Computername",$processes[0].MachineName)
    $propertyHash.Add("Total",$processes.count)
    $propertyHash.Add("Processes",$processes)
    $propertyHash.Add("Measure",$Measure)

    #create a custom object
    Write-Verbose -Message "Creating object from hashtable"
    $obj = New-Object -TypeName psobject -Property $propertyHash

这可能就足够了,但所有值都以字节为单位,并且默认显示将是一个列表。相反,我想要像使用 Get-Process 得到的默认输出。因此,我利用 PowerShell 的可扩展类型系统并创建了我自己的格式数据 xml 文件。实际上,我所做的是在 DotNetTypes.format.ps1xml 文件中找到流程对象的部分,复制并调整它。

我最初的想法是拥有一个单独的 XML 文件。如果我要构建一个模块,那将是最好的选择。但这是一个独立的函数,因此我添加了一些逻辑来在首次使用时创建 XML 文件并将其添加到我的 PowerShell 会话中。 XML 内容作为 Here 字符串存储在函数中。

if (-Not (Get-FormatData -TypeName "My.ProcessTotal")) {
      
      $formatXML=Join-Path -path "$env:USERPROFILE\Documents\WindowsPowerShell" -ChildPath "ProcessTotal.format.ps1xml"
      
      #test if ps1xml file exists and if not create the file
      if (-Not (Test-Path -path $formatXMl)) {
      #the format xml. The Here string must be left justified to start and finish
      $xml=@'
<?xml version="1.0" encoding="utf-8" ?>
...
Try {
            $xml | Out-File -FilePath $formatXML -Encoding ascii -ErrorAction Stop
           
        }
        Catch {
            Write-Warning "Failed to create format xml file $formatXML"
            Write-Warning $_.Exception.Message
        } 
      } #if not test path for format xml file

       #update format data
       Write-Verbose -Message "Adding a custom format view from $formatxml."
       Update-FormatData -AppendPath $formatXML -ErrorAction Stop
    } #if not get-formatdata

简而言之,该函数首先测试是否存在 My.ProcessTotal 类型的对象的格式数据。如果没有,则测试我存储在 WindowsPowerShell 文件夹中的 XML 文件。如果不存在,则创建该文件。无论如何,一旦文件存在,就会使用 Update-FormatData 将其加载到 PowerShell 中。

PowerShell 如何知道要使用什么类型?我告诉过它。当我定义自定义对象时,我还给了它一个新的类型名称。

$obj.psobject.TypeNames[0]="My.ProcessTotal"

将函数加载到我的会话中后,我现在可以获得如下结果:

PS C:\> Get-ProcessTotal chrome

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s) ProcessName
-------  ------    -----      ----- -----   ------ -----------
   3560     424   747336     855356  3027   948.83 chrome

输出与 Get-Process 类似,只是值是总和。我还添加了一个获取平均值的选项,以防万一。如果通过管道传输到 Get-Member,您将看到新的类型定义以及其他非默认属性。

PS C:\> Get-ProcessTotal chrome | get-member


   TypeName: My.ProcessTotal

Name         MemberType   Definition
----         ----------   ----------
Equals       Method       bool Equals(System.Object obj)
GetHashCode  Method       int GetHashCode()
GetType      Method       type GetType()
ToString     Method       string ToString()
Computername NoteProperty System.String Computername=JH-WIN81-ENT
CPU          NoteProperty System.Double CPU=960.484375
Handles      NoteProperty System.Double Handles=3569
Measure      NoteProperty System.String Measure=Sum
NPM          NoteProperty System.Double NPM=435088
PM           NoteProperty System.Double PM=762679296
Processes    NoteProperty System.Object[] Processes=System.Object[]
ProcessName  NoteProperty System.String ProcessName=chrome
Total        NoteProperty System.Int32 Total=11
VM           NoteProperty System.Double VM=3170050048
WS           NoteProperty System.Double WS=879349760

基于评论的帮助中还有一些其他示例。该脚本还会创建一个别名,因此如果您不想要它,请务必注释掉末尾的行。

我希望你们中的一些人能够讨论一下并让我知道你们的想法。或者至少我希望你掌握了新技术或新想法。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯