Theorie Powershell

Inhalt

1. Teil
1.1 Einführung
1.2 Absoluter und relativer Pfad
1.3 Script-Programme starten

2. Teil
2.1 Datentypen
2.2 Input/Output
2.3 Vergleichsoperatoren
2.4 Die Selektion
2.5 Die Iteration
2.6 Try and catch
2.7 Abstraktion / Funktion / Methode / Filter
2.8 Piping
2.9 Redirect
2.10 Alias

3. Teil
3.1 Das objektorientierte Programmierparadigma
3.2 Zugriff auf Eigenschaften und Methoden von Objekten
3.3 Statische Eigenschaften und Methoden von .Net-Klassen verwenden
3.4 Klassen instanzieren

4. Teil
4.1 Ausgabe in eine HTML-Datei
4.2 Mit Dateien arbeiten
4.3 Arbeiten in der Registry
4.4 Arbeiten mit Eventlogs
4.5 Arbeiten mit COM-Objekten
4.6 Arbeiten mit Webformularen
4.7 Arbeiten mit .net-Objekten


1. Teil

1.1 Einführung

Windows PowerShell bietet umfassende Möglichkeiten der Systemverwaltung und -automatisierung auf der Windows-Plattform. PowerShell ist eine Kommandozeilen- und Skriptumgebung, welche auf dem .NET Framework basiert. Sie erlaubt die Steuerung und Automatisierung von Windows Server aber auch von Anwendungen bzw. Services wie Active Directory, Hyper-V, Exchange Server, System Center, Skype for Business, Citrix und VMware ESX Server usw. PowerShell-Kenntnisse sind heute unerlässlich für Windows-Systemadministratorinnen und -administratoren – sei es für Installationen vor Ort oder in der Cloud. Seit der Version 5.1 steht mit PowerShell Core parallel dazu eine Cross-Plattform-Variante zur Verfügung, die auch für Linux und macOS eingesetzt werden kann.

Zur mächtigen Skriptsprache wird Powershell dank der .Net-Bibliothek, die mittlerweile eine ansehnliche Grösse erreicht hat und ständig am weiterwachsen ist. Aus diesem Grund lädt Powershell nur die am häufigsten benötigten Teile von .Net in den Arbeitsspeicher. Benötigt man allerdings eine .Net-Komponente, die standardmässig nicht geladen ist, muss man diese explizit nachladen. Um beispielsweise eine komfortable GUI-Schnittstellen zu realisieren, muss man die Windows.Forms-Assembly laden, bevor man dann ein z.B. Formular-Objekt erstellen und mit Schaltflächen, Textboxen und weiteren Dingen bestücken kann.

