Prozesse und Dienste

 

1 Überblick
   Beispiel 1: Ermitteln der Aliase von Stop-Process

2 lokal laufende Prozesse aufrufen
   Beispiel 1: lokale Prozesse ermitteln und mit Select-Object ausgeben
   Beispiel 2: lokale Prozesse ermitteln und das Ergebnis mit dem Formatoperator formatieren
   Beispiel 3: lokale Prozesse ermitteln und das Ergebnis mit dem Formatoperator, sowie Format-Table formatieren
   Beispiel 4: Wieviele und welche Prozesse laufen momentan
   Beispiel 5a: Vorder- und Hintergrundprozesse starten
   Beispiel 5b: Vorder- und Hintergrundprozesse mit Powershell unterscheiden

3 remote laufende Prozesse aufrufen
   3.1 Prozessabfrage mittels .Net bzw. Powershell cmdlet
         Beispiel 1: remote Prozesse und das Ergebnis mit dem Formatoperator formatieren
         Beispiel 2: Hinzufügen einer berechneten Spalte (Laufzeit eines Prozesses in Minuten)
   3.2 Prozessabfrage mittels WMI      
       Beispiel 1: remote Prozesse und das Ergebnis mit dem Formatoperator formatieren
   3.3 RemotePowershellSession
      Beispiel: Prozessabfrage über PSRemoting

4 Ausgewählte Prozesse analysieren und bearbeiten
   4.1 ein Prozessobjekt erstellen
      Beispiel 1: Ein Prozessobjekt mit .Net [system.diagnostics.process] bzw. mit dem cmdlet "get-process" erstellen
      Beispiel 2: Ein Prozessobjekt mit der WMI-Klasse win32_process erstellen
   4.2 Prozesse neu starten      
        4.2.1 Verwendung von start-Process aus den Communityextensions          
        4.2.2 Verwendung einer .Net Klasse zum Starten eines Prozesses
               Beispiel 1: Prozess neu starten mit [system.diagnostics.process]::start(<Name>)    
               Beispiel 2: Prozess neu starten mit [system.diagnostics.process]::start(<Name>) unter anderen Credentials
        4.2.3 Verwendung von start-process zum Starten eines Prozesses
               Beispiel 1: Prozess einfach neu starten mit cmdlet start-process (native)
               Beispiel 2: Prozess neu starten mit cmdlet start-process (native) mit den Parametern -wait und -WindowStyle
               Beispiel 3: Onlinehilfe zu start-process (native) mit dem Parameter -verb
               Beispiel 4: ermittlen der Verben von *.doc Dateien
               Beispiel 5: Prozess neu starten mit cmdlet start-process (native) mit dem Parametern -verb
       4.2.4 Verwendung von WMI zum Starten eines Prozesses
               Beispiel 1: einen RobocopyBefehl remote mit der Create-Methode von Win32_Process aufrufen               
               Beispiel 2: Weitere Optionen von Win32_Process ermitteln
               Beispiel 3: einen RobocopyBefehl mit weiteren Optionen wie Username, Passwort, Impersonationlevel aufrufen
               Beispiel 4: Cmdlet Invoke-WmiMethod (Alias: IWMI)
     4.2.5 Starten von mehreren Prozessen im Hintergrund
              Beispiel 1: Anzeige der Job-cmdlets
              Beispiel 2: Starten mehrerer Prozesse als Job
     4.2.6 Läuft mindestens eine Instanz eines Prozesses
              Beispiel 1: Läuft ein bestimmter Prozess
                
5 Schließen von Prozessen
  5.1 Prozesse beenden mit .Net Methoden
      Beispiele: einige Methoden einen Prozess zu schliessen oder anzuhalten
  5.2 Prozesse beenden mit der WMI-Klasse win32_process
      Beispiele: Beenden eines Prozesses mit der TerminateMethode
      Beispiel: Beenden eines Prozesses mit Get-WmiObject

6 Monitoring von Prozessen
  6.1  Prozessmonitoring mit  Get-Process (.Net-Klasse System.Diagnostics.Process)
  6.2 .NET-Klasse System.Management.ManagementEventWatcher
  6.3  cmdlet Register-WMIEvent (mit Beispiel)
  6.4  Prozesslisten vergleichen

7 DLLs (Module) eines Prozesses bestimmen (mit Beispiel)


1 Überblick

Prozesse lokal und remote auf einem oder mehreren Rechnern zu verwalten, zu überwachen, zu starten, zu stoppen und zu erforschen ist der Gegenstand dieses Kapitels.

In der Powershell 2.0 stehen für diese Aufgaben folgende cmdlets bereit:

Cmdlet

Alias

Synopsis

Get-Process
 

gps, ps

Ruft die Prozesse ab, die auf dem lokalen Computer oder einem Remotecomputer ausgeführt werden.

Start-Process

 

PSCX\Start-Process

saps, start

Native-Powershell:
Startet einen oder mehrere Prozesse auf dem lokalen Computer.

Community-Extensions:
Starts a new process.
(local oder remote)

Stop-Process

spps,kill

 

Wait-Process

 

Wartet, bis die Prozesse beendet wurden, bevor weitere Eingaben angenommen werden

Debug-Process

 

Debuggt einen oder mehr Prozesse, die auf dem lokalen Computer ausgeführt werden.

Get-WmiObject

GWMI

über die WMI-Klasse Win32_Process können Prozesse abgefragt werden. Mit den Eigenschaften create und terminate können Prozesse gestartet und beendet werden

Invoke-WmiMethod

IWMI

eignet sich, um Eigenschaften von WMI-Klassen aufzurufen. z.B. Create und Terminate der WMI-Klasse Win32_Process


Beispiel 1: Ermitteln der Aliase von Stop-Process

Get-Alias -definition Stop-Process
#Ausgabe

CommandType     Name     
-----------     ----
Alias           kill -> Stop-Process
Alias           spps -> Stop-Process

Hat man die CommunityExtensions (siehe Kapitel ■ My Powershell) installiert, so steht das cmdlet Start-Process mit Remotefähigkeit zur Verfügung.

 

