Während Sie mit einer PowerShell-Sitzung arbeiten, können Sie ihren Zustand (oder ihre Umgebung) auf verschiedene Weise ändern: Sie können Module importieren, Funktionen erstellen, Aliase angeben oder Variablen definieren, um nur einige zu nennen. Alle diese Änderungen sind jedoch vorübergehend: Ihre Auswirkungen verschwinden, sobald Sie die PowerShell-Sitzung schließen. PowerShell bietet jedoch einen Mechanismus, das so genannte PowerShell-Profil, mit dem Sie solche Umgebungskonstrukte und -einstellungen jedes Mal neu erstellen können, wenn Sie eine neue PowerShell-Sitzung starten. Und wenn ein Profil gut ist, wären dann nicht mehrere besser? Es stellt sich heraus, dass jede einzelne PowerShell-Sitzung eines (oder alle) von vier verschiedenen Profilen verwenden kann, und verschiedene PowerShell-Hosts bieten noch mehr Profilauswahlmöglichkeiten: Aber es ist eigentlich viel einfacher zu verwenden, als es den Anschein hat, wenn man erst einmal weiß, wo all die beweglichen Teile hingehören. Schauen wir uns das mal an.
Die Shell in PowerShell
Es gibt einen Unterschied zwischen der Shell und dem Host in PowerShell. Don Jones erklärt in seinem treffend betitelten Beitrag „The Shell vs. The Host“, dass Sie – als Benutzer, der auf der Tastatur tippt – nicht direkt mit der Shell (oder Engine) der PowerShell interagieren. Vielmehr interagieren Sie mit einer Host-Anwendung (wie powershell.exe oder powershell_ise.exe), die einen Runspace (eine Instanz der PowerShell-Engine) erstellt. Sie können den Unterschied sehen, indem Sie den Inhalt der Eigenschaft Name der Systemvariablen $Host
neben der Variablen $ShellId
anzeigen. Wenn Sie die Werte für die drei gängigsten PowerShell-Hosts untersuchen, sehen Sie, dass sie alle dieselbe Engine (Shell) verwenden, während jeder eine andere Benutzeroberfläche (Host) darstellt.
Host | $Host.Name | $ShellId |
PowerShell | ConsoleHost | Microsoft.PowerShell |
PowerShell ISE | Windows PowerShell ISE Host | Microsoft.PowerShell |
Visual Studio Package Manager Console | Package Manager Host | Microsoft.PowerShell |
Andere PowerShell-Hosts könnten möglicherweise andere $ShellId
-Werte haben (einige der frei verfügbaren PowerShell-IDEs umfassen beispielsweise PowerGUI, PowerShell Analyzer und PowerShell Plus, aber ich habe ihre $ShellId
-Werte nicht überprüft).
Das PowerShell-Profil
Ein PowerShell-Profil ist nichts anderes als ein schicker Name für ein Skript, das beim Start eines PowerShell-Hosts ausgeführt wird. In der Standard-PowerShell-Hilfe zu about_profiles heißt es: „Sie können das Profil als Anmeldeskript verwenden, um die Umgebung anzupassen. Sie können Befehle, Aliase, Funktionen, Variablen, Snap-Ins, Module und Windows PowerShell-Laufwerke hinzufügen. Sie können auch andere sitzungsspezifische Elemente zu Ihrem Profil hinzufügen, damit sie in jeder Sitzung verfügbar sind, ohne dass sie importiert oder neu erstellt werden müssen.“
Jeder PowerShell-Host unterstützt eigentlich zwei Profile, eines auf Benutzerebene, das für jeden Benutzer unterschiedlich ist, und eines auf Systemebene, das für alle Benutzer gilt. Dies ist ein vertrautes Paradigma, das Sie bei vielen Windows-Anwendungen kennen. PowerShell fügt jedoch seine eigene einzigartige Wendung hinzu: Es unterscheidet ebenfalls zwischen Host-Ebene (ein Profil für jeden Host) und Systemebene (ein gemeinsames Profil für alle Hosts).
Ausgehend von allen Kombinationen von Benutzern und Hosts können Sie also potenziell jedes (oder alle) von vier verschiedenen Profilen verwenden:
- AlleBenutzerAlleHosts
- AlleBenutzerAktuellerHost
- AktuellerBenutzerAlleHosts
- AktuellerBenutzerAktuellerHost
Diese Profile existieren alle friedlich nebeneinander, so dass Sie sich der Rangfolge bewusst sein müssen – sie sind oben in der Reihenfolge ihrer Ausführung aufgeführt. Wenn Sie dieselbe Variable in allen vier Profilen definieren, wird die Variable, sobald Sie einen PowerShell-Host starten und schließlich eine Eingabeaufforderung erhalten, den vom letzten Profil zugewiesenen Wert, CurrentUserCurrentHost
, haben, da jedes nacheinander verarbeitete Profil diese Variable mit seinem Wert überschreibt. Ein anderes Beispiel, das eher die Zusammenarbeit zwischen den Profilen als eine Konkurrenzsituation zeigt, ist die Inkrementierung einer Variablen. Definieren und initialisieren Sie sie zunächst in AllUsersAllHosts
auf einen Anfangswert (z.B. $someVar
= 0) und erhöhen Sie sie dann in jedem der anderen Profile (z.B. $someVar++
oder vielleicht $someVar += 5
, je nachdem, was Sie damit machen wollen).
Welches der vier Profile Sie verwenden sollten, hängt weitgehend von Ihren eigenen Bedürfnissen ab: Wenn Sie einen dedizierten Computer verwenden (d.h. nicht mit jemand anderem teilen), brauchen Sie sich nicht um die „Alle Benutzer“-Profile zu kümmern. Wenn Sie mehrere Hosts verwenden, sollten Sie einige Dinge zwischen dem Profil „Alle Hosts“ und einem speziellen Host-Profil unterscheiden. Mehr Details dazu finden Sie weiter unten in „Wie viele Profile benötigen Sie?“
Die $Profile-Variable
Um eines der Profile zu erstellen oder zu bearbeiten, müssen Sie natürlich wissen, wo Sie es finden können. PowerShell selbst kann Ihnen das leicht sagen, aber es kann auch einfach eines zur Bearbeitung öffnen, ohne dass Sie sich explizit um den Pfad kümmern müssen. Um den Pfad zu sehen, zeigen Sie den Wert der Variablen $Profile
an. Sie zeigt einen einzelnen Dateipfad an, der der Pfad zum Profil CurrentUserCurrentHost
ist. In einem Standard-PowerShell-Host zeigt meine Datei Folgendes an:
1
2
|
PS> $Profile
C:\Users\msorens\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
|
Hinweis: Dies sagt nichts darüber aus, ob die Datei existiert, sondern nur, dass dies der Pfad ist, den sie haben muss, wenn sie existiert. Um die Existenz zu prüfen, verwenden Sie Test-Path
:
1
2
|
PS> Test-Pfad $Profil
True
|
Wenn das Profil nicht existiert, können Sie es leicht erstellen:
1
|
PS> New-Item -Type file -Path $Profile -Force
|
Und wenn man das in einem Skript haben möchte, kann man das obige dann kombinieren und die Datei nur bei Bedarf erstellen:
1
2
|
PS> if (!(Test-Pfad $Profil)) {
New-Item -Type file -Path $Profile -Force }
|
Um das Profil schließlich zu bearbeiten, rufen Sie einfach Ihren bevorzugten Editor für die Datei auf, oder Sie können immer den allgegenwärtigen Notepad-Editor verwenden:
1
|
PS> notepad $Profil
|
Alle obigen Beispiele gelten, wie erwähnt, für das „Standard“-Profil (CurrentUserCurrentHost
). Sie können jedoch die gleichen Befehle auf jedes der vier Profile durch einen spezifischen Verweis anwenden; beide führen zum gleichen Ergebnis:
1
2
|
PS> notepad $Profile
PS> notepad $Profile.CurrentUserCurrentHost
|
Ersetzen Sie einen der anderen drei Profileigenschaftsnamen, um auf eines der nicht standardmäßigen Profile zuzugreifen.
Beachten Sie, dass es schwierig sein kann, Dateien in Systemverzeichnissen zu erstellen oder zu speichern (wo die „Alle Benutzer“-Profile gespeichert sind).
Mit bestimmten Microsoft-Tools (z. B. Notepad) ist dies möglich, mit bestimmten Nicht-Microsoft-Tools (z. B. meinem Lieblingseditor vim) jedoch nicht. Seltsamerweise tat vim so, als würde es bei mir funktionieren, tat es aber in Wirklichkeit nicht: Ich konnte eine Datei erstellen, den Editor vollständig schließen, dann den Editor erneut öffnen und die Datei aufrufen – doch die Datei wurde weder im Windows Explorer angezeigt, noch wurde sie von der PowerShell beim Starten gesehen! (Ich kenne die Ursache für dieses Problem nicht genau, aber es liegt nicht an fehlenden erhöhten Rechten).
Andererseits kennt Notepad offenbar die geheime Beschwörungsformel, denn sie funktioniert wie erwartet. Eine andere Möglichkeit besteht darin, das Profil „Alle Benutzer“ in Ihrem eigenen Benutzerverzeichnis zu erstellen und es dann einfach in das entsprechende Systemverzeichnis zu kopieren oder zu verschieben.
Dateinamen der Profile & Speicherorte
Im vorigen Abschnitt wurde erklärt, wie Sie Ihre Profile bearbeiten können, ohne zu wissen, wo sie sich im Dateisystem befinden, aber Sie sind ein Entwickler; Sie haben einen angeborenen Zwang zu wissen, wo sie sich verstecken! Die Tabelle zeigt die Pfade der einzelnen Profile. (HostId ist ein Platzhalter, wird gleich erklärt.)
Profile | Location |
AllUsersAllHosts | $PsHome\profile.ps1 |
AllUsersCurrentHost | $PsHome\HostId_profile.ps1 |
AlleBenutzerAktuellerHost | $Home\Dokumente\WindowsPowerShell\profile.ps1 |
CurrentUserCurrentHost | $Home\Dokumente\WindowsPowerShell\HostId_profile.ps1 |
Ein Fehler, den ich in einer Reihe von Artikeln im Web gesehen habe, ist, dass die „Alle Benutzer“-Profile unter $env:WinDir\System32
sind. Das ist falsch! $PsHome
kann für einige Hosts zufällig zu $env:WinDir\System32
aufgelöst werden, aber nicht für alle. Auf meinem System speichert zum Beispiel die Visual Studio Package Manager Console ihre „all users“-Profile unter $env:WinDir\SysWOW64
. (Dieser Fehler taucht sogar in Artikeln aus sehr seriösen Quellen auf, z. B. in diesem MSDN-Artikel.)
Wenn man sich die Speicherorte ansieht, ist es einfach, die Namenskonventionen zu verstehen. Die Profile auf Systemebene – die für alle Benutzer – befinden sich im Systemverzeichnis, auf das $PsHome
verweist. Die Profile auf Benutzerebene befinden sich im Home-Verzeichnis des jeweiligen Benutzers. Der einzige Punkt, der einer Erklärung bedarf, ist die Angabe HostId
für die rechnerspezifischen Profile in der Tabelle. Leider hat diese Host-ID keine direkte Ähnlichkeit mit der Host-Beschreibung und auch nicht mit der Eigenschaft $Host.Name
! Um die HostId
herauszufinden, muss einfach der Wert der Variablen $Profile
angezeigt werden, da sie Teil des Pfades ist. Der Einfachheit halber sind hier die HostId
-Werte für die gängigsten Hosts:
Host | HostId | $Host.Name |
PowerShell | Microsoft.PowerShell | ConsoleHost |
PowerShell ISE | Microsoft.PowerShellISE | Windows PowerShell ISE Host |
Visual Studio Package Manager Console | NuGet | Package Manager Host |
Ein weiterer Fehler in freier Wildbahn, wenn auch weniger häufig, ist, dass HostId
mit der bereits erwähnten Variable $ShellId
gleichzusetzen ist. Das ist falsch! Wie Sie gesehen haben, haben alle drei oben gezeigten gemeinsamen Hosts dieselbe $ShellId
, die zufälligerweise nur für den Standard-PowerShell-Host mit der HostId
übereinstimmt. (Dieser Fehler taucht zum Beispiel im Buch Windows PowerShell Unleashed auf.)
Wie viele Profile brauchen Sie?
Jedes Standard-Windows-System hat zwei Profile für den Standard-PowerShell-Host, zwei für den PowerShell-ISE-Host und zwei für alle Hosts – insgesamt also mindestens sechs. Fügen Sie den VS-Paketmanager hinzu, den ich gezeigt habe, das sind zwei weitere. Fügen Sie andere PowerShell-IDEs hinzu – zwei weitere für jede. Wie können Sie so viele Profile verwalten?
Interpretiert man die offizielle MSDN-Doktrin ( about_profiles), sollte man eine dreiteilige Lösung in Betracht ziehen.
- Erst einmal die wirklich gemeinsamen Dinge in
AllUsersAllHost
packen. - Zweitens, wenn es einige Besonderheiten in bestimmten Hosts gibt, benutze
AllUsersCurrentHost
für diese abweichenden Hosts. - Schließlich kann jeder Benutzer seine eigenen Präferenzen und Einstellungen in benutzerspezifischen Profilen verwalten.
Aber auch hier könnte es viele verschiedene Profile für den „aktuellen Host“ geben, sowohl auf der Systemebene als auch auf der Benutzerebene. Eine gute Referenz, wenn Sie über Ihre Wahlmöglichkeiten nachdenken, ist Ed Wilsons (The Scripting Guy) Beitrag Deciding Between One or Multiple PowerShell Profiles. Er enthält darin eine Liste von Vor- und Nachteilen für die Wahl zwischen einem Profil und mehreren Profilen. Meiner Meinung nach überwiegen jedoch die Vorteile eines einzelnen Profils bei weitem die Vorteile mehrerer Profile. Es ist zwar etwas aufwändiger einzurichten, aber man kann trotzdem hostspezifische Unterschiede berücksichtigen und hat alles an einem Ort, was die Pflege im Laufe der Zeit sehr viel einfacher macht.
Das meiste in Ihrem Profil wird wahrscheinlich für alle Hosts gleich sein, so dass die Verwendung eines einzigen Profils bedeutet, dass alle Änderungen in genau einer Datei vorgenommen werden. Für die Dinge, die sich von Host zu Host unterscheiden, fügen Sie einfach einen Abschnitt ein, der für jeden Host spezifisch ist, für den Sie sich interessieren. Mein Profil enthält etwa so etwas wie dies:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
if ($Host.Name -eq ‚ConsoleHost‘)
{
Import-Module PSReadline
# Verbose von Warnungen unterscheiden!
$privData = (Get-Host).PrivateData
$privData.VerboseForegroundColor = „cyan“
}
elseif ($Host.Name -like ‚*ISE Host‘)
{
Start-Steroids
Import-Module PsIseProjectExplorer
}
if (!$env:github_shell)
{
# Ich bin mir nicht sicher, warum, aber dies schlägt in einem Git-Host fehl
Add-PSSnapin Microsoft.TeamFoundation.PowerShell
}
|
Beachte, wie ich den aktuellen Host mit $Host.Name
identifiziere und dann selektiv Code ausführe. Sie sehen oben Beispiele für den Standard-PowerShell-Host und den PowerShell ISE-Host. Im ersten Fall wird die PSReadline-Erweiterung geladen, die nur auf dem PowerShell-Host funktioniert. Im letzteren Fall werden der PsISEProjectExplorer und das ISE Steroids-Modul geladen, die beide nur in der ISE-Umgebung funktionieren können.
Wenn Sie Git verwenden und das von Ihnen verwendete Installationsprogramm einen Git-PowerShell-Host für Sie erstellt hat, beachten Sie, dass dieser nicht durch das $Host.Name
vom Standard-PowerShell-Host unterschieden werden kann. Stattdessen habe ich eine eindeutig definierte Variable, $env:github_shell
, identifiziert, die nur im Git-Host vorhanden ist.
Was Sie in Ihr Profil aufnehmen sollten
Die Antwort auf diese Frage hängt von Ihren individuellen Bedürfnissen ab und ist daher sehr abstrakt: Nehmen Sie in Ihr Profil auf, was Sie verwenden können, um produktiver zu sein. Es gibt also keine allgemeingültige Antwort darauf, aber ich kann Ihnen sicherlich einige Vorschläge machen, um Ihre Kreativität anzuregen. Sie haben soeben einige Beispiele für den Import von Modulen von Drittanbietern gesehen, um die Funktionalität des jeweiligen Hosts zu erweitern. Neben den Modulimporten enthalten die folgenden Abschnitte nur einige Ideen, die Sie zum Nachdenken darüber anregen sollen, was Sie dort einfügen möchten. Werfen Sie auch einen Blick auf What’s in your PowerShell `profile.ps1` file? (auf StackOverflow), um viele weitere Beispiele zu finden.
Aliases
Viele integrierte PowerShell-Cmdlets haben Aliase; einige haben mehrere Aliase. Sie können z. B. ls
oder dir
oder gci
verwenden, anstatt Get-ChildItem
einzugeben. Für Cmdlets, die Sie regelmäßig verwenden und die keine Aliase bereitstellen (oder für Ihre eigenen benutzerdefinierten Funktionen und Cmdlets), können Sie mit Set-Alias
eigene Aliase erstellen. Set-Alias
ist geeignet, wenn Sie nur den Namen des Cmdlets oder der Funktion abkürzen möchten. Manchmal möchten Sie jedoch, dass ein Alias z. B. den Namen eines Cmdlets und einen Parameter enthält, den Sie normalerweise immer verwenden. Für diese Fälle können Sie einen Alias mit einer einfachen Funktion emulieren. Nehmen wir zur Veranschaulichung das Cmdlet Import-Module
. Ich verwende es häufig, und ich ziehe es vor, dass alle meine häufig verwendeten Cmdlets nur den Anfangsbuchstaben der einzelnen Komponenten verwenden. Damit wird der Alias im
eingerichtet, um dies zu erreichen:
1
|
Set-Alias im Import-Modul
|
Als Entwickler muss ich aber auch häufig Import-Module
mit dem Schalter -Force
verwenden. Dafür muss ich also auf eine Funktion zurückgreifen. Für meine Namenskonvention füge ich den ersten Buchstaben des Schalters hinzu, also imf
hier:
1
|
function imf($name) { Import-Module $name -force }
|
Ich kann dann z.B. im foobar
verwenden, um einen Vanilla-Import durchzuführen, oder imf foobar
, um mit -Force
zu importieren.
Einfache Funktionen
Funktionen wurden gerade als Mittel zur Erstellung von Pseudo-Aliasen erwähnt, d.h. im Wesentlichen, um Ihnen Tipparbeit zu ersparen. Aber natürlich sind sie nicht auf diesen Zweck beschränkt. Vielleicht möchten Sie in Ihr Profil eine Reihe von „Einzeilern“ aufnehmen, die Ihnen sowohl Tipparbeit ersparen als auch das Erinnern an Details von Cmdlets, die Sie weniger häufig verwenden. Schnell, wie zeigen Sie die letzten 50 Elemente in Ihrem Befehlsverlauf an? Sie sind sich nicht sicher? Das zu verwendende Cmdlet ist Get-History
(es hat einen Standard-Alias, der nur den Buchstaben h enthält). Ist es einfach, sich Get-History -Count 50
oder nur h50 zu merken? Hier ist meine Definition für h50 (und ein h10 als Zugabe):
1
2
|
Funktion h50 { Get-History -Count 50 }
function h10 { Get-History -Count 10 }
|
Hier ist eine weitere interessante Funktion. Wie würden Sie das Cmdlet hinter einem Alias, den Pfad zu einer ausführbaren Datei, die nur den Programmnamen enthält, die für ein bestimmtes Cmdlet verfügbaren Parametersätze oder den Inhalt einer benutzerdefinierten Funktion aufdecken? Ich verwende diesen Einzeiler für all das (benannt nach dem Unix/Linux-Befehl, der ähnlich funktioniert):
1
|
function which($cmd) { (Get-Command $cmd).Definition }
|
Hier sind einige Ergebnisse der Verwendung dieser Funktion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
PS> die h
Get-History
PS> welche notepad
C:\Windows\system32\notepad.exe
PS> which which
param($cmd)
(Get-Command $cmd).Definition
PS> which import-module
Import-Module <string> <string> -PSSession <PSSession>
Import-Modul <string> -CimSession <CimSession>
|
Finale, ein weiterer praktischer Einzeiler, der wiederum wie der Unix/Linux-Befehl funktioniert und Ihren domänenqualifizierten Benutzernamen meldet:
1
|
function whoami { (get-content env:\userdomain) + „\“ + (get-content env:\username }
|
Komplexe Funktionen
Es ist wahrscheinlich, dass Sie im Laufe Ihrer Arbeit einige Hilfsfunktionen erstellen werden, die viel komplexer sind als ein einfacher Einzeiler. Sie könnten sie natürlich einfach in Ihr Profil einbetten, aber das würde Ihr Profil lang und unübersichtlich machen. Wenn Sie eine Sammlung solcher Funktionen haben, können Sie sie immer in einem echten PowerShell-Modul organisieren und dann einfach ein Import-Module
in Ihr Profil einfügen, um sie einzubinden. Wenn Sie zwischen diesen beiden Extremen liegen, sollten Sie diesen Ansatz in Betracht ziehen. In meinem Profil habe ich diese Befehlssequenz, die alle Skripts in meinem lokalen profile_scripts-Verzeichnis beim Start in den Geltungsbereich bringt:
1
2
3
|
Resolve-Path $PSScriptRoot\profile_scripts\*.ps1 |
Where-Object { -not ($_.ProviderPath.Contains(„.Tests.“)) } |
Foreach-Object { . $_.ProviderPath }
|
$PSScriptRoot
ist eine Standard-Systemvariable, die nur im Kontext eines laufenden Skripts existiert. Sie wird aufgelöst zu $Home
\Dokumente\WindowsPowerShell\. Mein Verzeichnis profile_scripts befindet sich also unter diesem Pfad. Jedes Skript (mit Ausnahme von Testskripten) wird mit einem Punkt versehen, so dass es in Ihrem aktuellen Bereich sichtbar ist, sobald Sie nach dem Start eine Eingabeaufforderung erhalten.
Aktionen ausführen
Die vorherigen Elemente in diesem Abschnitt sind alle passiv; sie definieren Dinge, die Sie zu einem späteren Zeitpunkt nach dem Start verwenden können. Sie können aber auch aktive Elemente einfügen, die während des Starts ausgeführt werden. Ich empfehle Ihnen dringend, das Cmdlet „Don’t let me shoot myself in the foot“ zu verwenden:
1
|
Set-PSDebug -Strict
|
Sprachen, die schwach typisiert sind (z.z. B. JavaScript, PowerShell) geben Ihnen die Möglichkeit, sicher zu arbeiten oder nicht, während stark typisierte Sprachen Sie im Allgemeinen dazu zwingen, sicher zu arbeiten. Sicher bedeutet in erster Linie, dass Sie eine Variable nicht verwenden dürfen, bevor sie deklariert ist. Das verhindert, dass Sie sich versehentlich vertippen und unsägliches Leid verursachen, wenn Sie herausfinden wollen, warum Ihr Code nicht funktioniert. (Vermutlich denken die Entwickler von Sprachen mit schwacher Typisierung, dass einige Leute die sichere Bedienung als lästig empfinden könnten, und bieten daher diese Option an.) Fügen Sie das Set-PSDebug
einfach in Ihr Profil ein. Gehen Sie auf Nummer sicher. Bitte.
Andere Arten von Aktionen, die Sie in Ihr Profil aufnehmen können, sind Dinge wie die Anzeige einiger Statistiken, z. B. Betriebszeit, Festplattenspeicher oder PowerShell-Ausführungsrichtlinien. Wenn Sie mehrere Rechner verwalten, möchten Sie vielleicht Details über den Rechner sehen, in den Sie „remoted“ haben, um sicherzustellen, dass Sie sich auf dem Rechner befinden, den Sie vermuten (Domänenname, Computername, IP-Adresse usw.).
Sichern Sie Ihr Profil
Beim Umgang mit Computern muss die Sicherheit immer eine Rolle spielen. Sie verwenden eine Firewall und ein Antivirusprogramm, um Ihr System sicher zu halten. In ähnlicher Weise müssen Sie PowerShell-Skripte berücksichtigen, die Sie ausführen – einschließlich Ihrer eigenen Profile. PowerShell bietet eine gute Sicherheitsunterstützung, angefangen bei der Standardeinstellung, die die Ausführung von Skripts nicht zulässt; standardmäßig können Sie PowerShell-Befehle nur interaktiv verwenden. Sie müssen Ihr System gerade so weit öffnen, dass Sie Ihre Arbeit erledigen können, indem Sie die Ausführungsrichtlinie Ihres Computers festlegen (siehe Set-ExecutionPolicy).
Aber sobald Sie die Ausführung von Skripts zulassen, besteht die Möglichkeit, dass Sie versehentlich ein kompromittiertes Skript ausführen. Dies ist keine Besonderheit von PowerShell-Skripten an sich – alles auf Ihrem Computer kann kompromittiert werden -, sondern PowerShell hilft Ihnen, die Situation zu entschärfen. Dies geschieht, indem Sie die Ausführungsrichtlinie nach Ihren eigenen Bedürfnissen auf verschiedene Sicherheitsstufen einstellen können. Sie können unter anderem festlegen, dass jedes Skript authentifiziert werden muss oder dass nur alle Skripts, die Sie herunterladen, authentifiziert werden müssen. Authentifizierung bezieht sich in diesem Fall auf das Signieren von Skripts mit einer digitalen Signatur (siehe Set-AuthenticodeSignature), so dass bei einer (böswilligen oder nicht böswilligen) Änderung einer Datei die digitale Signatur die Manipulation erkennt und die Ausführung des Skripts verhindert.
Das Verwalten der Sicherheit für Ihre PowerShell-Skripts (einschließlich Ihrer Profile) ist jedoch kein triviales Unterfangen. (Es würde die Länge dieses Artikels mehr als verdoppeln!) Aber es gibt bereits viele gute Informationen, die Sie dabei unterstützen. Ich würde empfehlen, mit einem anderen Artikel hier auf Simple-Talk zu beginnen, nämlich Nicolas Prigents PowerShell Day-to-Day SysAdmin Tasks: Skripte absichern. Es gibt auch mehrere gute Referenzen in der PowerShell-Dokumentation: about_signing bietet eine gute Einführung in das Thema; mit New-SelfSignedCertificate können Sie Ihre eigenen selbstsignierten Zertifikate erstellen, und Get-ChildItem for Certificate zeigt die wenig bekannten Unterschiede in Get-ChildItem
auf, wenn Sie Ihren Zertifikatspeicher referenzieren. Microsoft bietet eine alte, aber immer noch nützliche Referenz über Best Practices für das Code-Signieren. Und Geoff Bard’s Signing PowerShell Scripts ist ebenfalls einen Blick wert.
Get that Profile Out of the Way!
Nun wissen Sie, wie Sie Ihr Profil einrichten, warum es nützlich ist, was Sie damit tun können und wie Sie es schützen. Aber wie bei jeder Superkraft müssen Sie sich über die Schattenseiten im Klaren sein. Nun, nicht so sehr eine dunkle Seite an sich, sondern dass es Zeiten gibt, in denen Sie einfach nicht wollen, dass Ihr(e) Profil(e) Ihnen in die Quere kommen. Oder, was noch schlimmer ist, die Profile anderer Leute.
Es gibt eine Vielzahl von Situationen, in denen Sie powershell.exe entweder mit einem literalen Befehl oder einer Skriptdatei ausführen möchten. Ein Beispiel: Sie haben ein PowerShell-Skript erstellt, das Sie mit einem Kollegen teilen möchten. Im Gegensatz zu Stapeldateien können Sie nicht einfach auf ein PowerShell-Skript doppelklicken, um es auszuführen; das ist Teil des Sicherheitsmodus von PowerShell, um Ihr System sicher zu halten. Aber das lässt sich leicht umgehen (nicht, dass ich das empfehlen würde!), indem Sie eine Standard-Windows-Verknüpfung erstellen, die auf powershell.exe abzielt und Ihre PowerShell-Skriptdatei als Parameter enthält.
Eine andere, vielleicht legitimere Verwendung wäre die Ausführung eines PowerShell-Skripts oder -Befehls innerhalb einer Build-Datei. Da MSBuild von Haus aus nicht weiß, wie man PowerShell-Skripte ausführt, würden Sie normalerweise ein Skript ausführen, indem Sie es als Argument an powershell.exe übergeben.
Immer wenn Sie powershell.exe ausführen, öffnen Sie jedoch einen neuen PowerShell-Host. Und was passiert, wenn Sie einen Host öffnen? Er führt eines (oder alle) Ihrer vier Profile aus! Aber fast immer, wenn Sie einen Host durch direkten Aufruf von powershell.exe öffnen, möchten Sie nicht, dass Ihre Profile ausgeführt werden, weder wegen des Overheads noch wegen der möglichen Konflikte, die sich daraus ergeben könnten. Denken Sie daran, dass, wenn jemand anderes einen Build ausführt, bei dem Sie einen Befehl zum Ausführen von powershell.exe eingeführt haben, sein Profil auf seinem Rechner ausgeführt wird, und Sie keine Ahnung haben, was dort lauern könnte. Außerdem möchten Sie nicht von etwas in einem Profil abhängig sein, denn wenn jemand Ihren Build zum ersten Mal ausführt, der die Abhängigkeit nicht kennt, wird er (möglicherweise auf mysteriöse Weise) fehlschlagen. Es ist also rundum am sichersten, die bewährte Praxis anzuwenden, Profile immer zu ignorieren, wenn Sie powershell.exe aufrufen. (Ich meine nicht, dass Sie sie ignorieren sollten, sondern eher, dass Sie PowerShell sagen sollten, sie zu ignorieren, natürlich!
Nach all dem spannenden Aufbau ist die Auflösung vielleicht etwas enttäuschend: Fügen Sie einfach ein -NoProfile
als Parameter zu powershell.exe hinzu.
Fazit
Das PowerShell-Profil ist Ihr Freund. Mit der in diesem Artikel dargelegten Roadmap haben Sie die verfügbaren Profiltypen gesehen und können die für Sie geeigneten auswählen. Sie können aber auch ein einziges Profil verwenden, in dem Sie hostspezifische Elemente nach Bedarf unterscheiden. Das Profil ist ein einfaches, aber leistungsfähiges Werkzeug, das Ihnen zur Verfügung steht, überhaupt nicht kompliziert zu bedienen ist und dessen Einsatzmöglichkeiten nur durch Ihre Phantasie begrenzt sind. Der einzige Nachteil ist die Zeit, die Sie jetzt damit verbringen werden, nach praktischen und cleveren Dingen zu suchen, die Sie Ihrem Profil hinzufügen können. (Habe ich schon erwähnt, dass Sie das Go-Shell-Modul einbeziehen sollten…?)