Inhalt

Vorheriges Thema

13. Aufgaben

Nächstes Thema

15. PowerShell im Editormodus

Diese Seite

14. Lösungen

14.1. Konsole

14.2. Editormodus

14.3. Variable_und_Datentyp

  • Was ist das Ergebnis des folgenden Skriptes

    [int]$a = -7
    [int]$b = 3
    Write-Host($a/$b)
    Write-Host([int]($a/$b))
    -2,3333
    -2
    

Das Ergebnis der Division zweier Ganzzahlen ist ein Wert vom Typ double. Erst durch das Casten des Wertes in ein Integer wird eine Ganzzahl als Ergebnis zurückgegeben. Bei Komma 5 wird der Integer-Wert auf die höhere Zahl aufgerundet

  • Welche Zeichen sind für das Erstellen eines Variablennamens möglich. Recherchieren Sie falls notwendig auch im Internet

    You can use virtually any variable name you choose, names are not case sensitive. Note: there are illegal characters such as; ! @ # % & , . and spaces. PowerShell will throw an error if you use an illegal character.

    I stated virtually any name as PowerShell does have a set of keywords that are reserved and cannot be used as variable names:

    • break
      • continue
      • do
      • else
      • elseif
      • filter
      • foreach
      • function
      • if
      • in
      • return
      • switch
      • until
      • where
      • while
  • Welchen Unterschied macht es, ob sie als Kennzeichen für einen String das Zeichen ” oder das Zeichen ‘ einsetzen.

    Beide Zeichen sind erlaubt, beim ‘-Zeichen wird nicht interpoliert. Eine Variable innerhalb des Strings würde nicht mit dem Wert dargestellt. Beispiel:

    $Teacher1 = "Steinam"
    $TEacher2  = 'Sierl'
    
    $ausgabe = "Hallo $Teacher1 "
    $ausgabe2 = "Hallo $Teacher2 "
    
  • Wie kann man erfahren, welcher Datentyp eine Variable bzw. ein Wert hat

    (42).GetType()
    
    
    IsPublic IsSerial Name               BaseType
    -------- -------- ----               --------
    True     True     Int32              System.ValueType
    
    
    (-7/3).GetType()
    (9/3).GetType()
    

Die Werte müssen erst berechnet werden. Dies wird durch die Klammerung erreicht.

  • Sie möchten einen String als Datum weiterverwenden, falls er ein reguläres Datum ist.

    [DateTime]"03/13/1964"
    
  • Welche Vorteile hat das Casten eines Strings in ein DateTime-Objekt

    Man verfügt anschließend über die Methoden des DateTime-Objektes, was eine Weiterbearbeitung häufig einfacher macht, z.B. bei Datumsberechnungen.

    $result = ((get-date).subtract([DateTime]"03/13/1964"))
    ($result.Days/366).gettype()
    
  • Welche Variablen sind beim Start von Powershell bereits vorhanden ? Wie kann man sie sichtbar machen

    dir variable:
    

    zeigt alle in der PS-Sitzung verwendeten bzw. bereits vorhandenen Variablen

  • Folgender Quellcode ist vorhanden

    $a = "Hello"
    $b = 123
    
    • Bestimmen Sie die Länge des Wertes der Variable $a
    • An welcher Stelle im String kommt der Buchstabe “e” vor
    • Tauschen Sie den Buchstaben ‘e’ durch den Buchstaben ‘a’
    $a.Length
    
    $a.IndexOf("e")
    
    $a.Replace("e", "a")
    

14.4. Operatoren

Einfach ein test

14.5. Arrays

  • Schreiben Sie eine Funktion, die als Parameter einen Pfad erwartet und anschließend den Inhalt des Pfades ausgibt

    function listDirectory($pfad)
    {
    
    cd $pfad
    Dir $pfad |Out-File  C:\temp\Ausgabe.txt
    
    }
    
  • Wie überprüfen Sie, ob ein Array einen bestimmten Wert enthält

    Mit Hilfe des -contains - Operators

  • Wie überprüfen Sie, ob zwei Arrays gleich sind

    Folgende Funktion überprüft zwei Arrays auf Gleichheit

    function AreArraysEqual($a1, $a2) {
            if ($a1 -isnot [array] -or $a2 -isnot [array]) {
              throw "Both inputs must be an array"
            }
            if ($a1.Rank -ne $a2.Rank) {
              return $false
            }
            if ([System.Object]::ReferenceEquals($a1, $a2)) {
              return $true
            }
            for ($r = 0; $r -lt $a1.Rank; $r++) {
              if ($a1.GetLength($r) -ne $a2.GetLength($r)) {
                            return $false
              }
            }
    
            $enum1 = $a1.GetEnumerator()
            $enum2 = $a2.GetEnumerator()
    
            while ($enum1.MoveNext() -and $enum2.MoveNext()) {
              if ($enum1.Current -ne $enum2.Current) {
                            return $false
              }
            }
            return $true
    }
    
  • Ein String ist eigentlich ein Array aus Elementen des Datentyps CHAR.

    $test = "Hello"
    $test[0].Gettype()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Char                                     System.ValueType
    

    Die Ansprechen eines einzelnen Elementes ist auch mit $test[1] problemlos möglich. Wie können Sie aber ein einzelnes Element eines bestehenden Strings mit Hilfe der Array-Indiziierung ändern, also etwas so

    $integerarray = 1,2,2
    $integerarray[2] = 345  # geht
    
    $test = "Hello"
    $test[0] = "F"                  #Fehlermeldung
    

    Lösung:

    Das Umwandeln mit Hilfe der String-Methode ToCharArray() erzeugt einen Array aus CHAR-Elementen, die verändert werden können.

    $ergebnis = $test.ToCharArray()
    $ergebnis[0] = "F"
    
  • Überprüfen sie, ob ein bestimmter Wert in einem Array enthalten ist, z.B.

    $arrColors = "blue", "red", "green", "yellow", "white", "pink", "orange", "turquoise"
    

    Prüfen Sie, ob der Wert “green” enthalten ist

    foreach($element in $arrColors)
    {
            if($element -eq "green")
            {
                    Write-Host
            }
            else
            {
                    Write-Host "Not found"
            }
    }
    

    Es geht natürlich in Powershell auch einfacher

    $arrColors = "blue", "red", "green", "yellow", "white", "pink", "orange", "turquoise"
    
    $result = $arrColors -contains "green"
    
  • Haben wir Elemente, die mit “bl” beginnen

    $arrColors = "blue", "red", "green", "yellow", "white", "pink", "orange", "turquoise", "black"
    
    $arrColors -like "bl*"
    
  • Sortieren sie den obigen Array alphabetisch

    $arrColors = "blue", "red", "green", "yellow", "white", "pink", "orange", "turquoise", "black"
    
    $arrColors = $arrColors | Sort-Object
    
  • Vergleichen Sie die Geschwindigkeit beim Erstellen und Suchen der folgenden Datenstrukturen: Array vs. Hashtable. Welches Ergebnis stellen Sie fest ?

    $testarray = @()
    $testhash = @{}
    
    Write-Host "Array anlegen"
    Measure-Command {
            for($i = 1; $i -lt 10000;$i++)
            {
                    $testarray += $i
            }
    }
    
    Write-Host "Hash anlegen"
    Measure-Command {
            for($i = 1; $i -lt 10000;$i++)
            {
                    $testhash.Add($i, $i)
            }
    }
    
    Write-Host "Array enthält 9000"
    Measure-Command{
            $testarray -contains 9000
    }
    
    Write-Host "Hash enthält 9000"
    Measure-Command{
            $testhash.get_Item(9000)
    }
    

    Das Skript erzeugt folgende Ergebnisse auf einem ASUS Netbook (N270, 2 GByte Ram, Windows 7):

    Array anlegen
    ...
    TotalSeconds      : 27,2567811
    TotalMilliseconds : 27256,7811
    
    Hash anlegen
    TotalSeconds      : 0,3869414
    TotalMilliseconds : 386,9414
    
    Array enthält 9000
    .....
    TotalSeconds      : 0,0359344
    TotalMilliseconds : 35,9344
    
    Hash enthält 9000
    ...
    TotalSeconds      : 0,0001328
    TotalMilliseconds : 0,1328
    

    Fazit:

    Gerade wenn Listen zur Laufzeit wachsen ist ein Array schon bei kleinen Datenmengen relativ langsam. Auch die Suche innerhalb von kleinen Datenmengen wird über eine Hashtable deutlich beschleunigt.

  • Sie besitzen eine Textdatei mit Familienname und Loginname der Firmenmitarbeiter. Sie umfasst über 9000 Einträge und soll dazu hergenommen werden, um “vergessene” Loginnamen zu suchen. Überlegen Sie sich, wie Sie diese Textdatei innerhalb von Powershell-Skripten nutzen können.

    $fam_login = @{}
    
    Import-Csv user_passwd.csv | ForEach-Object { $fam_login[$_.username] = $_.passwort}
    $fam_login
    $fam_login["?9d8k6L2"]
    
    $fam_login.GetEnumerator() | select key, value | export-csv .\testexport.csv
    
    $fam_login | export-clixml -path fam_login.xml
    
    
    $fam2 = import-clixml -path fam_login.xml
    

    Durch die Nutzung der export-clixml und import-clixml - Commandlets werden Dateien im XML-Format geschrieben. Diese machen es einfacher möglich, Metainformationen zu lesen und zu schreiben.

  • Folgende Noten einer Schulaufgabe sind vorhanden:

    2,3,3,2,4,5,4,3,2,1,6,4,3,2,5,4,1,2,3,6,5,4,3,2,1,4,3,2,1,5,4,4,4,3,2,3,4

    Lösen Sie mit Hilfe eines Arrays die folgenden Aufgaben:

    • Ermitteln Sie den Notendurchschnitt
    • Ermitteln sie die Häufigkeit jeder Note (absolut/prozentual)
    • Wie viele Noten liegen unter/über dem Schnitt
    • Erstellen Sie eine sortierte Ausgabe in Form eines Write-Host-Statements
    $noten = 2,3,3,2,4,5,4,3,2,1,6,4,3,2,5,4,1,2,3,6,5,4,3,2,1,4,3,2,1,5,4,4,4,3,2,3,4
    
    Write-Host "Anzahl der Noten: "  $noten.count
    
    #Durchschnitt berechnen
    $summe = 0
    foreach($note in $noten)
    {
       $summe = $summe + $note
    
    }
    $durschnitt = $summe/$noten.Count
    
    
    #Häufigkeit jeder Note berechnen
    #Mit Hilfe eines 2. Arrays;
    #Index dient als Notenzahl
    #das erste Element(0) bleibt frei
    $haeufigkeit = 0,0,0,0,0,0,0
    
    #Schleife hätte man auch in der ersten Lösung
    #novch mit reinnehmen können
    foreach($note in $noten)
    {
        $haeufigkeit[$note]+= 1
    }
    
    for($i = 1; $i -lt $haeufigkeit.Count;$i++)
    {
        Write-Host "Note $i = " $haeufigkeit[$i]
        #$prozent = 0
        $prozent = 100/$noten.Count*$haeufigkeit[$i]
    
        Write-Host "Note $i = " $prozent
    }
    
    
    #Wie viele Noten liegen unter/über dem Schnitt
    
    
    $zahl = 0
    #Ermittelt die Zahl besser als der Durchschnitt
    for($i = 1; $i -lt $durschnitt;$i++)
    {
        $zahl = $haeufigkeit[$i]
    
    }
    
    $besser = $zahl
    $schlechter = $noten.Count - $zahl
    
    Write-Host "besser sind $besser"
    Write-Host "schlechter sind $schlechter"
    
    
    #Sortieren der Noten
    #Über den Hilfsarray Hauefigkeit
    
    $AusgabeString = "|"
    
    for($i = 1; $i -lt $haeufigkeit.Count; $i++)
    {
       $AusgabeString += [string]$i * $haeufigkeit[$i] + "|"
    
    }
    
    $AusgabeString
    