2 Lokal laufende Prozesse aufrufen

Die aktuell laufenden Prozesse eines Systems lassen sich sehr einfach mit dem cmdlet "Get-Process" ermitteln. Die eigentliche Herausforderung besteht eher in der geeigneten Auswahl und passenden Formatierung der ermittelten Daten.

Beispiel 1: laufende Prozesse ermitteln und mit Select-Object ausgeben

Get-Process | Format-Table Name,Starttime -Auto
#[System.Diagnostics.Process]::GetProcesses() | Format-Table Name,Starttime -Auto
#gekürzte Ausgabe

Name                  
StartTime
----                   ---------
rdpclip                22.02.2010 10:22:12
conhost                22.02.2010 10:21:10
...                    ...
csrss                  22.02.2010 10:21:29
svchost                22.02.2010 10:21:02

 
Beispiel 2: laufende Prozesse  ermitteln und das Ergebnis mit dem Formatoperator formatieren

#Hier hat man schon etwas mehr Möglichkeiten über den Formatoperator die einzelnen Spalten zu formatieren. 

Get-Process | ForEach {"{0,-20} `t {1:d}" -f $_.Name,$_.StartTime}
#gekürzte Ausgabe

cmd         
    05.03.2010
conhost          22.02.2010
...              ...
csrss            22.02.2010


Beispiel 3:  laufende Prozesse eines Systems ermitteln und das Ergebnis mit dem Formatoperator, sowie Format-Table formatieren

#Hier hat man die meisten Möglichkeiten der Formatierung. Neben dem Formatoperator zur Wertformatierung kann man auch die Spaltenüberschriften, die Spaltenbreiten sowie die Ausrichtung der Spalten bestimmen

Set-StrictMode -Version "2.0"
Clear-Host

 
Get-Process  | Format-Table `
    @{Label="Prozessname";
      Expression={"{0}" -f ($_.Name)}
      Width=15
      Align="Left"
     },    

     @{Label="Startzeit";
      #g steht für Kombination aus Shortdate und Shorttime
      Expression={"{0:g}" -f ($_.StartTime)}  
      Align="Left"
      }
# Ausgabe gekürzt

Prozessname     Startzeit
-----------     ---------
cmd             05.03.2010 10:49
conhost         08.03.2010 13:23
conhost         22.02.2010 10:21
conhost         05.03.2010 11:46
conhost         05.03.2010 10:49

siehe Kapitel String- und Textanalysen -> "Formatierung des Outputs" -> "Formatierte Tabellen"

Beispiel 4: Wieviele und welche Prozesse laufen momentan lokal

Set-StrictMode -Version "2.0"
Clear-Host

$Query = "Select * From Win32_Process"
#$Query = "Select * From Win32_Process where Caption !='SvcHost.exe'"

$Threshhold = 1

$Processes = Get-WmiObject -Query $Query       
$ProcessCount = $Processes | Group-Object Caption | Sort count -Descending
$SortedCounts = $ProcessCount| Where {$_.Count -gt $Threshhold} | Format-Table Count,Name -auto
$SortedCounts
#mögliche Ausgabe

Count Name       
----- ----       
   12 svchost.exe
    5 notepad.exe
    2 csrss.exe  
    2 nvvsvc.exe

Mit Get-Process kann man diese Information auch von RemoteRechnern abfragen.

siehe 3.1 Prozessabfrage mittels .Net und Powershell cmdlet -> Beispiel 3

Beispiel 5a: Vorder- und Hintergrundprozesse starten
In Windows gibt es Prozesse, die am Bilschirm zu sehen sind (eventuell auch minimiert) und es gibt gänzlich vor dem Anwender versteckte Processe.

Set-StrictMode -Version "2.0"
Clear-Host

#Notepad (Editor) als Vordergrundprozess starten
Start-Process notepad 

#Notepad (Editor) als Hintergrundprozess starten
Start-Process notepad -WindowStyle Hidden

#NotepadProzesse abfragen
Get-Process Notepad
m#ögliche Ausgabe

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
     61       7     1108       3684    69     0,03     40 notepad
      3       3      512       1196    31     0,03   7276 notepad 

An der default Ausgabe von "get-process" erkennt man als noch nicht den Unterschied zwischen Vorder- und Hintergrundprozessen

Erkennbar sind die Prozesse natürlich im Taskmanager (hier: Windows 8)


Beispiel 5b: Vorder- und Hintergrundprozesse mit Powershell unterscheiden

Set-StrictMode -Version "2.0"
Clear-Host

Function Main{
 $Processes = Get-Process  
 $Processes | Format-Table Handles,NPM,PM,WS,VM,CPU,Id,ProcessName,
@{
  Label="IsBackGroundProcess"
  Expression={Test-IsBackground $_}
   } -AutoSize

} #Main

Function Test-IsBackground{
 Param($Process)
  If ($($Process.MainWindowTitle) -eq ""){
   Return $True
  }Else{
   Return $False
  }
}

Main
#mögliche Ausgabe (gekürzt)

Handles        WS         VM   Id ProcessName                 IsBackGroundProcess
-------        --         --   -- -----------                 -------------------
     92   5013504   62603264 2308 AdminService                               True
    166   9535488   99627008 2144 AppleMobileDeviceService                   True
   ...
    262  31760384  168235008 4868 filezilla                                 False
    884 516128768  903258112 6912 firefox                                   False
    198  10575872   95911936 2968 FlashPlayerPlugin_12_0_0_77                True
   ...

Ich frage in diesem Beispiel jeden Prozess nach dem Title seines HauptFensters (MainWindowTitle) ab. Ist dies "", so handelt es sich um einen Backgroundprocess
 

3 Remote laufende Prozesse aufrufen

Die zugrunde liegende .Net Klasse von Get-Process kann auch remote verwendet werden. Allerdings fehlen dem gewonnenen Prozessobjekt eines Remoterechners der Inhalt einiger Eigenschaften wie beispielsweise der Inhalt der Eigenschaft „Starttime“

 

3.1 Prozessabfrage mittels .Net und Powershell cmdlet

Beispiel 1: RemoteProzesse emitteln und das Ergebnis mit dem Formatoperator formatieren

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName="."
Get-Process –computername $ComputerName | Select -First 5 | `
        ForEach {"{0,-12} `t {1:d} `t {2}" -f $_.Name,$_.Handles, $_.WorkingSet}

