PowerShell – Schnelleinstieg und nützliche Snippets

Powershell Screenshot

Mit der Einführung von PowerShell hat Microsoft einen Ersatz für die Windows-Shell geschaffen, der in seiner Mächtigkeit keine Wünsche offen und die Windows-Shell alt aussehen lässt. Dennoch setzen viele Entwickler noch immer Batch-Scripte ein, um ihre Arbeit zu automatisieren.

Dieser Artikel gibt einen ersten Einstieg in PowerShell und vielleicht auch eine Motivation, um von der alten Windows-Shell auf PowerShell umzusteigen.

PowerShell 1.0 wurde bereits mit Windows Vista vorinstalliert ausgeliefert. Ob PowerShell installiert ist, findet man mit Hilfe des Tastenkürzels [WINDOWS] + [R] und der Eingabe von powershell heraus. Ist PowerShell installiert, erscheint das obligatorische Kommandozeilenfenster. Andernfalls kann das Tool auf der Seite von Microsoft heruntergeladen werden.

Grundlagen

PowerShell-Scripting basiert auf sehr einfachen Prinzipien, so sind zum Beispiel (fast) alle Befehle nach dem Muster Verb-Substantiv aufgebaut. Die Groß- und Kleinschreibung von Befehlen spielt dabei keine Rolle, die PowerShell arbeitet grundsätzlich Case-Insensitive. Das wechseln des Verzeichnisses erfolgt zum Beispiel mit set−location "c:\daten", das Anzeigen von Text in der Konsole über write−host "Hallo Welt!". Wer lieber die alten Bash-Befehle verwenden möchte kann das ebenfalls tun, da PowerShell sogenannte “Aliase” unterstützt. Im obigen Beispiel kann statt set−location "c:\daten" auch einfach nur cd "c:\daten" geschrieben werden. Zu beachten ist, das Zeilen in einem Script nur mit einem Zeilenumbruch, also ohne Semikolon oder ähnlichem beendet werden. Neu ist auch, das (die meisten) PS-Befehle, statt Strings, Objekte zurück liefern. So gibt get−childItem eine Liste von Objekten mit Dateieigenschaften zurück. Kommentarzeilen in PS-Scripten werden mit einer Raute eingeleitet.

Eine weitere Neuerung ist das “chainen” von Befehlen (welches unter Unix schon seit gefühlten 100 Jahren zur Verfügung steht). Damit ist es möglich, Befehlsketten aufzubauen, wobei die Befehle Ihren Rückgabewert an den nachfolgenden Befehl weitergeben. Folgendes Beispiel berechnet die Gesamtgröße aller Dateien in einem Verzeichnis:

get−childItem | measure−object −property length −sum

Die Pipe | verbindet dabei die Befehle miteinander, das Ergebnis von get−childItem wird als Eingangsparameter an measure−object weitergeleitet und entsprechend ausgewertet.

Um das geschrieben Script auszuführen wird in der Konsole einfach ."scriptfile" eingegeben. Dabei kann es jedoch vorkommen, das PowerShell dies mit einer Fehlermeldung zur Sicherheit quittiert. Ja, die PowerShell verfügt sogar über ein eigenes Berechtigungssystem. Um aber die Ausführung von externen Scripten zu erlauben, kann vorher folgender Code ausgeführt werden:

set−executionpolicy Bypass

PowerShell-Scripte besitzen normalerweise die Dateiendung “.ps1”. Versucht man solch ein Script zu starten, öffnet sich entweder die PowerShell-IDE oder schlicht Notepad.exe.Nicht gerade das, was man erwartet. Man kann aber eine Batch-Datei schreiben, welches die PowerShell mit dem eigentlichen Script als Parameter startet:

PowerShell −ExecutionPolicy Bypass &'scriptfile.ps1'

Wir sehen, das wir der PowerShell auch eine gewünschte execution-policy mitgeben können. Somit ersparen wir uns diese Zeile in unserem Script.

Um PowerShell-Scripte nur mit einem Doppelklick und ohne zusätzliche Batch-Datei zu starten, kann auch unser eigenes kleines Tool verwendet werden. Dazu müssen folgende Schritte durchgeführt werden:

  1. powershell_runner.zip herunterladen und entpacken
  2. eine .ps1-Script-Datei suchen und per “Rechtsklick, öffnen mit…”, mit dem “powershell_runner” verbinden. Nicht vergessen, das Häkchen bei “immer mit diesem Programm öffnen” setzen!
  3. (optional, Windows XP) Unter Systemsteuerung, Internetoptionen, Sicherheit, Lokales Intranet, Sites, Erweitert, “file://c” hinzufügen. Damit wird die Sicherheitsmeldung zum Ausführen von Dateien unterdrückt. Wer das interne Sicherheitskonzept nicht aufweichen will, sollte hier nur den Pfad zum Tool angeben.