14.6. Bedingungen

  • Mit welchen Vergleichsoperatoren können Sie in Bedingungen arbeiten ?
-eq,  -ne,  -ge,  -gt,  -lt,  -le,  -like,  -notlike,  -match,  -notmatch,  -contains, -notcontains, -is, -isnot

-and, -or, -xor, -not
  • Folgende Variablen sind gegeben:

    $user = 'steinam'
    $pass = 'passwort'
    

    Formulieren Sie eine Bedingung in Powershell, die gleichzeitig auf einen korrekten Usernamen und Passwort abfragt.

    if($user -ieq 'STEINAM' -and $pass -eq 'passwort')
    {
            Write-Host "OK"
    }
    else
    {
            Write-Host "Fehler"
    }
    
  • Mit Hilfe von WMI können Sie feststellen, welche Rolle ein Computer innerhalb einer Domäne spielt. Es gibt 6 verschiedene Rollen:
    • 0 = Stand alone workstation
    • 1 = Member Workstation
    • 2 = Stand Alone Server
    • 3 = Member Server
    • 4 = Backup Domain Controller
    • 5 = Primary Domain Controller

    Falls andere Werte zurückkommen, kann die Rolle nicht eindeutig definiert werden

    Erstellen Sie ein Skript, welches die jeweilige Rolle in Textform ausgibt.

    $wmi = get-wmiobject win32_computersystem
    "computer " + $wmi.name + " is: "
    
    switch ($wmi.domainrole)
    {
             0 {" Stand alone workstation"}
             1 {" Member workstation"}
             2 {" Stand alone server"}
             3 {" Member server"}
             4 {" Back up domain controller"}
             5 {" Primary domain controller"}
             default {" The role can not be determined"}
    }
    
  • Drucker auf verschiedenen Betriebssystemen ermitteln

    Verschiedene Betriebssysteme nutzen manchmal unterschiedliche WMI Klassen und/oder Eigenschaften, so z.B. Windows XP, Windows 2003 und Windows 2000. Sie wollen die auf diesen Betriebssystemen verwendeten Drucker auflisten und benötigen ein universell einsetzbares Skript. Verwenden Sie ein if-Statement zum Ermitteln der korrekten OS-Version und verwenden Sie den dafür vorgesehenen Code.

    Benutzen Sie die WMI-Klasse win32_OperatingSystem zum Ermitteln der OS-Version sowie win32_Printer auf XP und 2003 und win32_PrintJob auf Win2000-Systemen

    $strComputer = Read-Host "Printer Report – Enter Computer Name"
    $OS = Get-WmiObject -Class win32_OperatingSystem -namespace "root\CIMV2" -ComputerName $strComputer
    
    # if statement to run code for Windows XP and Windows 2003 Server.
    if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790"))
    {
            write-host "Computer Name: " $strComputer
            #nested if statement
            if ($OS.Version -eq "5.1.2600") {write-host "OS Version: Windows XP"}
            elseif ($OS.Version -eq "5.2.3790") {write-host "OS Version: Windows 2003"}
                    $colPrinters = Get-WmiObject -Class win32_Printer -namespace "root\CIMV2" -computerName $strComputer
                            foreach ($objPrinter in $colPrinters) {
                            write-host "Name: " $objPrinter.Name
                            write-host "Description: " $objPrinter.Description
                            write-host
                            }
    }
    
    # if statement to run code for Windows 2000 Server
    elseif ($OS.Version -eq "5.0.2195")
    {
            write-host "Computer Name: " $strComputer
            write-host "OS Version: Windows 2000 Server"
                    $colPrinters = Get-WmiObject -Class win32_PrintJob -namespace "root\CIMV2" -computername $strComputer
                    foreach ($objPrinter in $colPrinters) {
                    write-host "Name: " $objPrinter.Name
                    write-host "Description: " $objPrinter.Description
                    write-host
                    }
    }
    # if OS not identified
    else {write-host "The OS for: $strComputer is not supported."}
    write-host "–END OF REPORT–"
    

14.7. Schleifen

  • Ping

    Schreiben Sie eine Programm, welches Ihnen alle per PING erreichbaren Rechner eines Netzes ermittelt. Das Programm soll alle Adressen von 192.168.0.1 bis 192.168.0.255 pingen. Wenn ein PINg erfolgreich war, soll dies als Ausgabe angezeigt werden.

    $ping = New-Object System.Net.NetworkInformation.Ping
    $i = 0
    $liste = 1..255
    for($y=0;$y -le 255;$y++)
    {
            $ip = "192.168.0." + [string]$liste[$y]
            $Res = $ping.send($ip)
            if ($Res.Status -eq "Success")
            {
                            $result = $ip + " = Success"
                            Write-Host $result
                            $y++
            }
    }
    $Hosts = [string]$y + " Hosts is pingable"
    Write-Host $Hosts
    
    #Eine andere Lösung ist powershell-typischer (per pipeline)
    
    $ping = New-Object System.Net.NetworkInformation.Ping
    $i = 0
    1..255 | foreach
    {
            $ip = "192.168.0.$_"
            $Res = $ping.send($ip)
    
            if ($Res.Status -eq "Success")
            {
                    $result = $ip + " = Success"
                    Write-Host $result
                    $i++
            }
     }
     $Hosts = [string]$i + " Hosts is pingable"
     Write-Host $Hosts
    
  • ZahlenRaten

    Erstellen sie ein Skript, welches folgende Aufgabe erfüllt: Es muss eine Meldung anzeigen, in der der Benutzer aufgefordert wird, eine Zahl zwischen 1 und 50 einzugebeenn. Das Skript muss die vom Benutzer eingegebene Zahl mit einer zufällig generierten Zahl vergleichen. Wenn die Zahlen nicht übereinstimmen, muss das Skript eine Meldung anzeigen, in der angegeben wird, ob die geratene Zahl zu hoch oder zu niedrig war, und der Benutzer aufgefordert wird, noch einmal zu raten.

    Wenn der Benutzer richtig rät, muss das Skript die Zufallszahl sowie die Anzahl der Rateversuche anzeigen. An diesem Punkt ist das Spiel beendet, das Skript muss also auch beendet werden.

    $guesses = 0
    
    $low = 1
    $high = 50
    
    $a = New-Object Random
    $a = $a.Next($low,$high)
    
    while ($true)
    {
            $guess = read-host "Enter a number between 1 and 50: "
            $guesses++
    
            if ($guess -eq $a)
            {
                            "Random Number: " + $guess
                            "Number of Guesses: " + $guesses
                            break
            }
            elseif ($guess -gt $a)
            {
                            "Too high"
            }
            else
            {
                            "Too low"
            }
    }
    
    _images/zahlenraten.png
  • Dateien kopieren

    Diese Skripts sollen folgende Aufgaben ausführen:

    • Durchsuchen des Ordners “C:Scripts” und dessen Unterordnern.
    • Durchsuchen jedes Ordners nach sämtlichen Textdateien (Dateien mit der Erweiterung .txt) und Prüfen des Erstellungsdatums jeder Datei.
    • Kopieren/Verschieben jeder .txt-Datei, die mehr als 10 Tage zuvor erstellt wurde, in den Ordner “C:Old”.
    • Ausgeben des Dateinamens (kein vollständiger Pfad, nur Dateiname) jeder kopierten Datei.
    • Ausgeben der Anzahl der kopierten Dateien.
    foreach ($i in Get-ChildItem C:\Scripts -recurse)
    {
            if (($i.CreationTime -lt ($(Get-Date).AddDays(-10))) -and ($i.Extension -eq ".txt"))
            {
                    #Copy-Item $i.FullName C:\old
                    $i.Name
                    $x = $x + 1
            }
    }
    "Total Files: " + $x
    
  • Fonts finden