#gleichwertig.
<#
 [System.Diagnostics.Process]::GetProcesses($ComputerName) | Sort | Select -First 5 |
       ForEach {"{0,-12} `t {1:d} `t {2}" -f $_.Name,$_.Handles, $_.WorkingSet}
       #>
#mögliche Ausgabe

AcroRd32          217      3424256
AcroRd32          207      1605632
armsvc            71       131072
avgnt             197      3321856
avguard           250      1441792

 
Beispiel 2: Hinzufügen einer berechneten Spalte (Laufzeit eines Prozesses in Minuten)

Set-StrictMode -Version "2.0"
Clear-Host

#Definition der DataTable
$DataTable=New-Object System.Data.DataTable("Processes")

#Definition der Spalten
$Column0 = New-Object System.Data.DataColumn("Name")
$Column1 = New-Object System.Data.DataColumn("StartTime")
$Column2 = New-Object System.Data.DataColumn("UsedTimeInMins") #selfdefined
$DataTable.Columns.Add($Column0)
$DataTable.Columns.Add($Column1)
$DataTable.Columns.Add($Column2)

#DataTable füllen
$Processes = Get-Process
$Processes | ForEach {
  If($_.StartTime -ne $Null){
     $Usedtime = $((Get-Date)  - $_.StartTime).TotalMinutes
     $UsedTime = [Math]::Round($UsedTime,0)
     $DataTable.Rows.Add($($_.Name), $($_.StartTime).ToString('g'), $Usedtime) | Out-null
  }Else{
     #$DataTable.Rows.Add($($_.Name), "0" , "0") | Out-null
  }
}

$DataTable |  Format-Table Name,StartTime,UsedtimeInMins -auto
#$DataTable  |  Export-Csv -path "c:\temp\myprocesses.txt"
#mögliche Ausgabe

Name                           StartTime        UsedTimeInMins
----                           ---------        --------------
AcroRd32                       08.03.2013 20:16 256           
AcroRd32                       08.03.2013 20:16 256           
avgnt                          08.03.2013 19:10 322           
conhost                        08.03.2013 20:26 245

Ich arbeite hier mit einer DataTable (siehe Kapitel 2 Disconnected Classes), was den Code aber viel flexibler macht, sobald die gewonnen Daten aus Get-Process nicht einfach nur ausgegeben, sondern weiterverarbeitet werden.

Beispiel 3: Wieviele Prozesse und welche Prozesse laufen momentan auf einem Remoterechner

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = "AcerNB"
$Threshhold = 1

$processes = Get-Process –Computername $ComputerName   
$ProcessCount = $Processes | Group-Object ProcessName | Sort count -Descending
$SortedCounts = $ProcessCount| Where {$_.Count -gt $Threshhold} | Format-Table Count,Name -auto
$SortedCounts
#Ausgabe

Count Name   
----- ----   
   12 svchost
    5 notepad
    2 csrss  
    2 nvvsvc

 

 

3.2 Prozessabfrage mittels WMI

Als Alternative zur Bestimmung aller Eigenschaften von der Prozesse von Remoterechnern bietet sich WMI an

 

Beispiel 1: remote Prozesse ermitteln und das Ergebnis mit dem Formatoperator formatieren

Set-StrictMode -Version "2.0"
Clear-Host

$Query ="Select Name,Creationdate,WorkingsetSize from Win32_Process where Name='Winlogon.exe'"
$Processes=Get-WmiObject -query $Query -computername "."

$Processes | ForEach{
  if($_.CreationDate -ne $Null){
     "{0,-20}  {1,25:g}  {2,23}"   -f $_.Name, $_.ConvertToDateTime($_.Creationdate),$_.WorkingSetSize
  }else{
     "{0,-20}  {1,25:g}  {2,23}"   -f $_.name, 0,$_.WorkingSetSize
  }
}
#mögliche Ausgabe

winlogon.exe                   09.03.2013 11:46                  7266304

Bei der Verwendung von WMI-Klassen sollte man zwei Dinge beachten:

a) Die Namen der Eigenschaften und Methoden der .Net Klasse Prozess MSDN: Process Properties stimmen nicht oder nur zufällig mit den Namen der Eigenschaften und Methoden der WMI-Klasse Win32-Process MSDN: Win32_Process Class überein

b) das Zeit bzw. das Datumsformat unter WMI ist relativ kryptisch. Eine einfache Methode, ein gewohntes Format zu erhalten geht über ConvertToDateTime (s.o.). Mit dem Formatoperator -f kann das erhaltene Objekt beliebig umformatiert werden.

Unter "Formatierung des Outputs" -> "Formatierte Tabellen" gehe ich näher auf die Möglichkeiten an, den Output zu formatieren, dort sind auch die Ausdrücke wie {1,25:g} erklärt. "g" gibt dem Ausdruck  übrigens die Formatierung "General date/time pattern (short time)MSDN: Standard DateTime Format Strings
 

3.3 RemotePowershellSession

siehe: Powershell Remote

Eine weitere -indirekte- Methode Prozesse remote zu überwachen, bringt Powershell V2.0 mit der Möglichkeit PS-Skripte komplett remote auszuführen mit.
Dazu muss auf dem Zielrechner einmalig das PSremoting mit

Enable-PSRemoting

zugelassen werden, wodurch dort der RMListener gestartet und die WindowsFirewall angepasst wird, sofern man die beiden folgenden Sicherheitsabfragen positiv bestätigt.

Auf den RemoteRechner -bei mir DC1- kann man nun vom lokalen Rechner aus eine PowershellSession öffnen, in der man uneingeschränkt arbeiten kann.

