PowerShell Beispiele : Performance Counter

Performancecounter gibt es in Windows schon seit Windows NT 3.x und sie sind das Gegenstück zu SNMP auf Unix.

Performancecounter lesen

Seit PowerShell 2 gibt es nun auch ein "Get-Counter"-Commandlet, welches einen direkten lesenden Zugriff auf die Performance Counter erlaubt:

PS> (Get-Counter "\prozessor(_total)\prozessorzeit (%)").countersamples[0]

Path                       InstanceName                             CookedValue
----                       ------------                             -----------
\\nawnbfc\prozessor(_to... _total                              4,24059311090853

Natürlich kann man auch über das .NET-Framework auf Performancecounter zugreifen, was anscheinend auch schneller aber vor allem einfacher ist, als der WMI-Zugriff. Hier ein Muster auf einem englischen Server:

[PS] $perf = new-object System.Diagnostics.PerformanceCounter
[PS] $perf.countername = "% Processor Time"
[PS] $perf.Categoryname = "Processor"
[PS] $perf.Instancename = "_Total"
 
oder
 
[PS] $perf = new-object System.Diagnostics.PerformanceCounter "Processor","% Processor Time", "_Total"

[PS] $perf
 
CategoryName     : Processor
CounterHelp      : % Processor Time is the percentage of elapsed time that the
                   processor spends to execute a non-Idle thread. It is calcula
                   ted by measuring the duration of the idle thread is active i
                   n the sample interval, and subtracting that time from interv
                   al duration.  (Each processor has an idle thread that consum
                   es cycles when no other threads are ready to run). This coun
                   ter is the primäry indicator of processor activity, and disp
                   lays the average percentage of busy time observed during the
                    sample interval. It is calculated by monitoring the time th
                   at the service is inactive, and subtracting that value from
                   100%.
CounterName      : % Processor Time
CounterType      : Timer100NsInverse
InstanceLifetime : Global
InstanceName     : _Total
ReadOnly         : True
MachineName      : .
RawValue         : 36131046250000
Site             :
Container        :

Das ist ja noch einfach, so lange es genau ein Counter ist und die Namen als auch Instanzen gleich sind. Nun gibt es aber Performancecounter, die mehrere Instanzen haben, z.B.: die Exchange 2007 CCR Replikation. Da muss man sich dann selbst durch die Instanzen arbeiten.

[PS] $perfcat = new-object System.Diagnostics.PerformanceCounterCategory("MSExchange Replication")
[PS] $perfcat.GetInstanceNames() 
      | %{$perfcat.GetCounters($_)} 
      | ft Cat*,countername,Instancename,rawvalue
 
CategoryName        CounterName         InstanceName             RawValue
------------        -----------         ------------             --------
MSExchange Repli... CopyNotification... _total                     83317
MSExchange Repli... CopyGenerationNu... _total                     83317
MSExchange Repli... InspectorGenerat... _total                     83317
MSExchange Repli... ReplayNotificati... _total                     83317
MSExchange Repli... ReplayGeneration... _total                     83317
MSExchange Repli... ReplayQueueLength   _total                         0
MSExchange Repli... Suspended           _total                         0
MSExchange Repli... TrUNCatedGenerat... _total                         0
MSExchange Repli... CopyNotification... s1 sg1                     83317
MSExchange Repli... CopyGenerationNu... s1 sg1                     83317
MSExchange Repli... InspectorGenerat... s1 sg1                     83317
MSExchange Repli... ReplayNotificati... s1 sg1                     83317
MSExchange Repli... ReplayGeneration... s1 sg1                     83317
MSExchange Repli... ReplayQueueLength   s1 sg1                         0
MSExchange Repli... ReplayBatchSize     s1 sg1                         0
MSExchange Repli... CopyQueueLength     s1 sg1                         0

Aber auch das geht mit Get-Counter, man muss nur etwas geschickter die Abfrage stellen. Hier z.B. für die Anzahl der Handles aller Prozesse

(get-counter "\Process(*)\handle count" ).countersamples

Path                                    InstanceName                CookedValue
----                                    ------------                -----------
\\w2k8r2e2010\process(idle)\handle c... idle                                  0
\\w2k8r2e2010\process(system)\handle... system                              717
\\w2k8r2e2010\process(smss)\handle c... smss                                 32
\\w2k8r2e2010\process(csrss#2)\handl... csrss                                72
\\w2k8r2e2010\process(csrss#1)\handl... csrss                               293

Eine Filterung ist dann mit "Where" möglich oder sie suchen genau einen bestimmten Wert. Vielleicht hilft es auch einfach einmal alle Counter auf einem PC aufzulisten:

#Alle Counter listen
Get-Counter "\*\*"

# Alle Counter einer Gruppe mit allen Instanzen listen
Get-Counter "\MSExchange Replication(*)\*"

# Alle Counter einer bekannten Instanz auslesen
Get-Counter "\MSExchange Replication(_total)\*

# einen einzelnen Counter
Get-Counter "\MSExchange Replication(_total)\log copy kb/sec"

Achtung: Der String des Counters ist "Case sensibel"

Performancecounter anlegen

Was viele Personen vermutlich seltener verwenden ist die Funktion, eigene Counter anzulegen.

Damit das PowerShell-Skript Performancecounter anlegen kann, muss es als Administrator gestartet werden

# Create performance Counter
#
# Achtung: als ADMIN starten, wenn man den Counter anlegen muss

$categoryName = "MSXFAQCounters"
 
if ([System.Diagnostics.PerformanceCounterCategory]::Exists($categoryName)) {
    write-host "Counter exists"
}
else {
    write-host "Create Counters"
    $counterData = new-object System.Diagnostics.CounterCreationDataCollection
     
    $counter = new-object  System.Diagnostics.CounterCreationData
    $counter.CounterType = [System.Diagnostics.PerformanceCounterType]::AverageCount64
    $counter.CounterName = "64bit Counter Name"
    $counterData.Add($counter)

    # Counter real anlegen
    [System.Diagnostics.PerformanceCounterCategory]::Create($categoryName, $categoryName, [System.Diagnostics.PerformanceCounterCategoryType]::SingleInstance, $counterData)
}

Natürlich gibt es noch viele andere Countertypen. In Perfmon sind diese Counter dann einfach einzusehen

Offen bleibt dann nur noch die Frage, wie man aus PowerShell auch Werte schreiben kann

Performancecounter schreiben

Auch das ist per PowerShell relativ einfach möglich.

$categoryName = "MSXFAQCounters"
# Counter holen
$Percounter64bit = New-Object System.Diagnostics.PerformanceCounter($categoryName,"64bit Counter Name",$false)

# Aktueller Wert
$Percounter64bit.rawValue

# Wert ändern
$Percounter64bit.rawValue = [int]8

#Neuer Wert
$Percounter64bit.rawValue

 

Offen bleibt dann nur noch die Frage, wie man aus PowerShell auch Werte schreiben kann

 

Performancecounter löschen

Wenn Sie den Counter nicht mehr benötigen, dann sollten Sie diesen natürlich auch wieder korrekt entfernen

# Remove performance Counter
#
# Achtung: als ADMIN starten, wenn man den Counter loeschen will
$categoryName = "MSXFAQCounters"
 
if ([System.Diagnostics.PerformanceCounterCategory]::Exists($categoryName)) {
    [System.Diagnostics.PerformanceCounterCategory]::Delete($categoryName)
}

Hinweis:
Mit diesen wenigen Zeilen können jeden Counter ohne weitere Rückfrage entfernen !

Weitere Links

Auch hierzu finden sich im Internet umfangreiche Beschreibungen