$total = 0

$a = get-item "hklm:\\Software\Microsoft\WindowsNT\CurrentVersion\Fonts"
$f = $a.GetValueNames()

foreach ($i in $f)
{
        if ($i.contains("TrueType"))
        {
                $total++
                $i
        }
}
  • Schleifen optimieren

    Die Ausgabe des folgenden Powershell-Befehls dauert u.U. sehr lange. Verbessern Sie das Statement im Hinblick auf die Auführungsgeschwindigkeit

    # Foreach loop lists each element in a collection:
    Foreach ($element in Dir C:\ -recurse) { $element.name }
    

    Lösung: Ersetze Foreach durch das ForEach-Objekt, das die Elemente der Pipeline sofort bearbeiten kann.

    # ForEach-Object lists each element in a pipeline:
    Dir C:\ -recurse | ForEach-Object { $_.name }
    
  • Dateien per ftp hochladen

    Sie sollen alle Dateien eines zu spezifizierenden Ordners auf einen ftp-server hochladen. Übergeben Sie den Ordner auf der Kommandozeile

    #we specify the directory where all files that we want to upload
    #$Dir="C:/Dir"
    
    if(test-path $args[0])
    {
    
            $Dir=$args[0]
    
            #ftp server
            $ftp = "ftp://ftp.server.com/dir/"
            $user = "user"
            $pass = "Pass"
    
            $webclient = New-Object System.Net.WebClient
    
            $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
    
            #list every sql server trace file
            foreach($item in (dir $Dir "*.trc")){
                    "Uploading $item..."
                    $uri = New-Object System.Uri($ftp+$item.Name)
                    $webclient.UploadFile($uri, $item.FullName)
             }
    }
    

    Unter-Windows kann man auch das BitsTransfer-Cmdlet benutzen. Muss mit Import-Module BitsTransfer in die PS geladen werden (PS V. 2.0). Siehe dazu auch http://msdn.microsoft.com/en-us/library/ee663885%28v=VS.85%29.aspx

  • Übersicht über laufende Dienste

    Verschaffen Sie sich einen Überblick über die laufenden Prozesse. Falls die Prozesse einen bestimmten Namen besitzen, stoppen Sie diese Prozesse bzw. geben das Wort “Gefunden <Dienstname> aus.

    Erweitern Sie das Skript, indem Sie die laufenden Dienste in eine Datei schreiben, um sie später wie oben bereits geschehen, auszuwerten. Welche Schwierigkeiten können bei diesem Vorhaben auftreten.

    Get-Service | ForEach-Object {
            if($_.ServiceName -match "RpcSs")
            {
                    Stop-Service $_.ServiceName
                    Write-Host "Gefunden: "  $_.Name
            }
    }
    
    Get-Service | Export-Clixml C:\dienste.xml
    foreach ($service in Import-Clixml C:\dienste.xml)
    {
            if($service.ServiceName -match "RpcSs")
            {
                    Write-Host "Gefunden: "  $service.Name
            }
    }
    
  • Schätzen der Festplattenauslastung

    Wie lange wird der Speicherplatz einer Festplatte ausreichen, wenn ihr Inhalt jeden Monat um ca. 7,5% wächst. Die Platte hat eine Kapazität von 2 TBiT, eine Startbelegung von 100 MBiT

    $Zuwachs = 7.5
    $FestplatteMax = 2TB
    $StartKap = 100MB
    $FestplatteCurKap = $StartKap
    $i = 0
    do
    {
    
            $FestplatteCurKap *= 1 + $Zuwachs/100
            $i += 1
            Write-Host "Monat: " $i
    
    }while($FestplatteCurKap -lt $FestplatteMax)
    
    $result = Get-Date
    $result = $result.AddMonths($i)
    $result
    
  • Berechnung des Notendurchnschnitts und Notenverteilung eines Testes

    Ein Test ergab folgende Einzelnoten: 6,3,4,2,1,2,3,4,1,2,3,2,1,3,4,5,3,5,4,3,2,2,2,1,2,3

    Berechnen Sie die Anzahl jeder Note sowie den Durchschnitt

    Die folgende Lösung setzt in einigen Teilen die Pipeline der Powershell ein. Dies hätte auch durch eine weitere Schleife erledigt werden können. Bei der Zuweisung der Häufigkeiten pro Noten wird ein 2. Array eingesetzt, ders ich pro Indexposition (ab 1) die absolute Zahl der jeweiligen Note merkt. In Indexposition 0 wird später der Durchschnitt abgelegt

    $noten_sa1 = 6,3,4,2,1,2,3,4,1,2,3,2,1,3,4,5,3,5,4,3,2,2,2,1,2,3
    $notenwerte = 1,2,3,4,5,6
    $notenstat = 0,0,0,0,0,0,0
    
    1..6 | ForEach{
            $anzahl = 0
            for($i = 0;$i -lt $noten_sa1.length; $i++)
            {
                    if($noten_sa1[$i] -eq $_)
                    {
                            Write-Host "Note "  $_ "vorhanden an Position " + ($i + 1)
                            $anzahl++
                    }
                    else
                    {
                            Write-Host "Note nicht vorhanden"
                    }
            }
            $notenstat[$_] = $anzahl
    
    }
    Write-Host $notenstat
    
    $durchschnitt = 0
    $quersumme=0
    for ($i = 1; $i -lt $notenstat.length;$i++)
    {
            $quersumme += $notenstat[$i]*$i
    }
    $durchschnitt = $quersumme / $noten_sa1.length
    $notenstat[0] = $durchschnitt
    $quersumme
    $durchschnitt
    

    Eine weitere und vielleicht elegantere Möglichkeit wäre die Verwendung einer Hashmap anstelle des Arrays $notenstat. Damit müsste man die Indexpositionen nicht missbrauchen, sondern könnte die Noten als Key und die Anzahl als Values einsetzen.

    Eine Lösungsansatz:

    $noten_sa1 = 6,3,4,2,1,2,3,4,1,2,3,2,1,3,4,5,3,5,4,3,2,2,2,1,2,3
    $notenwerte = 1,2,3,4,5,6
    $notenhash = @{}
    
    1..6 | ForEach{
            $anzahl = 0
            for($i = 0;$i -lt $noten_sa1.length; $i++)
            {
                    if($noten_sa1[$i] -eq $_)
                    {
                            #Write-Host "Note "  $_ "vorhanden an Position " + ($i + 1)
                            $anzahl++
                    }
                    else
                    {
                            # Write-Host "Note nicht vorhanden"
                    }
            }
            $notenhash.Add($_, $anzahl)
    }
    
    $durchschnitt = 0
    $quersumme = 0
    foreach($key in $notenhash.get_Keys())
    {
            Write-Host $key $notenhash[$key]
            $quersumme += $key * $notenhash[$key]
    }
    $durchschnitt = $quersumme / $noten_sa1.length
    $durchschnitt
    

14.8. Struktogramm