Enter-PSSession DC1 #etsn ist Alias von Enter-PSSession
[DC1]: PS C:\Users\User1\Documents> Get-Process  #<-- Man beachte [DC1], dort wird der Befehl ausgeführt
#Ausgabe des RemoteRechners DC1 - gekürzt

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    276      39    13540      15136   106     1,50   1468 certsrv
     20       4     2140       2616    38     0,05   3124 cmd
     30       4      736       2212    25     0,00   2176 conhost

[DC1]: PS C:\Users\User1\Documents> Exit-PSSession  #exsn ist Alias von Exit-PSSession
PS C:\>_  #<- zurück auf der lokalen Maschine

Genauer auf das PSRemoting gehe ich im Kapitel "Powershell Remote" ein
 

4 Ausgewählte Prozesse analysieren und bearbeiten

4.1 ein Prozessobjekt erstellen

Um einen bestimmten Prozess genauer anzusehen, zu verändern (z.B. Stoppen, Anhalten) etc. braucht man zuerst eine Objekt, dass den gewünschten Prozess repräsentiert (= Instanz).
 

Beispiel 1: Ein Prozessobjekt mit .Net [System.Diagnostics.Process] oder mit cmdlet "Get-Process" erstellen

Set-StrictMode -Version "2.0"
Clear-Host

#Local
$LocalProcess = [System.Diagnostics.Process]::GetProcessesByName("notepad")

#Remote auf "DC1"
$RemoteProcess = [System.Diagnostics.Process]::GetProcessesByName("notepad","DC1")
$RemoteProcess = Get-Process –computername "DC1" notepad.exe

$LocalProcess
#$RemoteProcess
#Ausgabe

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
     63       7     1432       5204    74     0,08   2336 notepad
     63       7     1432       5232    74     0,06   3796 notepad
     65       7     1468       5716    74     0,38   3908 notepad

Je nachdem, ob man der überladenen Methode GetProcessByName einen oder zwei Parameter übergibt, ist die Prozessabfrage lokal oder remote


MSDN: Process.GetProcessesByName Method

 

Beispiel 2a: Prozesse mit der WMI-Klasse Win32_Process auslesen mit einer Datatable als Datenstruktur (GetOwner)

Wem dieses Beispiel zu lange ist, kann das Beispiel 2b verwenden, welches exakt denselben OutPut liefert.

Set-StrictMode -Version "2.0"
Clear-Host

$Properties = @("Caption","Priority","VirtualSize","Owner","CreationDate")
#Owner und CreationDate werden später gesondert bearbeitet, da kein Standard

#Anlage der DataTabelle mit Spalten für jede Property in Properties
$DataTable = New-Object System.Data.DataTable("Processes")
$Properties | foreach {
  $Column = New-Object System.Data.DataColumn($_)
  $DataTable.Columns.Add($Column)
  }


#WMI-Abfrage
$Query = "Select * From Win32_Process"
$Processes = Get-WmiObject -query $Query

 
#Eigenschaften der Prozesse in Datatable eintragen
Foreach($Process in $Processes){
  $PropertiesInRow =@()
  Foreach($Property in $Properties){
      If($Property -eq "Owner"){
        $PropertiesInRow += [String]$Process.Getowner().User
      }ElseIf($Property -eq "CreationDate"){
        $CreationDate= $Process.CreationDate
        Try{
          $ConvertedCreationDate = $Process.ConvertToDateTime($CreationDate)
          $PropertiesInRow += $ConvertedCreationDate
        }Catch{} #falls CreationDate leer ist z.B. System Idle Process
     }else{
        $PropertiesInRow += [String]$Process.$Property
     }#Else / If
  }#Foreach($Property in $Properties){

  $DataTable.Rows.Add($PropertiesInRow) | Out-Null
}#Foreach($Process in $Processes){

#DataView erzeugen
$DataView = New-Object System.Data.DataView($DataTable)

#DataView Sortieren
$DataView.Sort = "Caption DESC"

 
#DataView Filtern
$Filter = "(Owner Like 'System') And (Priority > 8)"
$DataView.RowFilter = $Filter

 
#DataView ausgeben
$DataView | Format-Table -Auto
#mögliche Ausgabe

Caption      Priority VirtualSize Owner  CreationDate       
-------      -------- ----------- -----  ------------       
winlogon.exe 13       59457536    SYSTEM 10.03.2013 17:58:56
wininit.exe  13       50483200    SYSTEM 10.03.2013 17:58:56
smss.exe     11       5169152     SYSTEM 10.03.2013 17:58:50
services.exe 9        44060672    SYSTEM 10.03.2013 17:58:56
lsass.exe    9        43630592    SYSTEM 10.03.2013 17:58:56
csrss.exe    13       50532352    SYSTEM 10.03.2013 17:58:55
csrss.exe    13       59015168    SYSTEM 10.03.2013 17:58:56

MSDN: Win32_Process Class

Dieses Beispiel liest alle laufenden Prozesse mit der WMI-Klasse aus. Zusätzlich zu den Standardeigenschaften kommen noch die Eigenschaften "Owner" und "CreationDate" hinzu, die ich erst im Code erzeuge. Als Datenstruktur nutze ich eine Datatable. Dies mache ich gerne, wenn wie hier nach der Erhebung die Daten noch verändert werden. Mit Datatables bleibt die Struktur auch in komplexeren Code übersichtlich. Näheres zu Datatables unter Datenzugriff über ADO.Net -> 2 Disconnected Classes

 

Beispiel 2b: Prozesse mit der WMI-Klasse Win32_Process auslesen

Set-StrictMode -Version "2.0"
Clear-Host

$Query = "Select * From Win32_Process"
#$Query = "Select * From Win32_Process where Caption !='SvcHost.exe'"