Dies war nur ein kleiner Anriss der Möglichkeiten von PowerShell. Nachfolgend werden noch nützliche und immer wiederkehrende Snippets aufgelistet.

Nützliche PowerShell-Snippets

Eine externe ps-Scriptdatei blockierend ausführen:

invoke−expression "myscript.ps <[param−name] parameter>"

Argumente für ein Script festlegen:

Param (
[string]$computername = 'defaultvalue',
[string]$basepath = 'c:/'
)

Zu beachten ist, das der Param-Block die erste ausführbare Anweisung in einer Script-Datei sein muss.

Eine Script-Datei inkludieren:

. "C:\dev\ps\common.ps1"

Dateien kopieren:

copy−item −path c:\mypath −destination c:\destpath −recurse −force

−recurse gibt an, das auch alle Unterverzeichnisse mit kopiert werden sollen. −force gibt an, dass keine Rückfragen an den Benutzer gestellt werden. Existiert eine Datei am Zielort, wird diese damit ohne Rückfrage überschrieben.

Prüfen, ob eine Datei schon existiert:

if(test−path c:\mypath) { echo "found" } else { echo "not found" }

Eine ausführbare Datei starten und auf Beendigung warten:

start−process −filepath "c:\myapp.exe" −Wait −NoNewWindow −argumentlist 'myargs'

Wird der Parameter −wait weggelassen, wird die Anwendung nur gestartet und das Script fährt umgehend mit der Abarbeitung fort. −NoNewWindow gibt an, das kein neues Kommandozeilenfenster geöffnet werden soll. Über −argumentList kann die Anwendung mit Parametern aufgerufen werden.

Eingabeprompt erzeugen:

$input = read−host "Bitte geben Sie Ihren Namen ein: "

Ausgabe auf der Konsole:

write−host "hello world!"

Auf einen Tastendruck vom Benutzer warten:

write−host "press any key to continue..."
$voidinput = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

$host.UI.RawUI.ReadKey() ist eine .Net-Funktion und kann direkt mit PowerShell aufgerufen werden (Eine der besten Eigenschaften der PowerShell). Weist man das Ergebnis von ReadKey keiner Variablen zu, wird das KeyDown-event auf der Konsole ausgegeben.

Datei vom Datenträger löschen:

remove−item −path "path" −force

Der Parameter −force gibt auch hier wieder an, dass die Datei ohne Rückfrage gelöscht werden soll.

Strings konkatenieren:

remove−item −path ('C:\myapps\myprojects\' + $directory + '\hello.tmp')

Zu beachten ist, das die Konkatenation geklammert erfolgt, da PS den Ausdruck ansonsten nicht auswerten könnte. Statt der oben gezeigten Konkatenation kann die Variable $directory auch direkt im String verwendet werden. PowerShell löst diese dann korrekt auf.

Verzeichnis erstellen:

new−item −Path "c:\mydir" −itemtype directory

Umgebungsvariablen nutzen:

cd $env:appdata

Aktuelles Verzeichnis abfragen (und ausgeben):

get−location | write−host

Den Pfad zur Scriptdatei ermitteln:

$scriptPath = split−path −parent $MyInvocation.MyCommand.Definition

Funktionen definieren:

function funkyfunc($paramA, $paramB) {
write−host ('funkyfunc invoked with ' + $paramA + ", " + $paramB)
}

… und aufrufen:

funkyfunc "erster param" "zweiter param"

Das Script sofort beenden:

exit

Datei per HTTP-get herunterladen:

(New−Object System.Net.WebClient).DownloadFile('http://www.devlabor.com', 'c:\devlabor.html')

URL-Encode per PowerShell:

$url = [System.Web.HttpUtility]::UrlEncode('?param=42param2=wtf')

Um diese Funktion zu nutzen muss vorher das Assembly System.Web inkludiert werden.

Assembly inkludieren:

Add−Type −AssemblyName System.Web

Den kompletten Inhalt einer Datei lesen:

$content = [IO.File]::ReadAllText('c:\samplefile.txt')

Hash-Tabellen erzeugen:

@{'warnings'='yes';'url'='https://devlabor.com'}

Alle Verzeichnisse auflisten:

$files = get−childitem | where{$_.mode −match "d"}

For-each in PowerShell:

foreach ($file in $files) { write−host $file.fullname }

So, das wäre geschafft, ich denke damit dürfte der Umstieg von alten Windows-Batch-Dateien hin zu PowerShell-Scripten gar nicht mal so schwer fallen! 🙂