14.9. Funktionen

  • Schreiben Sie eine Funktion, die als Parameter einen Pfad erwartet und anschließend den Inhalt des Pfades ausgibt

    function listDirectory($pfad)
    {
    
    cd $pfad
    Dir $pfad |Out-File  C:\temp\Ausgabe.txt
    
    }
    
  • Erweitern Sie die obige Funktion um eine rekursive Variante. Sollte der Pfad Unterordner besitzen, sollen auch diese ausgegeben werden.

    function listDirectory($pfad)
    {
    
    cd $pfad
    Dir $pfad -recurse |Out-File  C:\temp\Ausgabe.txt
    
    }
    
  • Erweitern Sie die obige Funktion: Es soll jetzt möglich sein, nach bestimmten Dateikennungen die Ausgabe zu gestalten

    function listDirectory($pfad, $ext)
    {
            cd $pfad
            Dir $pfad -Recurse  -include *.$ext |Out-File  C:\temp\Ausgabe.txt
    }
    
  • Wie überprüfen Sie, ob ein Array einen bestimmten Wert enthält

    Folgende Funktion überprüft zwei Arrays auf Gleichheit

    function AreArraysEqual($a1, $a2) {
            if ($a1 -isnot [array] -or $a2 -isnot [array]) {
              throw "Both inputs must be an array"
            }
            if ($a1.Rank -ne $a2.Rank) {
              return $false
            }
            if ([System.Object]::ReferenceEquals($a1, $a2)) {
              return $true
            }
            for ($r = 0; $r -lt $a1.Rank; $r++) {
              if ($a1.GetLength($r) -ne $a2.GetLength($r)) {
                            return $false
              }
            }
    
            $enum1 = $a1.GetEnumerator()
            $enum2 = $a2.GetEnumerator()
    
            while ($enum1.MoveNext() -and $enum2.MoveNext()) {
              if ($enum1.Current -ne $enum2.Current) {
                            return $false
              }
            }
            return $true
    }
    
  • Folgendes Powershell-Skript berechnet den Wochentag mit Hilfe eines eigenen Algorythmus. Verbessern Sie die Lesbarkeit des Skriptes, indem Sie die verschiedenen Teile des Quellcode mit Hilfe von Funktionen kapseln.

    <#
    .SYNOPSIS
    Fragt nach dem Teil eines Datums
    
    .DESCRIPTION
    Dient zum Erfassen der Bestandteile eines Datums. Macht keine Sicherheitsüberprüfungen
    
    .PARAMETER Frage
    Specifiziert die dem User zu stellende Frage.
    
    .OUTPUTS
    System.String. Gibt die von der Eingabeaufforderung übergebenen Zeichen zurück
    
    .LINK
    Read-Host
    #>
    function get-DatumsTeil([string]$Frage)
    {
            return Read-Host -prompt $Frage
    }
    
    
    function set-Monat()
    {
            if($m -le 2)
            {
               $m += 10;
                    $j -= 1;
            }
            else
            {
               $m -= 2;
            }
    
            [int]$c = $j/100;
            [int]$y = $j%100;
    
            [int]$h = (((26 * $m -2)/10) + $t + $y + $y/4 + $c/4 -2 * $c)%7
    
            if($h -lt 0)
            {
                    $h +=7;
            }
    
            return $h
    }
    
    
    function get-Day($value)
    {
       [string]$Tag = "";
            switch($h)
            {
               0 { $Tag = "Sonntag"; break}
    
               1 { $Tag = "Montag"; break}
    
               2 { $Tag = "Dienstag"; break}
    
               3 { $Tag = "Mittwoch"; break}
    
               4 { $Tag = "Donnerstag";break}
    
               5 { $Tag = "Freitag"; break}
    
               6 { $Tag = "Samstag"; break}
            }
    
            return $Tag
    }
    
    
    $t = get-DatumsTeil("Geben Sie den Tag ein")
    $m = get-DatumsTeil("Geben Sie den  Monat ein")
    $j = get-DatumsTeil("Geben Sie das Jahr ein")
    
    $MerkeMonat = $m
    $h = set-Monat
    $Tag = get-Day($h)
    Write-Host "Der " + $t +"." + $MerkeMonat + "." + $j + " ist ein " + $Tag
    
  • Schreiben Sie eine Funktion, die ihnen die Größe des vorhandenen physikalischen und virtuellen RAMs ausgibt. Benutzen Sie zum Ermitteln der Größe die WMI-Klasse WIN32_OperatingSystem und deren Eigenschaften FreePhysicalMemory sowie FreeVirtualMemory. Als kleine “Zugabe” möchten Sie die Angabe der Größe in verschiedenen Formaten (Byte, KByte, MByte) ermöglichen.

function get-memory ([string]$units = "b") {
         $comp = get-wmiobject Win32_OperatingSystem
         $mem = $comp.FreePhysicalMemory + $comp.FreeVirtualMemory
         switch ($units) {
                  "b" {$mem}
                  "k" {[int]($mem / 1024)}
                  "m" {[int](($mem * 100) / 1048576) / 100}
         }
}
  • Schreiben Sie eine Funktion zum Umbenennen eines Computernamens. Der Name soll entweder per Eingabeaufforderung übergeben werden können oder aus einer Textdatei gelesen werden, falls keine Eingabe vorgenommen wird. Kommentieren Sie die Funktion über die Powershell-typische Hilfesyntax. Prüfen Sie innerhalb der Funktion, ob Sie überhaupt die administrativen Rechte für die Umbenennung haben. Zum Abschluss des Vorgangs müssen Sie einen Reboot vornehmen.

siehe: http://www.gangleri.net/2009/11/25/ChangingComputerNameAndWorkgroupWithPowerShell.aspx

function Set-ComputerName
{
        <#
        .SYNOPSIS
                Sets the name of the computer
        .DESCRIPTION
                Uses WMI to set the name of the computer, if the name is successfully changed the user will be prompted to reboot and apply the changes
        .NOTES
                File Name: ComputerName.psm1
                Aurthor: Alan Bradley
                Requires: PowerShell 2.0
        .LINK
                http://www.gangleri.net
        .EXAMPLE
                Set-ComputerName -Name "{New name for computer}"
        .EXAMPLE
                Set-ComputerName "{New name for computer}"
        .EXAMPLE
                Set-ComputerName -Name "{New name for computer}" -AutoReboot
        .EXAMPLE
                Set-ComputerName "{New name for computer}" -AutoReboot
        .PARAMETER Name
                The new name that the computer will be known by
        #>
        param(
                [Parameter(Position=0, Mandatory=$true,ParameterSetName="Name")]
                [string]$Name,
                [Switch]$AutoReboot
        )
        process
        {
                $sysInfo = Get-WmiObject -Class Win32_ComputerSystem
                $result = $sysInfo.Rename($Name)

                switch($result.ReturnValue)
                {
                        0
                        {
                                Write-Host -ForegroundColor Green "Success"
                                if($AutoReboot -eq $false)
                                {
                                        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes",
                                                "Reboots the machine."
                                        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No",
                                                "Does not reboot the machine, you will manually have to reboot this machine for changes to take effect."
                                        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
                                        $ShouldReboot = $Host.UI.PromptForChoice("Reboot machine",
                                                "You must reboot for change to take effect. Do you want to reboot now?", $options, 0)
                                }
                                if($ShouldReboot -eq 0 -or $AutoReboot -eq $true)
                                {
                                        Restart-Computer
                                }
                        }
                        5 { Write-Host -ForegroundColor Red "This cmdlet must be execute with administrative privileges" }
                        default { Write-Host -ForegroundColor Red "Error" }
                }
        }
}
<#
.SYNOPSIS
        Renames a computer
.DESCRIPTION
        This Script will rename a computer by passing the oldComputername and the new Computername. If no names are given, a textfile will be openend
.EXAMPLE
        .\Set-Computername.ps1 'oldName' 'newName'
.PARAMETER originalPCName
        Old name of the computer
.PARAMETER computerName
        new name of the computer
.NOTES
        FileName     : Download-File.ps1
        Author       : Steinam
        LastModified : 06 Apr 2011 9:39 AM PST