Get-WmiObject -Query $Query | select Caption, Priority, VirtualSize,             
@{N="Owner"; E={$_.GetOwner().User}},
@{N="CreationDate"; E={$_.ConvertToDateTime($_.CreationDate)}} | `
   Format-Table -AutoSize 

Die Ausgabe entspricht exakt der Ausgabe des Beispiels 2a

 

Beispiel 3: Bestimmen des Owner eines Prozesses

Auch wenn ich in Beispiel 2 schon den Weg gezeigt habe, den Owner von Prozessen auszulesen, hier nochmal zwei Codebeispiele dies bei einem ganz bestimmten Prozess zu tun

Set-StrictMode -Version "2.0"
Clear-Host

$ProcessName = "Notepad.exe"
$Query = "Select * from Win32_Process where Name = 'notepad.exe'"
$Processes = @(Get-WmiObject -query $Query)

If($Processes.Count -gt 0){
  $Processes | Foreach{
    "Owner des Prozesses mit der ID {0} ist: {1} " -f $_.ProcessID,($_.GetOwner()).user
     }
}Else{
  Write "Kein Process $ProcessName vorhanden"
}
#mögliche Ausgabe

Owner des Prozesses mit der ID 3504 ist: KarlNapf
Owner des Prozesses mit der ID 292 ist: KarlNapf

 

Set-StrictMode -Version "2.0"
Clear-Host

$IDs = (Get-Process -Name Notepad) | Foreach ID
$IDs | Foreach{
     Get-CimInstance Win32_Process -Filter "ProcessID = `
        $_" | Invoke-CimMethod -Name GetOwner | ft user -HideTableHeaders
}
#mögliche Ausgabe

Karl
KarlNapf

 

4.2 Prozesse neu starten

4.2.1 Verwendung von start-Process aus den Communityextensions

Powershell V2.0 enthält das cmdlet start-process um Prozesse starten zu können. Die Communityextensions (siehe Kapitel Installation) bringen ein zusätzliches cmdlet zum Starten von Prozessen zusätzlich mit Remotefähigkeit mit. Leider wurde auch dieses cmdlet Start-Process genannt.

Ob man nun ein -oder beide cmdlets installiert hat, lässt sich  mittels Get-Help ermitteln

Get-Help Start-Process
#mögliche Ausgabe, wenn die Communityextensions installiert sind

Name                              Category  Synopsis
----                              --------  --------
Start-Process                     Cmdlet    PSCX Cmdlet: Starts a new process.
Start-Process                     Cmdlet    Startet einen oder mehrere Prozesse auf dem lokalen Computer.


Wenn man die Communityextensions nutzt, würde ich um mögliche Versionskonflikte zu vermeiden beim Skripten die cmdlets inklusive den Namespaces verwenden. Dann erhält man wenigstens eine aussagekräftigere Fehlermeldung, wenn der PSCX-Namespace fehlt.

Microsoft.PowerShell.Management\Start-Process  #natives cmdlet
#  entspricht: [system.diagnostics.process]::start("<ProzssName")

PSCX\Start-Process #hinzuinstalliertes cmdlet der CommunityExtensions

 

Get-Help PSCX\Start-Process
#Ausgabe gekürzt
PS C:\Windows\System32\WindowsPowerShell\v1.0> get-help PSCX\Start-Process

NAME
    Start-Process

ÜBERSICHT
    PSCX Cmdlet: Starts a new process.  #!!!!hier erkennt man die PSCX-Herkunft

 

 

4.2.2 Verwendung von .Net zum Starten eines Prozesses

 

Beispiel 1: Prozess neu starten mit [system.diagnostics.process]::start(<Name>)

[System.Diagnostics.Process]::Start("Notepad")
[System.Diagnostics.Process]::start("Notepad","c:\test.txt")


Beispiel 2: Prozess neu starten mit [System.Diagnostics.Process]::Start(<Name>) unter anderen Credentials

$Logon=Get-Credential #Credentials müssen eingegeben werden
[System.Diagnostics.Process]::Start("cmd.exe",$Logon.Username,$Logon.Password,"myMachine")

 

4.2.3 Verwendung von Start-Process zum Starten eines Prozesses

 

Beispiel 1: Prozess einfach neu starten mit cmdlet start-process (native)

Start-Process notepad C:\test.txt
#oder auch nur
notepad c:\test.txt

 

Beispiel 2: Prozess neu starten mit cmdlet start-process (native) mit den Parametern -wait und -WindowStyle

Set-StrictMode -Version "2.0"
Clear-Host

Start-Process -wait Notepad C:\test.txt -WindowStyle Maximized
Write-Host "Notepad wurde beendet"

-wait: Skript wartet bis der Notepad Prozess beendet wird. Write-Host wird erst nach dem Beenden von Notepad ausgeführt
-WindowsStyle: Gültige Werte sind "Normal", "Hidden", "Minimized", "Maximized"  
  #siehe Get-Help Start-Process -detailed


Beispiel 3: Ausdrucken einer Datei aus Powershell

Aus der Powershell Onlinehilfe zu Start-Process

Dieser Befehl startet einen Prozess, der die Datei "C:\PS-#Test\MyFile.txt" druckt.

Start-Process myfile.txt -workingdirectory "C:\PS-Test" -verb Print

Interessant ist Parameter -Verb, über den dies OnlineHilfe (etwas spärlich) aussagt

-Verb <string>
  Gibt ein Verb an, das beim Starten des Prozesses verwendet werden soll, z. B. "Edit", "Open" oder "Print".

Eine erweiterte Hilfe findet man unter Technet: Start-Process

The following table shows the verbs for some common process file types.

Extension

type Verbs

.cmd

Edit, Open, Print, Runas

.exe

Open, RunAs

.txt

Open, Print, PrintTo

.wav

Open, Play


Beispiel 3a: Öffnen der Hostsdatei

Start-Process notepad.exe -ArgumentList C:\Windows\\System32\drivers\etc\hosts -Verb RunAs


Beispiel 4: Enumeration der Verben von *.doc Dateien

Um die Verben weiterer Dateitypen wie Worddokumente zu erhalten, benötigt man die [System.Diagnostics.ProcessStartInfo] - Klasse  Technet: Start-Process -> Example 6

Set-StrictMode -Version "2.0"
Clear-Host

$ProcessStartInfo = New-Object System.Diagnostics.ProcessStartInfo -args text.doc
$ProcessStartInfo.Verbs
#Ausgabe

