PSModule
Bei meinem Projekt "ReportWeb" habe ich überlegt, wie ich Funktionen mehr oder minder dynamisch addieren kann. So bin ich eher spät auf die Module gestoßen, welche ab Powershell Version 2.0 schon vorhanden sind. Hätte ich schon früher deren Potential erkannt, wären einige Powershell-Aufgaben sicher anders umgesetzt worden. In Powershell 1.0 waren nämlich DLLs erforderlich um eine Powershell um eigene Befehle zu erweitern.
Sie konnten aber auch schon immer einfach eine PS1-Datei - erstellen die einfach eine "function" enthielt. Durch den Aufruf dieses Skripts haben Sie dann die Funktion in der aktuelle Session definiert. Problem hierbei war aber, dass alle "Variablen" in diesen Funktionen ebenfalls in ihrer Session definiert waren. Überschneidungen bei Namen können zu unerwarteten Ergebnissen führen. Zudem können die Funktionen eigentlich nicht mehr entfernt werden. Dieses Verfahren wird oft auch als "Dot Source" beschrieben.
Oder sie haben von einem Powershell-Skript ein anderes Skript aufgerufen. Hierbei war das Problem dann aber, dass eine mehrfache Verwendung immer wieder geladen werden muss. Schön ist das nicht.
Basics -Wo und wie
Powershell 2 Module sind einem Powershell Script sehr ähnlich. Sie haben den gleichen Aufbau und können mit den bekannten Editoren erstellt werden und haben einige deutliche Vorteile:
- Einbinden und Entfernen bei
Bedarf
Im Gegensatz zu Funktionen aus Skripten können Module zur Laufzeit einfach eingebunden aber auch wieder entladen werden - Funktionen exportiert
Per Default werden alle Funktionen im Modul exportiert. Dies kann aber über "Export-ModuleMember" im Modul selbst gesteuert werden, so das auch "private Funktionen" möglich sind, die aus der Session nicht gefunden und aufgerufen werden können. "Privat" sind diese natürlich nur hinsichtlich des Code. Der Sourcecode eines PSM1 ist natürlich einsehbar. - Lokale Variablen
Alle in dem Modul verwendeten Variablen sind per Default nicht außerhalb sichtbar.
Interessant ist, dass die Funktionen z.B. z.B. eigene Variablen und Objekte verwenden können und diese zwischen den Aufrufen bestehen bleiben. Es ist damit zwar noch keine Klasse, weil ein Modul nur einmal eingebunden werden kann, aber für viele Zwecke wird oft nur ein "Objekt" verwendet.
Laden, Finden, Sharen
Wenn Sie ein Modul mit "Add-Module" hinzufügen und sie keinen absoluten Pfad mit angeben, dann sucht die Powershell ein PSModulePath ab:
PS C:\> $env:psmodulepath C:\Users\fcarius\Documents\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules\;C:\Program Files\Common Files\Microsoft Lync Server 2010\Modules\
Die Powershell beobachtet dabei die Daten in der folgenden Reihenfolge:
- PSD1 - Manifestdatei
- PSM1 - Skriptmodul
- DLL - Kompiliertes Modul
Ein Modul wird aber immer nur einmal geladen. Gerade wenn Sie Module entwickeln und ändern müssen Sie das Modul in der Testumgebung immer erst entladen und neu laden oder mit "-force" laden. Bestehende Variablen im Modul werden dann aber natürlich zurück gesetzt.
Wenn man gewissenhaft Module in sich abgeschlossen entwickelt, z.B. auch unabhängig von globalen Voraussetzungen, dann können Sie sich eine Bausteinsammlung aufbauen, die sie immer wieder verwenden können.
Module können sogar verschachtelt werden. Schon fast wie wenn Sie ein bestehendes Module durch eigene Funktionen bereichern können. Wenn ein fertiges Modul ihnen zu viele Parameter hat, können Sie einfach ein eigenes Modul nutzen, welche das andere Modul einbindet und ihre lokal gültigen Parameter vorausfüllt. Dabei sind nur die Commandlets des Hauptmoduls erreichbar.
Beispiel
Es gibt viele Beispiele im Internet, die den Einsatz von Modulen zeigen. Ich möchte mich daher auf eine einfaches Modul als Muster beschränken:
# Modulsample to explain basic modules
[long]$script:test=0 # initialize Variable
function add-Modulsample {
$script:test++
write-host "Module1: Sub Plus-Modulsample done: Test=$script:test"
}
function get-Modulsample {
$script:test
write-host "Module1: Sub Get-Modulsample done: Test=$script:test"
}
function Set-Modulsample ($value ){
$script:test = $value
write-host "Module1: Sub Set-Modulsample done: Test=$script:test"
}
# Es ist ratsam am Ende eine Ausgabe zu generieren. Diese wir beim Laden des Moduls angezeigt
write-host "modulsample: Ready to Use"
Auf ein paar Dinge möchte ich hier hinweisen.
- Ausgabe am Anfang/Ende
Wenn Sie außerhalb der Funktionen, die später als Commandlet agieren auch Code verwenden, dann wird dieser beim Laden des Module direkt ausgeführt. Es ist ratsam hier eine Bildschirmausgabe vorzusehen. - Initialisierung
Sie können in dem Code aber auch schon erste Komponenten Initialisieren. Ich nutze dies im Beispiel für die Variable "Test", welche durch das Prefix "$Script:" innerhalb des Skripts als global definiert wird. Sie könnten hier aber auch z.B. SQL-Connections, PSSessions oder ADSI-Verbindungen aufbauen. - Variablen-Scope
Sie sehen hier auch die Feinheiten beim Einsatz von Variablen. "Test" ist global bezüglich des Skripts, sonst könnte ich die Werte nicht in den Funktionen verändern. Die Variable ist aber nicht in der Session erreichbar, welche diese Modul importiert.
Experimentieren Sie einfach etwas mit Modulen und verändern Sie den Beispielcode, um das unterschiedliche Verhalten zu sehen. Vergessen Sie aber nicht nach Änderungen am Modul diese neu zu laden.
Module und Klassen
Noch sind Module einfach weitere Powershell-befehle, die Sie nach dem Import nutzen können. Aber damit sind es noch keine Klassen, die mehrfach instanziert werden können und ihre internen Wert und Funktionen und nach extern erreichbare Properties und Methoden haben. Und genau das geht auch mit Modulen. Sie müssen Sie beim "Import-Module" oder New-Module einfach mit "-AsCustomObject" aufrufen. Damit werden aus den Funktionen entsprechende Methoden und exportierte Variablen werden zu Properties.
Hierbei zeigen sich aber zwei Probleme:
- Methoden sind Funktionen mit
Parametern
Es müssen bei der Methode immer alle Parameter angegeben werden. Die bislang gekannte Flexibilität - Funktionsnamen "Verb-Noun"
funktionieren nicht
Zwar wird das Modul als Objekt mit der Methode mit dem Namen importiert aber ist nicht aufrufbar. Das ist ja auch nicht weiter schlimm, wenn man die Funktionen der Moduls dann einfach umbenennt.
Mit beiden Einschränkungen kann man natürlich leben auch wenn Sie nicht schön sind. Um aber nicht in Konflikt mit anderen Namen zu kommen, sollte so ein Modul dann immer mit dem Parameter "CustomObject" geladen werden.
- Import-Module
http://technet.microsoft.com/fr-fr/library/dd819454.aspx - Importing Modules using -AsCustomObject
http://powershellstation.com/2012/02/08/importing-modules-using-ascustomobject/ - Import Module -
ascustomobject und
Modulparameter in PowerShell
http://www.humbug.in/stackoverflow/de/importing-modules-ascustomobject-and-module-parameters-in-powershell-5307734.html
Weitere Links
Advanced Automation Using
Windows PowerShell 2.0
http://channel9.msdn.com/Events/TechEd/NorthAmerica/2011/WSV406
Einstieg in Module ab 38. Minute
Windows PowerShell Modules
- Patterns and Practices - Dan Harman
http://www.youtube.com/watch?v=yDmkXZVD55w
US TEC 2011 PowerShell Deep Dive conference,
Windows PowerShell Program Manager Dan Harman
Die PowerShell Module
4:28Min
http://www.youtube.com/watch?v=Tmf7EFUXEhg&feature=related
- Powershell Beispiele
- Powershell Klassen
-
PowerShell4Admin
Powershell - Eine Einführung für Admins - PSRemote
- Windows Automation Snapin
for PowerShell
http://wasp.codeplex.com/ - Microcode: All About Modules
(Windows PowerShell CTP2)
http://blogs.msdn.com/b/mediaandmicrocode/archive/2008/08/10/microcode-all-about-modules-windows-powershell-ctp2.aspx - Powerpoint zu Powershell
Module (23 Seiten)
Autor: Bruce Payette,
https://skydrive.live.com/?cid=18d901b0daff5738&id=18D901B0DAFF5738%21225 - Huddled Masses: PowerShell
Modules
http://huddledmasses.org/powershell-modules/ - Introducing the
ScriptingHelp PowerShell Module
http://jdhitsolutions.com/blog/2012/05/introducing-the-scriptinghelp-powershell-module - push-module
http://poshcode.org/1773
push-module will import a powershell v2.0 module and ensure that when the module is removed using remove-module, the functions the module clobbered are restored