#Requires -Version 2.0
#>
function Set-ComputerName {
        param([switch]$help,
                  [string]$originalPCName=$(read-host "Please specify the current name of the computer"),
                  [string]$computerName=$(read-host "Please specify the new name of the computer"))

        $usage = "set-ComputerName -originalPCname CurrentName -computername AnewName"
        if ($help) {Write-Host $usage;break}

        $computer = Get-WmiObject Win32_ComputerSystem -OriginalPCname OriginalName -computername $originalPCName
        $computer.Rename($computerName)
        }


        #set-Computername
        $computer = Get-WmiObject Win32_ComputerSystem
        $computer | Format-List -Property N*
  • Powershell kann mit Hilfe des CommandLets Get-Eventlog die Ereignisanzeige von lokalen und remote-Computern anzeigen und filtern. Schreiben Sie eine Funktion getLogInfos, die Ihnen folgende Auswahlmöglichkeiten zulässt:
    • Wahl des Computers
    • Wahl des jeweiligen EventLogs
    • Wahl des jeweiligen Eintrags, z.B. Error, Warnig, Information

    Informieren Sie sich mit Hilfe von get-help über die weiteren Möglichkeiten von Get-Eventlog

    function getLogInfo([string]$Computer=".", [string]$EventLog, [string]$ErrorType)
    {
    
    
    }
    
  • Verändern von Attributen einer Datei

    Sie haben als Administrator einige Dateien, auf die sie von Zeit zu Zeit zugreifen müssen. Um die Dateien vor versehentlichen Änderungen zu schützen, versehen Sie diese mit ReadOnly - Flag. Leider ist aber jetzt ein Bearbeiten dieser Dateien mühsam, weil Sie nun immer erst dieses Flag ändern müssen.

    Schreiben Sie ein parametrisiertes Skript, welches alle Dateien eines Ordners ReadOnly bzw. Nicht-ReadOnly setzen kann. Schreiben Sie zusätzlich eine Funktion, die Ihnen alle Dateien mit ReadOnly-Flag auflistet. Eine Hilfe-Funktion soll Sie bei einer falschen Eingabe unterstützen.

     http://blogs.technet.com/b/heyscriptingguy/archive/2009/09/24/hey-scripting-guy-september-24-2009.aspx
    
     Param ([string]$path='c:\fso',
    [switch]$get,
    [switch]$clear,
    [switch]$set,
    [switch]$help
     )#end param
    
     # *** Functions here ***
    
     Function Get-ReadOnlyFiles([string]$path)
     {
      "Getting readonly attribute on files in $path"
      Get-ChildItem -Path $path |
      Where-Object { $_.attributes -match 'readonly' }
     } #end get-Readonlyfiles
    
     Function Clear-ReadOnlyFiles([string]$path)
     {
       "Clearing readonly attribute from files in $path"
      New-Variable -Name read_only -Value 1 -Option readonly
      Get-ChildItem -Path $path |
      Where-Object { $_.attributes -match 'readonly' } |
      ForEach-Object {
        $_.attributes = $_.attributes -Bxor $read_only }
     }#end Clear-ReadonlyFiles
    
     Function Set-ReadOnlyFiles([string]$path)
     {
      "Setting readonly attribute on files in $path"
      New-Variable -Name read_only -Value 1 -Option readonly
      Get-ChildItem -Path $path |
      ForEach-Object {
        $_.IsReadOnly = $True
      }
     }#end Set-ReadOnlyFiles
    
     Function Get-HelpText
     {
      $helpText = @"
       WorkWithReadOnlyFiles.ps1 -path c:\fso -get
       Gets a list of all readonly files in c:\fso folder
    
       WorkWithReadOnlyFiles.ps1 -path c:\fso -set
       Sets all files in the c:\fso folder to readonly
    
       WorkWithReadOnlyFiles.ps1 -path c:\fso -clear
       Clears the readonly attribute from all files in c:\fso folder
     "@
      $helpText
     }#end Get-HelpText
    
    
     # *** Entry Point to Script ***
     #$clear = $true
     if($help) { Get-HelpText ; exit }
     if(!$path) { "A path is required." ; Get-HelpText ; exit }
     if($get) { Get-ReadOnlyFiles -path $path ; exit }
     if($clear) { Clear-ReadOnlyFiles -path $path ; exit }
     if($set) { Set-ReadonlyFiles -path $path ; exit }
    
  • Ein Außendienstmitarbeiter erhält ein neues Firmen-Laptop. Auf seinem alten Laptop sind viele WLAN-Profile gespeichert und Sie suchen einen Weg, um diese Profile auf den neuen Rechner ohne manuelles Neuanlegen zu übernehmen. Ein Kollege erzählt Ihnen, dass Sie mit Hilfe des Befehls netsh Profile sowie exportieren als auch importieren können.

    • Informieren Sie sich über die Möglichkeiten des Befehls netsh

    • Schreiben Sie ein Skript, welches sowohl den Export als auch den Import der WLAN-Profile ermöglicht.

      function Export-WLAN {
      <#
      .SYNOPSIS
              Exports all-user WLAN profiles
      .DESCRIPTION
              Exports all-user WLAN profiles to Xml-files to the specified directory using netsh.exe
      .PARAMETER XmlDirectory
              Directory to export Xml configuration-files to
      .EXAMPLE
              Export-WLAN -XmlDirectory c:\temp\wlan
      #>
      
      [CmdletBinding()]
              param (
                      [parameter(Mandatory=$true)]
                      [string]$XmlDirectory
                      )
      
      #Export all WLAN profiles to specified directory
      $wlans = netsh wlan show profiles | Select-String -Pattern "Profil für alle Benutzer" | Foreach-Object {$_.ToString()}
      $exportdata = $wlans | Foreach-Object {$_.Replace("    Profil für alle Benutzer : ",$null)}
      $exportdata | ForEach-Object {netsh wlan export profile $_ $XmlDirectory}
      }
      
      function Import-WLAN {
      <#
      .SYNOPSIS
              Imports all-user WLAN profiles based on Xml-files in the specified directory
      .DESCRIPTION
              Imports all-user WLAN profiles based on Xml-files in the specified directory using netsh.exe
      .PARAMETER XmlDirectory
              Directory to import Xml configuration-files from
      .EXAMPLE
              Import-WLAN -XmlDirectory c:\temp\wlan
      #>
      
      [CmdletBinding()]
              param (
                      [parameter(Mandatory=$true)]
                      [string]$XmlDirectory
                      )
      
      #Import all WLAN Xml-files from specified directory
      Get-ChildItem $XmlDirectory | Where-Object {$_.extension -eq ".xml"} | ForEach-Object {netsh wlan add profile filename=($XmlDirectory+"\"+$_.name)}
      }
      
  • Aufruf von Remote-Desktop-Sitzungen

    Erstellen Sie ein Skript, welches eine rdp-Verbindung unter Berücksichtigung verschiedener Optionen des mstsc-Befehls ermöglicht.

    ########################################################################################################################
        # NAME
        #     Start-RDP
        #
        # SYNOPSIS
        #     Opens a remote desktop connection to another computer.
        #
        # SYNTAX
        #     Start-RDP [[-Server] <string>] [[-Width] <int>] [[-Height] <int>]
        #     Start-RDP -Path <string> [[-Width] <int>] [[-Height] <int>]
        #
        # DETAILED DESCRIPTION
        #     The Start-RDP cmdlet opens a new Remote Desktop connection using the Microsoft Terminal Services Client.
        #     Connection settings can be specified by argument or read from a standard RDP file.
        #
        # PARAMETERS
        #     -Server <string>
        #         Specifies the name of the server to connect to.  May also include an IP address, domain, and/or port.
        #
        #         Required?                    false
        #         Position?                    1
        #         Default value
        #         Accept pipeline input?       true
        #         Accept wildcard characters?  false
        #
        #     -Width <int>
        #         Specifies the desired width of the resolution for the connection (for non-full screen connections).
        #
        #         Required?                    false
        #         Position?                    2
        #         Default value
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        #     -Height <int>
        #         Specifies the desired height of the resolution for the connection (for non-full screen connections).
        #
        #         Required?                    false
        #         Position?                    3
        #         Default value
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        #     -Path <string>
        #         Specifies the path to an RDP file to connect with (resolution settings can be overridden using the
        #         -Width and -Height parameters.
        #
        #         Required?                    false
        #         Position?                    4
        #         Default value
        #         Accept pipeline input?       true
        #         Accept wildcard characters?  false
        #
        #     -Console <SwitchParameter>
        #         Connect to a Windows Server 2003 console session.
        #
        #         Required?                    false
        #         Position?                    named
        #         Default value                false
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        #     -Admin <SwitchParameter>
        #         Connect to a Windows Server 2008 administrator session.
        #
        #         Required?                    false
        #         Position?                    named
        #         Default value                false
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        #     -Fullscreen <SwitchParameter>
        #         Open connection in full screen mode.
        #
        #         Required?                    false
        #         Position?                    named
        #         Default value                false
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        #     -Public <SwitchParameter>
        #         Run Remote Desktop in public mode.
        #
        #         Required?                    false
        #         Position?                    named
        #         Default value                false
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        #     -Span <SwitchParameter>
        #         Span the Remote Desktop connection across multiple monitors.  Each monitor must have the same height
        #         and be arranged vertically.
        #
        #         Required?                    false
        #         Position?                    named
        #         Default value                false
        #         Accept pipeline input?       false
        #         Accept wildcard characters?  false
        #
        # INPUT TYPE
        #     String,System.IO.FileInfo
        #
        # RETURN TYPE
        #
        #
        # NOTES
        #
        #     -------------------------- EXAMPLE 1 --------------------------
        #
        #     C:\PS>Start-RDP
        #
        #
        #     This command opens the Terminal Services Client connection dialog to specify a connection.
        #
        #
        #     -------------------------- EXAMPLE 2 --------------------------
        #
        #     C:\PS>Start-RDP -Server myserver -Width 1024 -Height 768
        #
        #
        #     This command opens a new Remote Desktop connection to the server named "myserver" in a window with 1024x768 resolution.
        #
        #
        #     -------------------------- EXAMPLE 3 --------------------------
        #
        #     C:\PS>Start-RDP -Server myserver -Fullscreen
        #
        #
        #     This command opens a new full screen Remote Desktop connection to the server named "myserver".
        #
        #
        #     -------------------------- EXAMPLE 4 --------------------------
        #
        #     C:\PS>Start-RDP -Path C:\myserver.rdp
        #
        #
        #     This command opens a new Remote Desktop connection using the specified RDP file.
        #
        #
    
        #Function global:Start-RDP {
                param(
                        [string]$Server = "",
                        [int]$Width = "",
                        [int]$Height = "",
                        [string]$Path = "",
                        [switch]$Console,
                        [switch]$Admin,
                        [switch]$Fullscreen,
                        [switch]$Public,
                        [switch]$Span
                )
    
                begin {
                        $arguments = ""
                        $dimensions = ""
                        $processed = $false
    
                        if ($admin) {
                                $arguments += "/admin "
                        } elseif ($console) {
                                $arguments += "/console "
                        }
                        if ($fullscreen) {
                                $arguments += "/f "
                        }
                        if ($public) {
                                $arguments += "/public "
                        }
                        if ($span) {
                                $arguments += "/span "
                        }
    
                        if ($width -and $height) {
                                $dimensions = "/w:$width /h:$height"
                        }
                }
    
                process {
                        Function script:executePath([string]$path) {
                                Invoke-Expression "mstsc.exe '$path' $dimensions $arguments"
                        }
                        Function script:executeArguments([string]$Server) {
                                Invoke-Expression "mstsc.exe /v:$server $dimensions $arguments"
                        }
    
                        if ($_) {
                                if ($_ -is [string]) {
                                        if ($_ -imatch '\.rdp$') {
                                                if (Test-Path $_) {
                                                        executePath $_
                                                        $processed = $true
                                                } else {
                                                        throw "Path does not exist."
                                                }
                                        } else {
                                                executeArguments $_
                                                $processed = $true
                                        }
                                } elseif ($_ -is [System.IO.FileInfo]) {
                                        if (Test-Path $_.FullName) {
                                                executePath $_.FullName
                                                $processed = $true
                                        } else {
                                                throw "Path does not exist."
                                        }
                                } elseif ($_.Path) {
                                        if (Test-Path $_.Path) {
                                                executePath $_.Path
                                                $processed = $true
                                        } else {
                                                throw "Path does not exist."
                                        }
                                } elseif ($_.DnsName) {
                                        executeArguments $_.DnsName
                                        $processed = $true
                                } elseif ($_.Server) {
                                        executeArguments $_.Server
                                        $processed = $true
                                } elseif ($_.ServerName) {
                                        executeArguments $_.ServerName
                                        $processed = $true
                                } elseif ($_.Name) {
                                        executeArguments $_.Name
                                        $processed = $true
                                }
                        }
                }
    
                end {
                        if ($path) {
                                if (Test-Path $path) {
                                        Invoke-Expression "mstsc.exe '$path' $dimensions $arguments"
    
                                } else {
                                        throw "Path does not exist."
                                }
                        } elseif ($server) {
                                Invoke-Expression "mstsc.exe /v:$server $dimensions $arguments"
                        } elseif (-not $processed) {
                                Invoke-Expression "mstsc.exe $dimensions $arguments"
                        }
                }
        #}
    
  • Setzen Sie mit Hilfe der PS die IP-Adresse eines Rechners. Geben Sie auch die Daten für Gateway, SN-Mask, NIC, DNS-Server

            # corrected version - $mask variable corrected to match in both places
            function Set-IPAddress {
        param(  [string]$networkinterface =$(read-host "Enter the name
                        of the NIC (ie Local Area Connection)"),
                        [string]$ip = $(read-host "Enter an IP Address (ie 10.10.10.10)"),
                        [string]$mask = $(read-host "Enter the subnet mask (ie 255.255.255.0)"),
                        [string]$gateway = $(read-host "Enter the current name of the NIC you want to rename"),
                        [string]$dns1 = $(read-host "Enter the first DNS Server (ie 10.2.0.28)"),
                        [string]$dns2,
                        [string]$registerDns = "TRUE"
                        )
    
                        $dns = $dns1
        if($dns2){$dns ="$dns1,$dns2"}
        $index = (gwmi Win32_NetworkAdapter | where {$_.netconnectionid -eq $networkinterface}).InterfaceIndex
        $NetInterface = Get-WmiObject Win32_NetworkAdapterConfiguration | where {$_.InterfaceIndex -eq $index}
        $NetInterface.EnableStatic($ip, $mask)
        $NetInterface.SetGateways($gateway)
        $NetInterface.SetDNSServerSearchOrder($dns)
        $NetInterface.SetDynamicDNSRegistration($registerDns)
    
    }
    
  • Mit Hilfe des Befehls net view \UNC-Name können Sie die Freigaben eines Rechners ermitteln. Schreiben Sie eine Funktion, die als Parameter einen UNC-Namen und einen speziellen Freigabetyp erwartet. Die Funktion soll dann die gefundenen Freigaben zurückgeben.

function Get-ShareNames([string]$server, [string]$ShareType)
{
<#
        .SYNOPSIS
                Get-Sharenames

        .DESCRIPTION
                Gets all printers from specified server
                using intern the net view command

        .Parameter Server
                Specified Servername who holds the shares

        .Parameter ShareType
                Specify type of shares, e.g. "Drucker" or "Platte"


#>

        $result = net view $server | Select-String $ShareType
        #$result = net view "\\win-srv11" | Select-String "Drucker"

        $ausgabe = @()


        foreach($element in $result)
        {
                 #nächste Zeile ist notwendig, da $element kein string
                 #sondern ein matchInfo-Objekt ist
                 #Wahrscheinlich wegen dem Select-String-ComandLet
                 $zeile = $element.toString()
                 $name = $zeile.split("Drucker")
                 $ergebnis = $name[0].TrimEnd()
                 $ausgabe += $ergebnis
        }


        return $ausgabe

}


Get-Sharenames "\\win-srv11" "Drucker"


Get-ShareNames

14.10. Pipeline

  • Virtual Memory

    Get-Process | Sort-Object WorkingSet | Select-Object -First 5
    
  • Largest File

    Get-ChildItem -Recurse | Where-Object { $_.Length -gt 10MB } |
    Sort-Object Length -Descending | Select-Object -First 10
    
  • Foreach: Foreach-Objekt besrbeitet die Elemente der Pipeline sofort

    # ForEach-Object lists each element in a pipeline:
    Dir C:\ -recurse | ForEach-Object { $_.name }
    
  • Alias:

    Get-Alias | where-object { $_.definition -eq "get-process" }
    
  • 20 MByte-Prozesse

    get-process | where-object {$_.WorkingSet64 -gt 20MB }
    ps | ? {$_.ws -gt 20MB }
    
  • Sortiert nach Größee

    ps | ? {$_.ws -gt 20MB } | sort ws
    
  • Ausgabe Produktversion

    ps | select company, name, product, productversion
    
  • Dateien

    Get-Childitem h:\daten -filter *.doc -r
    | Where-Object { $_.Length -gt 40000 }
    | Select-Object Name, Length
    | Sort-Object Length
    | export-csv p:\GrosseWordDateien.csv -notype
    
  • Geben Sie alle Unterordner bis zu einer bestimmten Tiefe aus, ausgehend vom jeweils aktuellen Ordner

$Cred = New-Object System.Management.Automation.PSCredential “Administrator”, $Pw

gci -recurse | ? {$_.PSisContainer -eq $true} | where{
       if(($_.fullname.split("\")).count -le 4)
       {
               write-host $_.fullname
       }
}
  • Sie wollen prüfen, ob auf bestimmten Rechnern innerhalb ihres LANs Software bestimmter Hersteller vorhanden ist. Schreiben Sie ein entsprechendes Skript

    ########################################
    # The PowerShell script inventories the installed software
    # of a producer on n computer systems
    # (C) Dr. Holger Schwichtenberg
    ########################################
    $Producer = "*Microsoft*"
    $EntryFilename = "computernames.txt"
    $OutputFilename = "Softwareinventory.csv"
    $pw = Read-Host -AsSecureString
    
    
    
    
    # Import of computer names
    $Computernames = Get-Content "computernames.txt"
    $Computernames | foreach {
           if (Ping($_))
           {
                   Write-Host "Inventorize software for computer $_ ..."
                   # Fetching of installed MSI packages on all computers
    
                   $Cred = New-Object System.Management.Automation.PSCredential $_\Administrator, $Pw
    
                   $Software = foreach { get-wmiobject win32_product -computername $_ -credential $Cred }
                   | where { $_.vendor -like $Producer }
                   # Export in CSV
                   $Software | export-csv $OutputFileName -notypeinformation
           }
           else
           {
                   Write-Error "Computer not accessible!"
           }
    }
    # Execute Ping
    function Ping
    {
           $status = Get-WmiObject Win32_PingStatus -�lter "Address='$args[0]'" |
           select StatusCode
           return $status.Statuscode -eq 0
    }
    

Das Skript ist in mehrere Teile gegliedert:

  1. Function Ping

    # Execute Ping
    function Ping
    {
           $status = Get-WmiObject Win32_PingStatus -�lter "Address='$args[0]'" |
           select StatusCode
           return $status.Statuscode -eq 0
    }
    

    Erhält als Parameter einen Computernamen, ermittelt den Statuscode und gibt true zurück, wenn der Computer erreichbar ist

  2. Einstieg in das Skript

    $Producer = "*Microsoft*"
    $Entry�lename = "computernames.txt"
    $Output�lename = "Softwareinventory.csv"
    # Import of computer names
    $Computernames = Get-Content "computernames.txt"
    

    Definition von einigen Variablen Lesen der zu überprüfenden Computernamen aus einer Textdatei

  3. Informationsbeschaffung

    $Computernames | foreach {
      if (Ping($_))
      {
            Write-Host "Inventorize software for computer $_ ..."
            # Fetching of installed MSI packages on all computers
            $Software = foreach { get-wmiobject win32_product -computername $_ }
            | where { $_.vendor -like $Producer }
            # Export in CSV
            $Software | export-csv "Softwareinventar.csv" -notypeinformation
      }
      else
      {
            Write-Error "Computer not accessible!"
      }
    }
    

    Über eine Pipeline werden die Computernamen nacheinander aufgerufen Bei erfolgreichem Ping wird per WMI der Remote-Computer auf das Vorhandensein des Herstellernamens abgefragt. Bei Vorhandensein wird es als Ergebnis in eine CSV-Datei geschrieben.

  • Erweitern Sie obiges Skript um die Abfrage nach bestimmten Softwarenamen bzw. Versionsständen.

    function Get-IsInstall($Application, $Computer, $Version)
    {
           $a = (Get-WmiObject -Class Win32_Product -Filter
           "Name='$Application' and Version='$Version'" -computername
           $Computer)
           return ($a -ne $null)
    }
    $e = Get-IsInstall "QuickTime" "E01" "7.2.0.240"
    if ($e)
    {
           "Software is installed!"
    }
    else
    {
           "Software is not installed!"
    }
    
  • I needed to merge 365 CSV files that represent daily weather data sets into one CSV file that contains all the data accumulated during one year. Each of the daily CSV files had a header row. The yearly file should only have one. Filtering out rows is a perfect application of the PowerShell filter functions. Übersetzen Sie den anglischen Text sinngemä߸ und schreiben Sie ein entsprechendes Skript.

This is where PowerShell’s pipeline programming is shining. It only takes a Filter function definition, inserting it into an pre-existing pipeline and you are done.

Here is the sample script:

http://www.tellingmachine.com/post/Using-PowerShell-Filter-functions-to-filter-out-header-rows-CSV-file-merges.aspx

#Filter Function filters out records that start with "Time"
Filter Filter-Header
{
        if($_ -match "^Time")
        {
                $_ | out-null
        }
        else
        {
                $_
        }
}

cd "C:\WeatherStation\FilterTest"

#Initializing yearly file
$YearlyFileName = "Weather2009.csv"
#Set the header only once in the yearly file
Set-Content -Path $YearlyFileName -value "Time,TemperatureF,DewpointF,PressureIn,WindDirectionDegrees,WindSpeedMPH,WindSpeedGustMPH,Humidity,HourlyPrecipIn" -force -encoding "UTF8"

#Open all csv files get-content and add it to the yearly file
$Files = dir -Path "C:\Users\Klaus\Desktop\TO PLANET\WeatherStation\FilterTest" -Filter "*.csv"

#Filter in Action
$Files | ForEach-Object `
{
        Get-Content -Path $_.Name -Encoding "UTF8" | Filter-Header | Add-Content -path $YearlyFileName -Encoding "UTF8"
}
  • Suchen Sie die letzten 2000 Systemereignisse des Eventlogs, die vom Typ “Error” sind

    # PowerShell script to find Error messages in the System eventlog.
    Get-EventLog system -newest 2000 | where {$_.entryType -match "Error"}
    
  • Sie schreiben ein Powershell-Skript, welches eine eigene Ereignisquelle im Eventlog schafft und darunter seine Ereignisse schreibt.

    ## Step 1 - PowerShell Script to create eventlog source by David Stone
    Clear-Host
    if (!(test-path ` HKLM:\SYSTEM\CurrentControlSet\Services\Eventlog\Application\SampleApp )) `
    {new-eventlog -logname Application -source SampleApp `
    -ErrorAction SilentlyContinue}
    
    ## Step 2 - Create a 'Job start' entry in your event log
    $startTime = Get-date
    $startLog = 'Sample job started at ' +$startTime+ ' local time'
    write-eventlog -LogName Application -Message $startLog -Source SampleApp `
    -id 1 -entrytype Information -Category 0
    
    ## Step 3 - A production script would have a payload here.
    
    ## Step 4 - Write errors during processing (typically part of a if statement)
    write-eventLog -LogName Application -Message 'Message content' `
    -Source SampleApp -id 100 -entrytype Warning -category 0
    
    ## Step 5 - Write end of process entry in your event log
    $endTime = Get-date
    $endLog = 'Sample job ended at ' +$endTime+ ' local time'
    write-eventlog -LogName Application -Message $endLog -Source SampleApp `
    -id 9 -entrytype Information -category 0
    
  • Schreiben Sie die Einträge der obigen Quelle in eine CSV-Datei. Es soll nur die jeweils letzte Stunde eingetragen werden

    ## Step 6 - Write the entries to a csv file
    Clear-Host
    $logtime=[DateTime]::Now.AddHours(-1)
    $CSVPath = "C:\SSource.csv"
    Get-EventLog -LogName application -Source 'SampleApp' `
    -EntryType warning -After $logtime `
    | select eventid, machinename, entrytype, source, message, timegenerated `
    | Export-Csv $CSVPath -NoTypeInformation
    
  • A Real-life Example of Select-String

    My practical problem was that I wanted to search for instances a particular string in a directory with hundreds of file. If a file had duplicate entries, then I needed to know.

    The PowerShell problem is how to create a stream of the files, then compare each file with my string value. In the output I needed to know the filename.

    To solve the problem, I employed four main commands, which you can see in the following script:

        Get-ChildItem - recurse
        foreach (loop) {what to do block}
    if (test) {output block}
    select-String -pattern to match my string value.
    
    # A real-life example of PowerShell's Select-String
    $i=0
    $File = Get-ChildItem "C:\html" -include *.html -recurse
    $StringVid = "msbuild"
    foreach ($Entry in $File) {
       $List = select-string -pattern $StringVid $Entry
              if ($List.LongLength -gt 1) {
              "{0,-8} {1,-4} {2,18}" -f
              "Files ", $List.LongLength, $Entry.FullName;
              $i++
              }
    }
    
  • Namensauflösung einer IP-Range

    Die Programmfunktionalität wird mit Hilfe von 2 Funktionen realisiert. Get-ComputerNameByIP zeigt die Verwendung von Fehlerbehandlungscode, Check-Online zeigt die Verwendung von Hintergrundprozessen.

    Als Speicher für die IP-Adressen und Hostnamen wird die Datenstruktur eines Hashes verwendet,

    <#
    .SYNOPSIS
    Gets a computer name
    .DESCRIPTION
    Resolve a computer name using an IP address
    .PARAMETER <paramName>
    $IPAddress
    .EXAMPLE
    Get-ComputerNameByIP "192.168.1.1"
    .AUTHOR
    G.W. Scheppink
    #>
    
    function Get-ComputerNameByIP {
                    param(
                            $IPAddress = $null
                    )
    
                    begin { }
    
                    process {
                            if ($IPAddress -and $_) {
                                    Throw "Please use either pipeline or input parameter"
                                    break
                            } elseif ($IPAddress) {
                                    ([System.Net.Dns]::GetHostbyAddress($IPAddress))
                            } elseif ($_) {
                                    trap [Exception] {
                                            write-warning $_.Exception.Message
                                            continue;
                                    }
                                    [System.Net.Dns]::GetHostbyAddress($_)
                            } else {
                                    $IPAddress = Read-Host "Please supply the IP Address"
                                    [System.Net.Dns]::GetHostbyAddress($IPAddress)
                            }
                    }
    
                    end { }
    
            } # End function
    
            function Check-Online {
                    param(
                            $computername
                    )
    
                    test-connection -count 1 -ComputerName $computername -TimeToLive 5 -asJob |
                    Wait-Job |
                    Receive-Job |
                    Where-Object { $_.StatusCode -eq 0 } |
                    Select-Object -ExpandProperty Address StatusCode
            }
    
            # This code pings an IP segment from 192.168.1.1 to 192.168.1.254 and returns only those IPs that respond.
            CLS
    
            $ip_name = @{}
            $Start = Get-Date
            $ips = 1..254 | ForEach-Object { "192.168.0.$_" }
            $online = Check-Online -computername $ips
            $online
    
            foreach ($PC in $online) {
                    $pcname =  Get-ComputerNameByIP $PC
                    $ip_name+=@{$PC=$pcname.HostName}
            }
    
            $End = Get-Date
            Write-Host "`nStarted at: " $Start
            Write-Host "Ended at: " $End
    
            $ip_name
    
            #umständliches Schreiben der key-value-Paare aus einem Hash heraus
            $ip_name.GetEnumerator() | Sort-Object Name |
            ForEach-Object {"{0} , {1}" -f $_.Name,$_.Value} |
            Add-Content C:\temp\log.csv`
    
  • Laptop oder Desktop

    Sie sind die IT-Leiter einer kleinen mittelständischen Firma. Sie müssen Inventur machen und Sie brauchen dazu die Anzahl der zur Zeit sich im Netz befindlichen Laptop-und Desktop-Computer in ihrer Firma.

    Following is the full script.
    
    <#
    .Synopsis
    
       helper function used by Get-HardwareType
    
    .EXAMPLE
    
       Example of how to use this cmdlet
    #>
    function Is-Laptop {
    
    [CmdletBinding()]
    [OutputType([boolean])]
    
            param
            (
            [Parameter(Mandatory=$true)]
            [string]        $strHostName
            )
    
            $blnResult = $false
            $query = "select __SERVER,ChassisTypes from Win32_SystemEnclosure"
    
    
                    $objWMI = Get-WmiObject -ComputerName $strHostName -Query $query -ErrorAction Stop
    
                    switch ($objWMI.ChassisTypes) {
    
                            9  {$blnResult = $true} # Laptop
                            10 {$blnResult = $true} # Notebook
                            12 {$blnResult = $true} # Docking Station
                            14 {$blnResult = $true} # Sub Notebook
                            default {}
                      }
                      return $blnResult
    
    } # end function
    
    <#
    
    .Synopsis
      function to determine chassis type using a WMI query
    
    .DESCRIPTION
       function to determine chassis type using a WMI query
    
    .EXAMPLE
       "pc01","pc02","pc03" | Get-HardwareType
    #>
    function Get-HardwareType {
    
    [CmdletBinding()]
    [OutputType([psobject])]
    
    Param
    (
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
    $strHostName
    )
    
    process {
    
            try {
    
                    $objHostName = [system.net.dns]::GetHostByName($strHostName)
    
                    $query = "select __SERVER,ChassisTypes from Win32_SystemEnclosure"
    
                            if (Test-Connection -ComputerName $objHostName.HostName -count 1 -erroraction silentlycontinue) {
    
                                    try {
    
                                            $objResult = New-Object -TypeName psobject -Property @{HostName=$objHostName.HostName;IsLaptop=(Is-Laptop -strHostName $objHostName.HostName)}
    
                                            return $objResult
    
                                    }
    
                                    catch {
    
                                            "Error trying to query $($objHostName.HostName)"
    
                                    }
    
                       }
    
                       else {
    
                                    write-host "error connecting to $($objHostName.HostName)"
    
                       }
    
            }
    
            catch {
    
                    write-host "Unable to resolve DNS address for $strHostName"
    
            }
    
      }
    
    } # end function
    
    
    $laptopCount = 0
    $desktopCount = 0
    
    $searcher = new-object directoryservices.directorysearcher([ADSI]"","(&(objectcategory=computer)(!operatingsystem=*server*))")
    
    [void]$searcher.PropertiesToLoad.Add("cn")
    $arrMachineName = $searcher.findall() | %{$_.properties.cn}
    
    $result = $arrMachineName | Get-HardwareType
    $result
    
    $result | ForEach-Object {if ($_.islaptop) {$laptopCount++} else {$desktopCount++}}
    
    "Laptop Total: $laptopCount"
    "Desktop Total: $desktopCount"
    
    ## beim Lesen aus Textdatei
    #$result = import-csv C:\temp\laptop_desktop.ps1 | Group-Object {$_.chassis} -noelement
    #$result = import-csv C:\temp\laptop_desktop.ps1 | Group-Object -property chassis -noelement
    
    #$result
    

14.11. Objekte

14.11.1. Aufgabe 1:

 $strComputer = "."

 # Neues leeres Objekt erstellen
 $Infos= New-object -TypeName PSObject

 # Wert an das Objekt anfügen
 Add-Member -InputObject $Infos -Name Manufacturer -Value 1 -MemberType NoteProperty
 # Wert an das Objekt anfügen
 Add-Member -InputObject $Infos -Name Model -Value 2 -MemberType NoteProperty
 # Wert an das Objekt anfügen
 Add-Member -InputObject $Infos -Name Memory -Value 3 -MemberType NoteProperty
 Add-Member -InputObject $Infos -Name BiosDescription -Value 3 -MemberType NoteProperty
 Add-Member -InputObject $Infos -Name SerialNumber -Value 3 -MemberType NoteProperty
 Add-Member -InputObject $Infos -Name OperatingSystem -Value 3 -MemberType NoteProperty

  Function SysInfo($Infos)
  {
      $colItems = Get-WmiObject Win32_ComputerSystem `
      -Namespace "root\CIMV2" -ComputerName $strComputer

      foreach($objItem in $colItems) {
        $Infos.Manufacturer =  $objItem.Manufacturer
        $Infos.Model = $objItem.Model
       $Infos.Memory =  $objItem.TotalPhysicalMemory
      }
   }

   Function BIOSInfo($Infos)
   {

      $colItems = Get-WmiObject Win32_BIOS -Namespace "root\CIMV2" `
      -computername $strComputer
      foreach($objItem in $colItems) {
              $Infos.BiosDescription = $objItem.Description
              $Infos.SerialNumber =  $objItem.SerialNumber
      }
   }


   Function OSInfo($Infos)
   {
      $colItems = Get-WmiObject Win32_OperatingSystem -Namespace ` "root\CIMV2" -Computername $strComputer

      foreach($objItem in $colItems) {
              $Infos.OperatingSystem =  $objItem.Name
      }
  }



 #*=============================================================
 #* SCRIPT BODY
 #*=============================================================
 #* Connect to computer


 #* Call SysInfo Function
 Write-Host "Sytem Information"
 SysInfo $Infos


#* Call BIOSinfo Function
Write-Host "System BIOS Information"
BIOSInfo $Infos
Write-Host

#* Call OSInfo Function
Write-Host "Operating System Information"
OSInfo $Infos
Write-Host


$Infos | Select-Object Name, Model

# CSV Export der Daten
Export-Csv -InputObject $Infos -Path "C:\Temp\infos.csv"

 `

14.11.2. Aufgabe 2:

Measure-Command{
$site_urls = Import-CSV C:\temp\weekly_stats.csv

function bla
{

    foreach($url in $site_urls)
    {
        $obj_avg = New-Object -TypeName psobject
        Add-Member -InputObject $obj_avg -MemberType NoteProperty -Name "site_url" -Value $url.site_url
        Add-Member -InputObject $obj_avg -MemberType NoteProperty -Name "url_avg" `
            -Value ([int](([int]$url.monday + [int]$url.tuesday + [int]$url.wednesday + [int]$url.thursday + [int]$url.friday + [int]$url.saturday + [int]$url.sunday)/7))
        $obj_avg
    }

}