Edit
Open
OpenAsReadOnly
Print
Printto
Save As

 

Beispiel 5: Prozess neu starten mit cmdlet Start-Process (native) mit dem Parametern -verb

Wobei dann auch nicht alle Verben wirklich verwendet werden können

Set-StrictMode -Version "2.0"
Clear-Host

$Path = "c:\temp\test.doc"

Start-Process "C:\Programme\Microsoft Office\OFFICE11\winword.exe" $Path -verb OpenAsReadonly
# bringt eine Fehlermeldung

Start-Process "C:\Programme\Microsoft Office\OFFICE11\winword.exe" $Path -verb Open
# öffnet die Worddatei

Falls jemand weitere Informationen und Einsatzmöglichkeiten über die verbs findet, würde ich mich sehr über Informationen freuen (Kontakt: siehe Home)

 

4.2.4 Verwendung von WMI zum Starten eines Prozesses (SchemaQuery)

MSDN: Create Method of the Win32_Process Class

Um WMI-Methoden aufzurufen, gibt es wie so oft mehrere Ansätze.  Ich will hier den Ansatz über die .Net-Klasse [System.Management.ManagementClass] mit dem zugehörigen Powershell TypeAccelerator [WmiClass] zeigen und danach über das cmdlet Invoke-WMIMethod mit dessen Alias iwmi.
Mit [WMIClass] erstellt man eine Instanz der Klasse selbst und wendet darauf eine Statische Methode wie "create" an. Kapitel WMI Abschnitt
2.6.2 Mit SchemaQueries neue Instanzen einer Klasse erstellen


Beispiel 1 : einen RobocopyBefehl remote mit der Create-Methode von Win32_Process aufrufen

Set-StrictMode -Version "2.0"
Clear-Host

$Command="RoboCopy C:\temp\ C:\temp1 /s"
$RemoteServer="DC1"
$MC=[WmiClass] "\\$RemoteServer\ROOT\cimv2:Win32_Process"

$StartupOptions = [WmiClass] "Win32_ProcessStartup"
$StartupOptions.PsBase.Properties["ShowWindow"].Value=0

$MC.Create($command)

- [WmiClass] ist der Shortcut von [System.Management.ManagementClass]

- Im Kapitel Filesystem -> 2.1.2.4 Komprimieren und Dekomprimieren von Dateien und Ordnern findet ihr ein Beispiel für die compress.exe

- Durch die das Setzen der StartupOption "ShowWindow=0" flackert kein Commandlinefenster auf
  weitere Optionen unter MSDN:  Win32_ProcessStartup class

- Möchte man  die Robocopy-Robustheit in Powershell nachbauen, sind diese Links vielleicht interessant:
blog.usepowershell.com - Using the Sync Framework from PowerShell

The ProwerShell Guy - PowerShell and Robocopy Part 4


Beispiel 2: Weitere Optionen von Win32_Process ermitteln

$Process = [WmiClass] "Win32_Process"
$Process.PsBase.Scope.Options | Get-Member
#Ausgabe gekürzt
   TypeName: System.Management.ConnectionOptions

Name             MemberType Definition
----             ---------- ----------
Authentication   Property   System.Management.AuthenticationLevel Authentication {get;set;}
EnablePrivileges Property   System.Boolean EnablePrivileges {get;set;}
Impersonation    Property   System.Management.ImpersonationLevel Impersonation {get;set;}
Password         Property   System.String Password {set;}
SecurePassword   Property   System.Security.SecureString SecurePassword {set;}
Timeout          Property   System.TimeSpan Timeout {get;set;}
Username         Property   System.String Username {get;set;}


Beispiel 3: Robocopy mit weiteren Optionen wie Username, Passwort, Impersonationlevel aufrufen

Set-StrictMode -Version "2.0"
Clear-Host

$Cmd="Robocopy C:\temp\ C:\temp1 /s"
$Server="Dc1" # für die lokale Maschine "."
$User="Dom1\User1"
$Password="HollaDieWaldFee1"
$Process = [WMIClass]"\\$server\ROOT\cimv2:Win32_Process"
$Process.PsBase.Scope.Options.UserName=$User
$Process.PsBase.Scope.Options.Password=$Password
$Process.PsBase.Scope.Options.Impersonation = [System.Management.ImpersonationLevel]::Impersonate
$Process.PsBase.Scope.Options.Authentication = [System.Management.AuthenticationLevel]::PacketPrivacy
$Process.Create($Cmd)

# ProcessId and ReturnValue

$Process.ProcessId
$Process.ReturnValue

Alternativ könnte man sich auch unter den geänderten Credentials ein Laufwerk mappen und darüber die Kopieraktion ausführen

Filesystem: 2.1.2.6 Ausführen von Operationen im FileSystem unter anderen Credentials


Beispiel 4: Cmdlet Invoke-WmiMethod (Alias: IWMI)

Sehr elegant lässt sich das Aufrufen eines Skripts auf einem Remotecomputer auch mit dem cmdlet Invoke-Wmi-Method lösen:

Set-StrictMode -Version "2.0"
Clear-Host

$Computer = "DC1"
Invoke-WmiMethod -path Win32_Process -name Create -argumentlist "Robocopy c:\temp C:\temp1 /S" -computer $Computer

 

4.2.5 Starten von mehreren Prozessen im Hintergrund

Mehrere Prozesse möglichst rasch nacheinander so zu starten, dass der nächste Prozess schon gestartet wurde, bevor der vorige beendet war, hat man zu Batchzeiten rudimentär mit den "Start"-Befehl erledigt.
Unter Powershell sind dafür die Job-cmdlets zuständig:

 

Beispiel 1: Anzeige der Job-cmdlets

Get-Command *-job | Format-Table CommandType,Name -auto
#Ausgabe

CommandType     Name
-----------     ----
Cmdlet          Get-Job
Cmdlet          Receive-Job
Cmdlet          Remove-Job
Cmdlet          Start-Job
Cmdlet          Stop-Job
Cmdlet          Wait-Job