Folgende Möglichkeiten zum Nachladen von .Net-Komponenten stehen zur Auswahl:

  • .Load()-Methode, falls man den "Full Name" der Komponete kennt:
    [system.reflection.assembly]::Load("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    oder alternativ, ohne "system":
    [reflection.assembly]::Load("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

  • .LoadForm()-Methode, falls man den absoluten Pfad zur Komponente kennt:
    [reflection.assembly]::LoadFrom("C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll")

  • .LoadWithPartialName()-Methode, falls man nur Teile des "Full Name" der Komponente kennt:
    [reflection.assembly]::LoadWithPartialName("Windows.Forms")

  • Mit CmdLet Add-Type: (Funktioniert nicht immer. Benötigt z.T. "Full Name")
    Add-Type –AssemblyName Windows.Forms

PowerShell-Version anzeigen :

$PSVersionTable

Hilfe zu einem CmdLet erhalten (z.B Write-EventLog):

Get-Help Write-Eventlog -full (-examples)

Properties und Methods von einem Objekt anzeigen:

"Hello" | Get-Member

WPS-Sicherheitseinstellungen anpassen:

Um Scripte ausführen zu können, muss man im WPS-Terminal die Sicherheitseinstellung von WPS anpassen:
Set-ExecutionPolicy unrestricted

Explizite Variablendeklaration erwirken:

In diesem WPS-Kurs wird eine explizite Variablendeklaration verlangt. Dies kann mit folgender Skriptzeile erzwungen werden:
set-psdebug -strict

Relative Pfade verwenden:

Um mit relativen Pfaden (Funktionen, Dateien) zu arbeiten, empfiehlt es sich, den aktuellen Pfad bewusst als CWD (Current Working Directory) zu setzen, z.B. auf den Skriptordner. Dies kann mit den folgenden zwei Skriptzeilen erfolgen:
[String] $scriptPath = Split-Path $MyInvocation.MyCommand.Path
Set-Location $scriptPath

1.2 Absoluter und relativer Pfad

Absoluter Pfad = C:\Benutzer\FelixMuster\Dokumente\MeinText.txt
Relativer Pfad: Abhängig vom CurrentWorkingDirectory (CWD)
Falls CWD = C:\Benutzer\FelixMuster\Dokumente
Relativer Pfad = .\MeinText.txt
Falls CWD = C:\Benutzer\FelixMuster
Relativer Pfad = .\Dokumente\MeinText.txt

Hinweis: Der Punkt (.) steht für das CWD

1.3 Script-Programme starten

Script aus der Powershell-ISE oder aus einem anderen Skript heraus starten:

  • Im aktuellen Variablen-Gültigkeitsbereich («.» beachten!)
    . "C:\Benutzer\FelixMuster\Dokumente\myScript.ps1
    . .\myScript.ps1
  • Im eigenen Variablen-Gültigkeitsbereich («&» beachten!)
    & "~\Dokumente\myScript.ps1"   #~ bedeutet Home-Verzeichnis
    & .\myScript.ps1

Powershellscripts und CmdLet's aus der Konsole CMD aufrufen:

  • Konsole «cmd.exe» aufrufen und darin folgendes ausführen...
  • Powershell.exe -command Get-Process #WPS-CmdLet «Get-Process» ausführen
  • Powershell.exe -command Set-ExecutionPolicy unrestricted #Policy ändern, wie in der WPS-ISA auch, um eigener Skript ausführen zu dürfen
  • Powershell.exe -command .\myScript.ps1 #Eigener Skript über relationalen Pfad aufrufen

2. Teil

2.1 Datentypen

(Aufzählung nicht abschliessend)

  • [int] $intVar = 0 #32-Bit-Ganzzahl
  • [double] $dblVar = 0 #Fliesskommazahl
  • [char] $chrVar = ' ' #Ein Unicode-16-Bit-Character
  • [string] $strVar = "" #Textzeile
  • [boolean] $boolVar = $true #Logische Variable
  • [DateTime] $datVar = "01.31.1999"
  • [DateTime] $datVar = Get-Date #Variable mit aktuellem Datum füllen
  • [Object] $objVar = 0 #Der Stamm einer Objekthierarchie
  • [int[]] $intArr = 66,77,88,99 #Feldvariable / Array
    $intArr[0] =22 #Überschreiben des "ersten" Elements 0
    $intArr[1] = 33 #Überschreiben des "zweiten" Elements 1
  • Set-Variable constWert -Value 100 -option ReadOnly #Unveränderbare Konstante mit Inhalt 100

2.2 Input/Output

  • Wert mit Read-Host einlesen:
    $intVar = Read-Host "Bitte eine Zahl eingeben:"

  • Ausgabe mit Write-Host:
    Write-Host "Das Resultat lautet:" $intVar

  • Ausgabe mit Out-GridView:
    Get-Services | Out-GridView

2.3 Vergleichsoperatoren

  • Gleich: -eq
  • Ungleich: -ne
  • Kleiner als: -lt
  • Kleiner oder gleich als: -le
  • Grösser als: -gt
  • Grösser oder gleich als: -ge
  • Zeichenkette mit Wildcards finden: -like (Bsp.: "Arnold" -like "Arn*")
  • Substring finden: -match (Bsp.: "Arnold" -match "nol")
  • Suche in Collections: -contains (Bsp.: $w = "Do","Re","Mi" → $w -contains "Mi")

2.4 Die Selektion

Selektion → Verzweigung

  • Zweiseitige Selektion:
    if
    ( $userInput -ne $null )
    {
      echo "Input was [$userInput]"
    }
    else
    {
      echo "User cancelled the form!"
    }

  • Entscheidungen können auch mit Pipelines formuliert werden. Die Bedingung ist wahr ($true), wenn die Pipe mindestens ein Objekt zurückliefert:
    if (dir *.txt | Select-String "Steuererklaerung")
    {
      write-host "Es existiert mindestens eine Datei Steuererklaerung"
    }

  • Mehrfachselektion:
    switch( $A )
    {
      1 { Write-Host "Eins" }
      2 { Write-Host "Zwei" }
      3 { Write-Host "Drei" }
    default { Write-Host "Leer" }
    }

2.5 Die Iteration

Iteration → Schleife

  • Kopfgesteuerte Iteration:
    [int] $myVar = 0
    while
    ($myVar -lt 10)
    {
      Write-Host Hello
      $myVar++
    }

  • Fussgesteuerte Iteration:
    [int] $myVar = 0
    do
    {
      Write-Host Hello
      $myVar++ 
    } while ($myVar -lt 10)

  • Kopfgesteuerte Iteration - Spezialfall for-Schleife:
    [string] $sterne = ""
    [int] $maxPosition=8
    for ( $currPosition = 1 ; $currPosition -le $maxPosition ; $currPosition++ )
    {
      $sterne = $sterne + "*"
    }
    write-host $sterne

  • Diese Iteration arbeitet eine Sammlung von Objekten ab. Die sogenannte Element-Variable $Variable speichert bei jedem Durchgang jeweils ein Objekt der Objekt-Gruppe:
    Foreach ($Variable in get-childitem C:\windows)
    {
      ...
      $Variable.Name;
      $Variable.CreationTime
      ...
    }

  • Vereinfachte Variante mit dem CmdLet «Foreach_Object»: Man kann mit der Standardvariable $_ auf die einzelnen Objekte in der Pipeline zugreifen:
    (Vorsicht: Das vorangegangenen Beispiel mit der foreach-Funktion unterscheidet sich zu diesem Beispiel darin, dass hier ein foreach-CmdLet verwendet wird. Im Gegensatz zur Funktion muss beim CmdLet die geschweifte Klammer «{» auf derselben Zeile folgen.)
    get-childitem C:\windows | Foreach-Object {
      ...
      $_.Name;
      $_.CreationTime
      ...
    }

2.6 Try and catch

Da gewisse Anweisungen einen Laufzeitfehler auslösen können, bedient man sich um diese abzufangen einer Try-and-Catch-Struktur: Wird innerhalb des Try-Blocks ein Laufzeitfehler ausgelöst, wird der Catch-Block ausgeführt. Damit kann man eine robuste Dateneingabe erreichen, den Aufruf eines nicht vorhandenen Dienstes abblocken oder Zahlen überprüfen.

  • Try-Catch in einer Iteration:
    do
    {
      try
     
    {
        $numOk = $true
        [int]$myNumber = Read-host "Enter a number between 0 and 100"
      } # end try-Part
      catch
      {
        $numOK = $false
      } # end catch-Part
    } until (($myNumber -ge 1 -and $myNumber -lt 100) -and $numOK)

  • Dienst auf sein Vorhandensein überprüfen:
    $servicename = Read-host "Bitte geben Sie ein Servicename ein"
    try
    { # der Fehler beim ausgeführten Cmdlet wird abgefangen!
      Get-Service $servicename -ErrorAction Stop
    } # end try-Part
    catch
    {
      Write-Warning "Diesen Service ($servicename) gibt es nicht!" 
    } # end catch-Part

  • Robuste Zahleneingabe:
    function isNumeric ($x)
    {
      try
     
    {
        0 + $x | Out-Null #Versucht mit der Variable zu rechnen
        return $true #Wenn möglich $true zurückgeben
      }
      catch
      {
        return $false #Wenn Fehler auftritt handelt es sich nicht um eine Zahl, somit $false
      }
    }

2.7 Abstraktion / Funktion / Methode / Filter

Sowohl Cmdlets als auch in Bibliotheken bereitgestellte Funktionen (Methoden bei Objekten) stellen Abstraktionen dar. Oft liefern diese einen Rückgabewert (ReturnValue) an das aufrufende Programm zurück. Es lassen sich aber auch eigene Funktionen erstellen. Im Quellcode müssen diese vor ihrem Aufruf definiert werden.

  • Variante 1: Die param-Angabe bestimmt dabei erforderliche Übergabeparameter und definiert deren Namen. Über diese Namen kann ein Parameter beim Aufruf auch explizit gesetzt werden.
    function myFunction
    {
      param([int]$parameter1, [string]$parameter2, …) #Parameter definieren
      … #Hier steht der Inhalt der Funktion
      return ... #Damit kann ein allfälliger Rückgabewert an den Aufrufer zurückgegeben werden
    }
    Aufruf der Funktion:
    c:\user\...> $resultat = myFunction -parameter2 "Text" -parameter1 12 …

  • Variante 2: Kurzschreibweise ohne "param" Bei der Übergabe muss die hier definierte Reihenfolge eingehalten werden.
    function myFunction ([int]$parameter1, [string]$parameter2, …)
    {
      … #Hier steht der Inhalt der Funktion
      return ... #Damit kann ein allfälliger Rückgabewert an den Aufrufer zurückgegeben werden
    }
    Aufruf der Funktion:
    c:\user\...> write-host myFunction 12 "Text" …

  • Variante 3: Übergabe von Werten via Argumentübergabe mittels der vordefinierten Variable $args (=Array) und $arg.count (=Anzahl übergebener Parameter).
    function myFunction
    {
      … #Hier steht der Inhalt der Funktion
      $args[…] #Der erste Wert hat den Index 0
      … #Hier steht der Inhalt der Funktion
      return ... #Damit kann ein allfälliger Rückgabewert an den Aufrufer zurückgegeben werden
    }
    Aufruf der Funktion:
    c:\user\...> myFunction 12 "c:\" … | out-file resultat.txt

Beispiele: (Hinweis: Beim Aufruf mit mehreren Parametern müssen die Parameter mit Leerschlag und nicht mit Komma getrennt werden! Kommata definieren ein Array und werden als solche dann in einem Parameter abgelegt. Um zusammenhängenden Text in einen Parameter zu packen müssen Sie ihn mit " " einfassen.)

  •  function myMessage ($string, $title='PowerShell Message')
    {
      [windows.forms.messagebox]::Show($string, $title)
    }

    myMessage "Diesen Text anzeigen!"; #Funktionsaufruf

  • $nl = [System.Environment]::NewLine #oder `n
    function myHallo
    {
      param $name
      $date = Get-Date
      If ($date.Hour -lt 12 -and $date.Hour -gt 6)
      {
        "Guten Morgen $name,$nl Es ist $($date.DateTime)"
      } 
      elseif ($date.Hour -gt 12 -and $date.Hour -lt 19)
      {
        "Guten Tag $name,$nl Es ist $($date.DateTime)"
      }
      elseif ($date.Hour -gt 19 -and $date.Hour -lt 24)
      {
        "Guten Abend $name,$nlEs ist $($date.DateTime)"
      }
    }

    myHallo -name Stefan Rehwald #Funktionsaufruf
    myHallo -name "Konrad Ernst Otto Zuse" #Funktionsaufruf
    myHallo "Rudolf Diesel" #Funktionsaufruf
    $User = "Nikolaus Kopernikus"
    myHallo $User #Funktionsaufruf

Definition eines eigenen Filters für die Pipe:
Filter werden identisch zu den Funktionen definiert. Eine Funktion wird einmal für alle Objekte in der Pipeline gemeinsam aufgerufen, ein Filter jeweils einmal für jedes Objekt. Um also beispielsweise einen Befehl zu entwickeln, der die Summe einer bestimmten Eigenschaft berechnet, wird eine Funktion eingesetzt, was jedoch auch den Nachteil hat, dass die Pipeline-Verarbeitung solange angehalten wird, bis sämtliche Objekte zur Verfügung stehen. Bei einem Filter kann die Pipeline weiterarbeiten, obwohl das vorhergehende Cmdlet noch weitere Objekte liefert.

  • Variante 1:
    filter name { param($parameter1, $parameter2, …) … }
  • Variante 2:
    filter name ($parameter1, $parameter2, …) {…}
  • Variante 3:
    filter name { … $args[…] … }

2.8 Piping

Beispiel: Get-Process explorer | Get-Member (Get-Process und Get-Member sind CmdLets. Den Pipe «|» erhält man mit ALTGR + 7)

2.9 Redirect

Redirect nennt man die Umleitung des Outputs vom Standard-Ausgabedevice (WPS-ISE-Konsole) in eine Textdatei:

  • get-process | out-file "myProc.txt" #Interprozesskommunikation per Pipe «|» (WIN: ALTGR + 7)
  • get-process > "myProc.txt" #Wie bei UNIX/LINUX üblich: Es wird die Datei myProc.txt erstellt oder wenn bereits bestehend, ohne Rückfrage überschrieben.
  • get-process >> "myProc.txt" #Append = Wenn die Datei bereits existiert, wird der Inhalt an das Dateiende angehängt, sonst wird die Datei neu erstellt.

2.10 Alias

Das Wort Alias bedeutet «Sonst» bzw. ein Alias ist ein Pseudonym für einen anderen Befehl.

  • Set-Alias -Name list -Value get-childitem #get-childitem ist ein CmdLet
  • Set-Alias list get-childitem #Kurzform
  • Set-Alias np c:\windows\notepad.exe
  • Set-Alias no1 .\myNumberOneScript.ps1
  • Get-Alias #Aliase anzeigen
  • Achtung: Eigene Aliase sind nur temporär vorhanden und verschwinden nach einem Neustart der WPS-ISE!

3. Teil

3.1 Das objektorientierte Programmierparadigma

Die objektorientierte Programmierung (OOP) ist ein auf dem Konzept der Objektorientierung basierendes Programmierparadigma. Die Grundidee besteht darin, die Architektur einer Software an den Grundstrukturen desjenigen Bereichs der Wirklichkeit auszurichten, der die gegebene Anwendung betrifft.

  • Alles ist ein Objekt
  • Objekte kommunizieren durch das Senden und Empfangen von Nachrichten
  • Objekte haben ihren eigenen Speicher
  • Jedes Objekt ist die Instanz einer Klasse
  • Die Klasse beinhaltet das Verhalten aller ihrer Instanzen

Der hauptsächliche Unterschied zwischen prozeduraler und objektorientierter Programmierung ist die Beziehung zwischen Daten und Funktionen. Während bei der objektorientierten Programmierung Daten und Funktionen, die auf diese Daten angewandt werden können, in Objekten zusammengefasst werden, haben bei der prozeduralen Programmierung Daten und Funktionen keinen Zusammenhalt.

Beispiel:

Aufgrund eines Bauplans (Class) werden Exemplare (Objects) davon erzeugt (instanziert). Nämlich in diesem Fall ein Objekt mit dem Namen «Lightning», ein anderes mit dem Namen «Blizzard» und ein drittes mit dem Namen «Thunder». Diese Objekte können nun über ihre Objektnamen angesprochen werden.

Die Objekte besitzen:

  • Eigenschaften oder Attribute (Properties), wie z.B. Farbe, Grösse und weitere Merklmale
  • Methoden, Funktionen (Methods). Methoden können Parameter erhalten, die beim Aufruf übergeben werden müssen, und einen Rückgabewert besitzen, den sie am Ende dem Aufrufer zurückgeben. Beispielsweise hat die Methode «addiere» die Parameter Zahl 1 und Zahl 2 und gibt als Rückgabewert die Summe der Zahlen zurück.

Verändern von Eigenschaften (Zugriff auf Properties):

Ausführen von Funktionen (Methods):

Spezielle Methoden zur Erzeugung und Zerstörung von Objekten heissen Konstruktoren Create() beziehungsweise Destruktoren Kill().

3.2 Zugriff auf Eigenschaften und Methoden von Objekten

Erklärt an einem Beispiel das voraussetzt, dass der Prozess Notepad auf dem System gestartet ist:

  • Alle Eigenschaften und Methoden des Prozess-Objekts «Notepad» anzeigen:
    Get-Process Notepad | Get-Member #Get-Process und Get-Member sind CmdLet's
  • Erste Variante "Methode ausführen": Mit dem CmdLet «Get-Process» das Prozess-Objekt «Notepad» ansprechen und die Methode «GetType()» aufrufen:
    (get-process notepad).GetType()
  • Zweite Variante "Methode ausführen": Mit dem CmdLet «Get-Process» das Prozess-Objekt «Notepad» in der Object-Variablen «myObj» speichern und anschliessend über die Object-Variable die Methode «GetType()» ausführen:
    [Object] $myObj #Object-Variable deklarieren 
    $myObj = get-process Notepad #Object-Variable zuweisen
    $myObj.GetType() #Über Object-Variable eine seiner Methoden ausführen
  • Eigenschaft Prozess-ID anzeigen:
    (Get-Process Notepad).Id
    $myObj.Id

Wenn man mit einer PowerShell-Pipeline arbeitet und sich auf das Objekt beziehen möchten, das sich gerade in der Pipeline befindet, kann man eine der beiden automatisch generierten und völlig gleichwertigen Variablen $PSItem oder $_ nutzen. Dazu ein Beispiel:

  • Get-Process | Foreach-Object { write-host $PSItem.ProcessName $PSItem.CPU}
  • Get-Process | Foreach-Object { write-host $_.ProcessName $_.CPU}
  • Get-Process | Foreach-Object { write-host $_.ProcessName }
  • Get-Process | Foreach-Object { $_.ProcessName }

3.3 Statische Eigenschaften und Methoden von .Net-Klassen verwenden

  • [<Klassenname>]::Eigenschaft
  • [<Klassenname>]::Methode(<Parameter>)

Beispiele mit der .Net-Klasse «Math»

  • [Math]::Pi #Konstatnte Pi
  • $x = 0.5; [Math]::Sin($x) #Sinuswert ermitteln
  • $y = 2; [Math]::Sqrt($y) #Quadratwurzel ermitteln

Beispiele mit der .Net-Klasse «Convert»

  • $Bin2Dez = [Convert]::ToInt32("101101010101",2) #Resultat: 290110
  • $Oct2Dez = [Convert]::ToInt32("1234567",8) #Resultat: 34239110
  • $Dez2Hex = [Convert]::ToString("65098",16) #Resultat: "FE4A"
  • $Dez2Bin = [Convert]::ToString("12345",2) #Resultat: "11000000111001"

3.4 Klassen instanzieren

Bei Powershell ist alles ein Objekt mit Eigenschaften und Methoden, sogar der Integer und der String. Beispiel:
[string] $myStr
$myStr = "Hello"
$myStr | Get-Member
$myStr.Length  (ergibt den Wert 5)
$myStr.ToUpper() (ergibt HELLO)

Achtung! Beim folgenden Beispiel wird nicht ein neues Objekt erzeugt, sondern eine Objektvariable erstellt und dieser die Referenz auf das Prozessobjekt "notepad" zugewiesen. Das Prozessobjekt "notepad" wurde von Betriebssystem zu dem Zeitpunkt erstellt, als das Programm notepad.exe gestartet wurde:
[object] $myObject
$myObject = Get-Process notepad 

Es soll mit New-Object ein Objekt von einer .Net-Klasse erstellt werden. Dies soll anhand eines Beispiels mit der Klasse Net.WebClient gezeigt werden. Diese enthält die Methode DownloadFile, mit der eine Datei aus dem Internet geladen und lokal gespeichert werden kann:

  • $web = New-Object -typename Net.WebClient
  • $web.DownloadFile("http://edu.juergarnold.ch/fach_it/wpssummary/titel.jpg", "C:\Users\FelixMuster\Pictures\titel.jpg")

Falls an ihrem Standort ein Proxiserver mit z.B. IP=192.0.200.200 an Port=8080 existiert, muss folgendes ergänzt werden:

  • $web = New-Object -typename Net.WebClient
  • $proxy = New-Object System.Net.WebProxy("http://192.0.200.200:8080")
  • $web.proxy = $proxy #WebClient über diesen Proxy leiten
  • $proxy.UseDefaultCredentials = $true #Benutzt Benutzername & PW des aktuellen Standorts
  • $web.DownloadFile("http://edu.juergarnold.ch/fach_it/wpssummary/titel.jpg", "C:\Users\FelixMuster\Pictures\titel.jpg")

4. Teil

4.1 Ausgabe in eine HTML-Datei

get-service | ConvertTo-Html -title "MELDUNG SYSADMIN" -body (get-date) -pre "<p>Erstellt von Felix Muster</p>" -post "<p> Weitere Infos siehe <a href=http://felixmuster> http://felixmuster </a></P>" –Property Name, Status | foreach {
  if ($_ -like "*<td>Running</td>*")
  {
    $_ -replace "<tr>", "<tr bgcolor=green>"
  }
  elseif ($_ -like "*<td>Stopped</td>*")
  {
    $_ -replace "<tr>", "<tr bgcolor=red>"
  }
  else
  {
    $_
  }
} > .\ServiceStatus.html

4.2 Mit Dateien arbeiten

  • Pfad setzen:
    Set-Location [Pfad]
  • Pfad auslesen:
    Get-Location
  • Existenz eines Pfades überprüfen:
    Test-Path -path [Pfad] #Liefert $True oder $False zurück
  • Verzeichnis oder Datei lesen:
    Get-Item [dir] oder Get-Item [file]
    Get-ChildItem [dir] #Optionen: -include Pattren, -exclude Pattern -recurse
  • Leeres Unterverzeichnis löschen:
    (Get-Item .\meinUnterverzeichnis).delete()
  • Dateiinformationen auslesen:
    $myFile = Get-Item *.txt #Ergibt Array von gefundenen Dateiobjekten
    $myFile | Get-Member #Dateiobjekt-Array wird an Get-Member weitergereicht
  • Zugriff auf Dateieigenschaften:
    $myFile = Get-Item .\meinText.txt
    Write-Host $myFile.Name
    Write-Host $myFile.Length
  • Handelt es sich um eine Datei oder ein Verzeichnis?
    $myFileList = get-ChildItem c:\Users\FelixMuster\Desktop -recurse
    foreach($myFile in $myFileList) {
      if($myFile.PSISContainer -eq $True)
      {
        Write-Host $myFile.Name
      }
    }
    Alternative Datei oder ein Verzeichnis:
    dir c:\Users\FelixMuster\Desktop –r | foreach {if ($_.mode –match "d"){Write $_.Name}}
  • Da es zu einer Fehlermeldung kommt, wenn WPS eine Datei nicht findet, auf die eine Operation ausgeführt werden soll, muss zuerst deren Existenz überprüft werden:
    if ((get-ChildItem .\meinText.txt).exists -eq $True)
    {
      write-host OK
    }
    else 
    {
      write-host NOK
  • Datei kopieren:
    [environment]::CurrentDirectory = Get-Location #Falls relative Pfadangabe folgt
    $myFile = Get-Item .\meinText.txt
    $myFile.CopyTo(".\meinUnterverzeichnis\meinTextbackup.txt", -1) #-1 für Überschreiben
  • Mehrere Dateien kopieren:
    $myFileList = get-ChildItem c:\Users\FelixMuster\Dokumente\*.txt
    $destinationDir = "c:\Users\FelixMuster\Backup\"
    foreach($myFile in $myFileList)
    {
      $myFile.CopyTo($destinationDir+($myFile.Name), -1) | Out-Null #Out-Null unterdrückt Ausgabe
    }
    Alternative Mehrere Dateien kopieren:
    $myFileList = get-ChildItem c:\Users\FelixMuster\Dokumente\*.txt
    $destinationDir = "c:\Users\FelixMuster\Backup\"
    Copy-Item $myFileList $destinationDir -force #force erzwingt Überschreiben
  • Dateien verschieben:
    Funktioniert wie das Kopieren. Die Methode heisst «.MoveTo()», das CmdLet heisst: «Move-Item»
  • Dateien löschen:
    Funktioniert wie das Kopieren. Die Methode heisst «.Delete()», das CmdLet heisst: «Remove-Item»
  • Dateien umbenennen:
    Eine eigentliche Methode gibt es nicht. Allenfalls kann mit «.MoveTo()» eine Umbenennung konstruiert werden. Ein CmdLet existiert allerdings und nennt sich «Rename-Item». Beispiel:
    $myNewName = Read-Host "Neuer Dateinamen"
    $myZaehler = 0
    $myFiles = Get-ChildItem *.txt
    if($myFiles -ne $NULL)
    {
      foreach($File in $myFiles)
      {
        $myFullNewName = $myNewName + $myZaehler + ($File.extension)
        Rename-Item $File $myFullNewName
        $myZaehler++
      }
      write-host ($myZaehler)" Dateien umbenannt"
    }
  • Webseite in eine Datei kopieren:
    $wc = new-object System.Net.WebClient
    $wc.DownloadString('http://edu.juergarnold.ch/index.html') | out-file edu.txt
    get-content edu.txt

4.3 Arbeiten in der Registry

Die Windows-Registrierungsdatenbank (Registry) ist die zentrale hierarchische Konfigurationsdatenbank des Betriebssystems Windows. Hier werden sowohl Informationen zu Windows selbst als auch Informationen zu Programmen gespeichert. Die Registry steht Powershell wie ein normales Laufwerk zur Verfügung. Darum kommen ähnliche CmdLets und Funktionen zur Anwedung wie beim Arbeiten mit Dateien. Registry-Schlüssel (HKEY_ = Handle to a Key_) lassen sich mit Get-ChildItem anzeigen, deren Inhalte mit Get-ChildItemProperty.

  • Registry-Schlüssel und Properties in "HKEY_LOCAL_MACHINE\Software" anzeigen:
    Get-ChildItem HKLM:\Software

  • Properties anzeigen: (Hier der Autostart-Schlüssel)
    Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Run

  • Neuer Registry-Schlüssel in "HKEY_LOCAL_MACHINE\Software" anlegen:
    New-Item -path "HKLM:\Software" -Name "Testkey"

  • Neuer Eintrag erstellen:
    New-ItemProperty -literalpath "HKLM:\Software\Testkey" -Name "Testkey" -Value "Test CRM" -type String

  • Eintrag entfernen:
    Remove-ItemProperty -literalpath "HKLM:\Software\Testkey" -Name "Testkey"

  • Registry-Schlüssel entfernen:
    Remove-Item -path "HKLM:\Software\Testkey"

4.4 Arbeiten mit Eventlogs

  • Die drei letzten Einträge im System-Eventlog formatiert auslesen:
    get-eventlog system -newest 3 | format-list
    get-winevent -logname system -computername 127.0.0.1 -maxevents 3 | format-list

  • Ein Event in den Application-Eventlog eintragen:
    Falls noch nicht geschehen, die neue Event-Quelle einmalig registrieren:
    New-EventLog -LogName Application -Source myApp #Neue Event-Quelle registrieren
    Write-EventLog -logname "Application" -computername $env:COMPUTERNAME -source "myApp" -eventID 9999 -entrytype Information -message "Hello World"
    Hinweis -computername [computername] ermöglicht auch die Abfrage über das Netzwerk. $env:COMPUTERNAME ist der eigene Computername 127.0.0.1. In diesem Fall könnte -computername auch ganz weggelassen werden.

4.5 Arbeiten mit COM-Objekten

Das Component Object Model (COM) ist eine von Microsoft entwickelte Technik zur Interprozesskommunikation unter Windows. COM-Komponenten können sowohl in Form von Laufzeitmodulen (DLLs) als auch als ausführbare Programme umgesetzt sein. COM soll eine leichte Wiederverwendung von bereits geschriebenem Programmcode ermöglichen, zum Teil auch über Betriebssystemgrenzen hinweg.  Als Beispiel sollen Automatisierungsmöglichkeiten von Office, speziell Excel und Webseitenabfragen mit Internetexplorer aufgezeigt werden.

Excel:

  • Excel-Objekt erzeugen:
    $myExcel = New-Object -comobject Excel.Application

  • Eigenschaften und Methoden des Excel-Objekts anzeigen:
    $myExcel | Get-member

  • Neues Workbook erstellen:
    $myWorkbook = $myExcel.Workbooks.Add()

  • Neues Worksheet erstellen:
    $mySheet = $myWorkbook.Worksheets.Item(1)

  • Zellen des Excelsheets füllen:
    $mySheet.Cells.Item(1,1) = "Hello World"
    $mySheet.Cells.Item(2,1) = "2+4" #Textzeile
    $mySheet.Cells.Item(3,1) = 2+4 #Integer

  • Excelsheet anzeigen:
    $myExcel.Visible = $True

  • Excelsheet abspeichern: (Bei relativem Pfad in Dokumentenordner)
    $myWorkbook.SaveAs(".\test.xlsx")

  • Aufräumen bzw. Excel schliessen und Variablen löschen:
    $myExcel.Quit()
    Remove-Variable mySheet, myWorkbook, myExcel

Internet-Explorer:

  • InternetExplorer-Objekt erzeugen:
    $myIE = New-Object -comobject InternetExplorer.Application

  • Eigenschaften und Methoden des InternetExplorer-Objekts anzeigen:
    $myIE | Get-member

  • InternetExplorer positionieren:
    $myIE.top = 20; $myIE.width = 1800; $myIE.height = 1600 ; $myIE.Left = 20;

  • InternetExplorer anzeigen:
    $myIE.Visible = $True

  • Webseite aufrufen:
    $myIE.Navigate("edu.juergarnold.ch")

4.6 Arbeiten mit Webformularen

  • Mit Invoke-WebRequest ein Formular aufrufen und Formular mit SessionKey merken:
    $myWebForm=Invoke-WebRequest http://edu.juergarnold.ch/fach_it/wpssummary/testForm.html -SessionVariable mySession

  • Im Formular "berechnung" das Feld "resultat" beschreiben:
    $myWebForm.Forms["berechnung"].Fields["resultat"] = "2"

  • Formularinhalt übermitteln und Formularaktion auslösen:
    Invoke-WebRequest -Method POST -URI ("http://edu.juergarnold.ch/fach_it/wpssummary/" + $myWebForm.Forms["berechnung"].action) -Body $myWebForm.Forms["berechnung"].Fields -WebSession $mySession

4.7 Arbeiten mit .net-Objekten

Erstellen einer grafischen Benutzereingabe:

  • Benötigte .NET-Frameworkklassen laden:
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing

  • Instanz einer Form-Klasse erstellen:
    $form = New-Object System.Windows.Forms.Form

  • Form-Objekt anpassen:
    $form.Text = 'FORMULAR'
    $form.Size = New-Object System.Drawing.Size(400,300)
    $form.StartPosition = 'CenterScreen'

  • OK-Button kreiern, anpassen und in das Formular einfügen:
    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Point(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = 'OK'
    $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $form.AcceptButton = $OKButton
    $form.Controls.Add($OKButton)

  • Cancel-Button kreiern, anpassen und in das Formular einfügen:
    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Point(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = 'Cancel'
    $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    $form.CancelButton = $CancelButton
    $form.Controls.Add($CancelButton)

  • Beschriftung kreiern, anpassen und in das Formular einfügen:
    $label = New-Object System.Windows.Forms.Label
    $label.Location = New-Object System.Drawing.Point(10,20)
    $label.Size = New-Object System.Drawing.Size(280,20)
    $label.Text = 'Bitte Text eingeben:'
    $form.Controls.Add($label)

  • Texteingabezeile kreiern, anpassen und in das Formular einfügen:
    $textBox = New-Object System.Windows.Forms.TextBox
    $textBox.Location = New-Object System.Drawing.Point(10,40)
    $textBox.Size = New-Object System.Drawing.Size(260,20)
    $form.Controls.Add($textBox)

  • Topmost-Eigenschaft auf $True setzen, um das Öffnen des Fensters über anderen geöffneten Fenstern und Dialogfeldern zu erzwingen:
    $form.Topmost = $true

  • Formular aktivieren und Fokus auf das Textfeld setzen:
    $form.Add_Shown({$textBox.Select()})

  • Formular anzeigen lassen:
    $result = $form.ShowDialog()

  • Der Code im If-Block weist Windows an, wie mit dem Formular verfahren werden soll, nachdem der Benutzer einen Text eingegeben und die Schaltfläche OK oder Eingabetaste gedrückt hat:
    if ($result -eq [System.Windows.Forms.DialogResult]::OK)
    {
      $x = $textBox.Text
    }