bla | Sort-Object url_avg

}




Measure-Command {
$site_urls2 = Import-CSV C:\temp\weekly_stats.csv

$site_urls2 | Select @{name="site_url";expression={$_.site_url}}, `
@{name="avg";expression={([int](([int]$_.monday + [int]$_.tuesday + [int]$_.wednesday + [int]$_.thursday + [int]$_.friday + [int]$_.saturday + [int]$_.sunday)/7))}} | `
Sort-Object avg
}







add-type @"
using System;
public class siteurl{

        public string url = "";
        public double durchschnitt = 0;

        public void seturl(string _url)
        {
            this.url = _url;
        }

        public void avg(int mon, int tue, int wed, int thu, int fri, int sat, int sun)
        {
                this.durchschnitt =  ((monday+tuesday+wednesday+ thursday + friday+ saturday + sunday)/7);
        }
}
"@

Measure-Command {
function bla2
{

$site_urls = Import-CSV C:\temp\weekly_stats.csv

    foreach($url in $site_urls)
    {
        $net_avg = New-Object -typename siteurl
        $net_avg.seturl($url.site_url)
        $net_avg.avg($url.monday,$url.tuesday,$url.wednesday,$url.thursday,$url.friday,$url.saturday,$url.sunday)
        $net_avg
    }

}

bla2 |select url, durchschnitt | Sort-Object durchschnitt
 `

14.11.3. Aufgabe 3:

Gegeben ist folgendes PS-Skript.

Function Get-NetworkConfiguration
{
    param (
        [parameter(
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true,
            Position=0)]
        [Alias('__ServerName', 'Server', 'Computer', 'Name')]
        [string[]]
        $ComputerName = $env:COMPUTERNAME,
        [parameter(Position=1)]
        [System.Management.Automation.PSCredential]
        $Credential
    )
    process
    {
        $WMIParameters = @{
  • Wählen Sie statt der Write-Host-Ausgabe einen objektorientieten Ansatz

    Der foreach-teil muss wie folgt geändert werden:

    foreach ($adapter in (Get-WmiObject @WMIParameters))
    {
        $AdapterProperties = @{
            Server = $adapter.DNSHostName
            Adapter =  $adapter.Description
            IPAddress = $adapter.IpAddress
            SubnetMask = $adapter.IPSubnet
            DefaultGateway = $adapter.DefaultIPGateway
            DNSServers = $adapter.DNSServerSearchOrder
            DNSDomain = $adapter.DNSDomain
        }
    
        New-Object PSObject -Property $AdapterProperties
    }
    
  • Sie wollen nicht alle Informationen ausgeben, sondern beispielsweise nur die IP-Adresse und die Subnet-Maske

    Get-NetworkConfiguration ‘Server1’, ‘Server2’, ‘Server3’ | Format-Table Server, Adapter, SubnetMask, DefaultGateway –auto –wrap
    
  • Können Sie mit diesem Skript mehrere Rechner abfragen ?

    ja

  • Welche Rechner ihres Netzes benutzen den gleichen DNS-Server mit der IP-Adresse *.*.***.***. Eine Liste der Computer erhalten Sie mit Hilfe des CommandLets get-adcomputer

    Get-ADComputer –filter * | Get-NetworkConfiguration | Where-Object {$_.DNSServers –contains $IPofMyTroublesomeDNSServer}
    
  • Wie viele Rechner benutzen den gleichen Default-Gateway

    Get-ADComputer -filter * | Get-NetworkConfiguration | Group-Object DefaultGateway -NoElement
    

14.12. Fehlerbehandlung