Beispiel 2: Starten mehrerer Prozesse als Job

Set-StrictMode -Version "2.0"
Clear-Host

For($Counter=1;$Counter -le 10; $Counter++){
  Start-Job -name $Counter -scriptblock {Notepad c:\temp\big150000.txt}
}

"Das Skript ist fertig, obwohl noch nicht alle NotepadProzesse fertig sind"
#Ausgabe

Das Skript ist fertig, obwohl noch nicht alle NotepadProzesse fertig sind

Man bekommt die "Fertig-Meldung" schon, während die Notepad-Prozesse noch starten

 

4.2.6 Läuft mindestens eine Instanz eines Prozesses

 

Beispiel 1: Läuft ein bestimmter Prozess

Set-StrictMode -Version "2.0"
Clear-Host

$ServiceName = "Notepad"
If (@([System.Diagnostics.Process]::GetProcessesByName($ServiceName)).count -gt 0) {
  "eine oder mehrere Instanzen von $ServiceName sind vorhanden"
}Else{
  "keine Instanz von $ServiceName vorhanden"
 }
#mögliche Ausgabe

keine Instanz von Notepad vorhanden

 

5 Schließen von Prozessen

5.1 Prozesse beenden mit .Net Methoden

Beispiel 1: einige Methoden einen Prozess zu schliessen oder anzuhalten

MSDN: Process Methoden
  

A) Die Kill()-Methode beendet alle Prozesse

Set-StrictMode -Version "2.0"
Clear-Host

$ProcessName = "Notepad"
$ErrorActionPreference = "SilentlyContinue"
$Processes = Get-Process Notepad

If ($?) {
     $Processes.Kill()
     "$ProcessName beendet"
  }else{
  "$Processname nicht vorhanden"
  }

Durch "$ErrorActionPreference = "SilentlyContinue" werden Fehler nicht angezeigt

$? ist die ErrorVariable. Diese ist $True, wenn kein Fehler aufgetreten ist.

$Processes = Get-Process notepad
$Processes | foreach {Stop-Process ($_.Id)}

 

$Processes = Get-Process Notepad
$Processes | ForEach {$_.Kill()}  #MSDN: Hält den zugeordneten Prozess sofort an.

 

$Processes = Get-Process Notepad
$Processes | foreach {$_.Close()}

Close: Gibt alle dieser Komponente zugeordneten Ressourcen frei, schließt die Prozesse aber nicht

 

$Processes = Get-Process Notepad
$Processes | foreach {$_.CloseMainWindow()}

#MSDN: Schließt einen Prozess mit einer Benutzeroberfläche, indem eine Meldung zum Schließen an das Hauptfenster gesendet wird.

Um an eine Anwendung vor dem Schliessen noch eine bestimmte Tastenkombination zu senden, bietet sich das "Windows Automation Snapin for Powershell" an. Codeplex: Windows Automation Snapin for PowerShell

 

5.2 Prozesse beenden mit der WMI-Klasse "Win32_Process"

Technet - ScriptingGuy!:  Use PowerShell and WMI to Terminate Multiple Processes

 

Beispiel1 : Beenden eines Prozesses mit der TerminateMethode

Terminate Method of the Win32_Process Class

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = "."  # für die lokale Maschine "."
$Query = "SELECT * FROM Win32_Process WHERE Name = 'notepad.exe'"
$Processes = Get-WmiObject -query $Query -computername $ComputerName

$ErrorActionPreference = "SilentlyContinue"
ForEach($Process in $Processes){
   $ReturnValue = $($Process.Terminate()).ReturnValue  #Terminate entspricht kill
   If ($ReturnValue -eq 0){
      "Notepad erfolgreich beendet"
      }
   If(!$?){
    "Kein Notepad-Process vorhanden"
   }
}
$ErrorActionPreference = "Continue" #Defaultwert

# zum evtl. Troubleshooting helfen die im MSDN-Artikel genannten Return Values

 

Beispiel 2: Beenden eines Prozesses mit Get-WmiObject

Ein schönes Beispiel mit "Invoke-WMIMethod"  Prozesse zu beenden, habe ich bei den ScriptingGuys gefunden

#Skript aus blogs.technet.com/heyscriptingguy/archive/2009/12/10/hey-scripting-guy-december-10-2009.aspx

Set-StrictMode -Version "2.0"
Clear-Host

Get-WmiObject -Class Win32_Process -Filter "Name = 'notepad.exe'" | ForEach-Object {
    Invoke-WmiMethod -Path $_.__Path –Name Terminate
    }

 

6 Monitoring von Prozessen

Gelegentlich möchte man auf einem Rechner überwachen, ob ein bestimmter Prozess läuft und wann dieser gestoppt wurde. Dazu stehen einem aus .Net die Klasse [System.Management.ManagementEventWatcher] und aus WMI die Klasse SWBEMServices MSDN: SWbemServices.ExecNotificationQueryAsync Method zur Verfügung. Die WMI-Klasse wird im Kapitel WMI, dort in Abschnitt 2.5 behandelt.
 

6.1 Prozessmonitoring mit Get-Process (.Net-Klasse System.Diagnostics.Process)

Technet - Scriptingguys: How Can I Use Windows PowerShell to Be Notified When an Application Terminates?

Das Skript "beobachtet" den Prozess Notepad, wenn er vorhanden ist

Set-StrictMode -Version "2.0"
Clear-Host

$ProcessName="Notepad"
$ComputerName="."

if (Get-Process $ProcessName -ComputerName $ComputerName -EA 0) {
 Do{
   $Notepad = Get-Process $ProcessName -ComputerName $ComputerName
   $Notepad.WaitForExit()
   "Notepad wurde am {0} beendet" -f $(Get-Date)
   break
   } while (0 -lt 1)
}else{
 "Der Prozess {0} läuft nicht auf diesem System"
}


 

6.2 .Net-Klasse System.Management.ManagementEventWatcher

Flexibler als mit System.Diagnostics.Process bzw. get-process ist man mit der Klasse ManagementEventWatcher die .Net zum Monitoring vorsieht

