ค้นหาเว็บไซต์

มีเรื่องรวมเกิดขึ้นที่นี่


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 ดังนั้นฉันจึงเขียนฟังก์ชัน PowerShell ขั้นสูงที่เรียกว่า Get-ProcessTotal

#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 จะถูกจัดเก็บเป็นสตริงที่นี่ในฟังก์ชัน

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 หรือไม่ ถ้าไม่เช่นนั้น ให้ทดสอบไฟล์ XML ที่ฉันจัดเก็บไว้ในโฟลเดอร์ WindowsPowerShell หากไม่มีอยู่ ไฟล์จะถูกสร้างขึ้น ไม่ว่าในกรณีใดก็ตาม เมื่อไฟล์นั้นมีอยู่แล้ว ไฟล์นั้นจะถูกโหลดลงใน PowerShell โดยใช้ Update-FormatData

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

มีตัวอย่างอื่นๆ ในความช่วยเหลือตามความคิดเห็น สคริปต์ยังสร้างนามแฝงด้วย ดังนั้นหากคุณไม่ต้องการให้ตรวจสอบให้แน่ใจว่าได้แสดงความคิดเห็นในบรรทัดตอนท้าย

ฉันหวังว่าพวกคุณบางคนจะเตะมันและแจ้งให้เราทราบว่าคุณคิดอย่างไร หรืออย่างน้อยที่สุด ฉันหวังว่าคุณจะได้รับเทคนิคหรือแนวคิดใหม่ๆ

บทความที่เกี่ยวข้อง