MSDN: __InstanceDeletionEvent Class
MSDN: __InstanceCreationEvent Class

Das folgende Skript protokolliert fortlaufend alle Prozesse, die geschlossen werden

Anleitung:

Skript muss gestartet werden und laufen
http://blogs.technet.com/heyscriptingguy/archive/2007/03/26/how-can-i-use-windows-powershell-to-be-notified-when-an-application-terminates.aspx

$a = 0

$timespan = New-Object System.TimeSpan(0,0,10) # gibt in Stunden,Minuten,Sekunden an, wie oft der Monitor läuft
$scope = New-Object System.Management.ManagementScope("\\.\root\cimV2") #. steht für den lokalen Rechner
$query = New-Object System.Management.WQLEventQuery `
    ("__InstancedeletionEvent",$timespan, "TargetInstance ISA 'Win32_Process'" )
$watcher = New-Object System.Management.ManagementEventWatcher($scope,$query)

do
    {
        $b = $watcher.WaitForNextEvent()
        $b.TargetInstance.Name
        $b.TargetInstance.caption     # Eigenschaftenn der WMI-Klasse: win32_process
        $b.TargetInstance.executablepath
        $b.TargetInstance.creationdate #Datum im WMI-Format
        ([WMI]'').ConvertToDateTime($b.TargetInstance.creationdate) #Datum im Langformat
        "Eventdatum: $(get-date)"
    }
while ($a -ne 1)
#Ausgabe

calc.exe
calc.exe
C:\Windows\system32\calc.exe
20100315154406.481302+060

Montag, 15. März 2010 15:44:06
Eventdatum 03/15/2010 15:44:09

Neben der Klasse __InstanceDeletionEvent gibt es noch das Gegenstück __InstanceCreationEvent um Erstellung von Prozessen zu beobachten.

 

6.3 cmdlet Register-WMIEvent

Eine andere, sehr elegante Möglichkeit den Start oder das Ende von Prozessen zu überwachen bietet Register-WMIEvent

Technet: WMI Event Monitoring

Register-WMIEvent -query "Select * From __InstanceCreationEvent `
  within 3 Where TargetInstance ISA 'Win32_Process'" -messageData "Prozess" -sourceIdentifier "SourceIdentifier1"

Dadurch werden Events untet dem SourceIdentifier1 (beliebiger Name) gesammelt und können mit Get-Event ausgelesen werden

 

Get-Event –sourceIdentifier "SourceIdentifier1"
#Ausgabe

ComputerName     : 
RunspaceId       : 74868721-121e-4c91-af93-a4e7a55056b6
EventIdentifier  : 1
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  : System.Management.EventArrivedEventArgs
SourceArgs       : {System.Management.ManagementEventWatcher, System.Management.EventArrivedEventArgs}
SourceIdentifier : New Process
TimeGenerated    : 15.03.2010 16:35:33
MessageData      : A new process has started.

ComputerName     : 
RunspaceId       : 74868721-121e-4c91-af93-a4e7a55056b6
EventIdentifier  : 2
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  : System.Management.EventArrivedEventArgs
SourceArgs       : {System.Management.ManagementEventWatcher, System.Management.EventArrivedEventArgs}
SourceIdentifier : New Process
TimeGenerated    : 15.03.2010 16:35:52
MessageData      : A new process has started.

 

Den SourceIdentifier kann man auch wieder deregistrieren mit

Unregister-Event "New Process"

Alle WMI SystemKlassen sind in der MSDN hier aufgeführt: MSDN: WMI System Classes

 

6.4 Prozesslisten vergleichen

Technet: Compare-Object

Ein schönes, praxisnahes Beispiel zur Fehleranalyse auf Rechnern liefert die OnlineHilfe de cmdlets Compare-Object.

Set-StrictMode -Version "2.0"
Clear-Host

$ProcessesBefore = Get-Process
notepad
$Processes_After  = Get-Process

Compare-Object -referenceobject $Processes_Before -differenceobject $Processes_After
#Ausgabe

InputObject                              SideIndicator
-----------                              -------------
System.Diagnostics.Process (notepad)     =>


Beschreibung (siehe Technetlink Beispiel 3)
-----------
Mit diesen Befehlen werden zwei Sätze von Prozessobjekten verglichen.

Im ersten Befehl werden mit dem Cmdlet "Get-Process" die Prozesse auf dem Computer abgerufen. Diese werden in der Variablen "$processes_before" gespeichert.

Mit dem zweiten Befehl wird Editor gestartet.

Mit dem dritten Befehl wird wieder das Cmdlet "Get-Process" verwendet, und die resultierenden Prozesse werden in der Variablen "$processes_after" gespeichert.

Mit dem vierten Befehl wird das Cmdlet "Compare-Object" verwendet, um die beiden Sätze von Prozessobjekten zu vergleichen. Dabei werden die Unterschiede zwischen den Sätzen angezeigt, wozu auch die neue Instanz von Editor gehört.

 

7 DLLs (Module) eines Prozesses bestimmen

Sieht man sich die Eigenschaften und Methoden eines Prozesses an z.B. mit "get-process notepad | get-member", so findet man die Eigenschaft Modules.

#Skript, welches die von einem Prozess geladenen DLLs anzeigt

Set-StrictMode -Version "2.0"
Clear-Host

#Eine einzige(!) NotepadInstanz geöffnet halten
(Get-Process Notepad).Modules | ft -auto
#Ausgabe gekürzt

Size(K) ModuleName     FileName
------- ----------     --------
    212 notepad.exe    C:\WINDOWS\system32\notepad.exe
   1700 ntdll.dll      C:\WINDOWS\SYSTEM32\ntdll.dll
   1148 kernel32.dll   C:\WINDOWS\system32\kernel32.dll

 

Die unter Modules [System.Diagnostics.ProcessModule] zur Verfügung stehenden Eigenschaften und Methoden erhält man mit

$NotePad = Get-Process notepad
$NotePad | Foreach {$_.Modules} | Get-Member