Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Ich hatte vor kurzem eine Idee für Modul, die ich als binäres Modul implementieren wollte. Ich muss noch eine mit der PowerShell Standard Library erstellen, daher schien dies eine gute Gelegenheit zu sein. Ich habe den Leitfaden Erstellen eines plattformübergreifenden Binärmoduls verwendet, um dieses Modul ohne Hindernisse zu erstellen. Wir werden diesen Prozess durchlaufen, und ich werde auf dem Weg einen kleinen zusätzlichen Kommentar hinzufügen.
Anmerkung
Die Originalversion dieses Artikels erschien auf dem Blog, der von @KevinMarquettegeschrieben wurde. Das PowerShell-Team danke Kevin für das Teilen dieser Inhalte mit uns. Bitte schauen Sie sich seinen Blog bei PowerShellExplained.coman.
Was ist die PowerShell-Standardbibliothek?
Die PowerShell-Standardbibliothek ermöglicht es uns, plattformübergreifende Module zu erstellen, die sowohl in PowerShell als auch in Windows PowerShell 5.1 funktionieren.
Warum binärmodule?
Wenn Sie ein Modul in C# schreiben, verzichten Sie auf den einfachen Zugriff auf PowerShell-Cmdlets und -Funktionen. Wenn Sie jedoch ein Modul erstellen, das nicht von vielen anderen PowerShell-Befehlen abhängt, kann der Leistungsvorteil erheblich sein. PowerShell wurde für den Administrator und nicht für den Computer optimiert. Durch den Wechsel zu C# können Sie den von PowerShell hinzugefügten Aufwand reduzieren.
Beispielsweise haben wir einen kritischen Prozess, der viele Arbeit mit JSON und Hashtables erledigt. Wir haben die PowerShell so weit optimiert, wie wir es können, aber der Vorgang dauert noch 12 Minuten, bis der Vorgang abgeschlossen ist. Das Modul enthielt bereits eine Menge von PowerShell im C#-Stil. Dadurch wird die Konvertierung in ein binäres Modul sauber und einfach. Durch die Konvertierung in ein binäres Modul haben wir die Prozesszeit von mehr als 12 Minuten auf unter vier Minuten reduziert.
Hybridmodule
Sie können binäre Cmdlets mit erweiterten PowerShell-Funktionen kombinieren. Alles, was Sie über Skriptmodule wissen, gelten auf die gleiche Weise. Die leere psm1 Datei ist enthalten, damit Sie später weitere PowerShell-Funktionen hinzufügen können.
Fast alle kompilierten Cmdlets, die ich erstellt habe, haben zuerst als PowerShell-Funktionen begonnen. Alle unsere Binärmodule sind wirklich Hybridmodule.
Erstellen von Skripts
Ich habe das Buildskript hier einfach gehalten. Im Allgemeinen nutze ich ein großes Invoke-Build-Skript als Teil meiner CI/CD-Pipeline. Es leistet mehr als das Ausführen von Pester-Tests und PSScriptAnalyzer, die Versionsverwaltung und die Veröffentlichung in der PSGallery. Nachdem ich angefangen hatte, ein Buildskript für meine Module zu verwenden, konnte ich viele Dinge finden, die ich hinzufügen konnte.
Planen des Moduls
Der Plan für dieses Modul besteht darin, einen src Ordner für den C#-Code zu erstellen und den Rest wie für ein Skriptmodul zu strukturieren. Dazu gehört die Verwendung eines Buildskripts, um alles in einen Output Ordner zu kompilieren. Die Ordnerstruktur sieht wie folgt aus:
MyModule
├───src
├───Output
│ └───MyModule
├───MyModule
│ ├───Data
│ ├───Private
│ └───Public
└───Tests
Erste Schritte
Zuerst muss ich den Ordner erstellen und das Git-Repository erstellen. Ich verwende $module als Platzhalter für den Modulnamen. Dies sollte es Ihnen erleichtern, diese Beispiele bei Bedarf wiederzuverwenden.
$module = 'MyModule'
New-Item -Path $module -Type Directory
Set-Location $module
git init
Erstellen Sie dann die Ordner auf Stammebene.
New-Item -Path 'src' -Type Directory
New-Item -Path 'Output' -Type Directory
New-Item -Path 'Tests' -Type Directory
New-Item -Path $module -Type Directory
Setup des binären Moduls
Der Artikel konzentriert sich auf das binäre Modul, und dort werden wir beginnen. In diesem Abschnitt werden Beispiele aus dem Leitfaden zur Erstellung eines plattformübergreifenden Binärmoduls entnommen. Überprüfen Sie dieses Handbuch, wenn Sie weitere Details benötigen oder Probleme haben.
Zunächst möchten wir die Version des dotnet core SDK überprüfen, das wir installiert haben. Ich verwende 2.1.4, aber Sie sollten 2.0.0 oder höher haben, bevor Sie fortfahren.
PS> dotnet --version
2.1.4
In diesem Abschnitt arbeite ich mit dem Inhalt des Ordners src.
Set-Location 'src'
Erstellen Sie mithilfe des Dotnet-Befehls eine neue Klassenbibliothek.
dotnet new classlib --name $module
Dadurch wird das Bibliotheksprojekt in einem Unterordner erstellt, aber ich möchte diese zusätzliche Schachtelungsebene nicht. Ich werde diese Dateien auf eine Ebene verschieben.
Move-Item -Path .\$module\* -Destination .\
Remove-Item $module -Recurse
Legen Sie die .NET Core SDK-Version für das Projekt fest. Ich habe das 2.1 SDK, sodass ich 2.1.0angeben werde.
Verwenden Sie 2.0.0, wenn Sie das 2.0 SDK verwenden.
dotnet new globaljson --sdk-version 2.1.0
Fügen Sie dem Projekt die PowerShell-StandardbibliothekNuGet-Paket hinzu. Stellen Sie sicher, dass Sie die neueste Version verwenden, die für die erforderliche Kompatibilitätsstufe verfügbar ist. Ich würde standardmäßig die neueste Version verwenden, aber ich denke nicht, dass dieses Modul alle neueren Features als PowerShell 3.0 nutzt.
dotnet add package PowerShellStandard.Library --version 7.0.0-preview.1
Wir sollten über einen src-Ordner verfügen, der wie folgt aussieht:
PS> Get-ChildItem
Directory: \MyModule\src
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/14/2018 9:51 PM obj
-a---- 7/14/2018 9:51 PM 86 Class1.cs
-a---- 7/14/2018 10:03 PM 259 MyModule.csproj
-a---- 7/14/2018 10:05 PM 45 global.json
Jetzt können wir dem Projekt eigenen Code hinzufügen.
Erstellen eines binären Cmdlets
Wir müssen die src\Class1.cs aktualisieren, um dieses Start-Cmdlet zu enthalten:
using System;
using System.Management.Automation;
namespace MyModule
{
[Cmdlet( VerbsDiagnostic.Resolve , "MyCmdlet")]
public class ResolveMyCmdletCommand : PSCmdlet
{
[Parameter(Position=0)]
public Object InputObject { get; set; }
protected override void EndProcessing()
{
this.WriteObject(this.InputObject);
base.EndProcessing();
}
}
}
Benennen Sie die Datei so um, dass sie dem Klassennamen entspricht.
Rename-Item .\Class1.cs .\ResolveMyCmdletCommand.cs
Anschließend können wir unser Modul erstellen.
PS> dotnet build
Microsoft (R) Build Engine version 15.5.180.51428 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 18.19 ms for C:\workspace\MyModule\src\MyModule.csproj.
MyModule -> C:\workspace\MyModule\src\bin\Debug\netstandard2.0\MyModule.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.19
Wir können Import-Module für die neue DLL aufrufen, um unser neues Cmdlet zu laden.
PS> Import-Module .\bin\Debug\netstandard2.0\$module.dll
PS> Get-Command -Module $module
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Resolve-MyCmdlet 1.0.0.0 MyModule
Wenn der Import auf Ihrem System fehlschlägt, versuchen Sie, .NET auf 4.7.1 oder höher zu aktualisieren. Die Anleitung zum Erstellen eines plattformübergreifenden Binärmoduls enthält weitere Details zur Unterstützung und Kompatibilität von .NET für ältere Versionen.
Modulmanifest
Es ist cool, dass wir die DLL importieren können und über ein Arbeitsmodul verfügen. Ich möchte weiterhin damit fortgehen und ein Modulmanifest erstellen. Wir benötigen das Manifest, wenn wir später in der PSGallery veröffentlichen möchten.
Im Stammverzeichnis unseres Projekts können wir diesen Befehl ausführen, um das benötigte Modulmanifest zu erstellen.
$manifestSplat = @{
Path = ".\$module\$module.psd1"
Author = 'Kevin Marquette'
NestedModules = @('bin\MyModule.dll')
RootModule = "$module.psm1"
FunctionsToExport = @('Resolve-MyCmdlet')
}
New-ModuleManifest @manifestSplat
Ich werde auch ein leeres Stammmodul für zukünftige PowerShell-Funktionen erstellen.
Set-Content -Value '' -Path ".\$module\$module.psm1"
Auf diese Weise kann ich sowohl normale PowerShell-Funktionen als auch binäre Cmdlets im selben Projekt kombinieren.
Erstellen des vollständigen Moduls
Ich kompiliere alles zusammen in einem Ausgabeordner. Dazu müssen wir ein Buildskript erstellen. Normalerweise würde ich dies zu einem Invoke-Build Skript hinzufügen, aber wir können es für dieses Beispiel einfach halten. Fügen Sie dies zur Datei build.ps1 im Stammverzeichnis des Projekts hinzu.
$module = 'MyModule'
Push-Location $PSScriptRoot
dotnet build $PSScriptRoot\src -o $PSScriptRoot\output\$module\bin
Copy-Item "$PSScriptRoot\$module\*" "$PSScriptRoot\output\$module" -Recurse -Force
Import-Module "$PSScriptRoot\Output\$module\$module.psd1"
Invoke-Pester "$PSScriptRoot\Tests"
Diese Befehle erstellen unsere DLL und platzieren sie in unseren output\$module\bin Ordner. Anschließend werden die anderen Moduldateien an ihren Platz kopiert.
Output
└───MyModule
├───MyModule.psd1
├───MyModule.psm1
└───bin
├───MyModule.deps.json
├───MyModule.dll
└───MyModule.pdb
An diesem Punkt können wir unser Modul mit der psd1-Datei importieren.
Import-Module ".\Output\$module\$module.psd1"
Von hier aus können wir den .\Output\$module Ordner in unserem $Env:PSModulePath Verzeichnis ablegen und den Befehl automatisch laden, wenn wir ihn benötigen.
Update: neue Vorlage für PSModule im Befehl dotnet
Ich habe gelernt, dass das dotnet-Tool über eine PSModule Vorlage verfügt.
Alle oben beschriebenen Schritte sind noch gültig, aber diese Vorlage lässt viele davon weg. Es handelt sich um eine noch relativ neue Vorlage, die weiterhin verfeinert wird. Erwarten Sie, dass sie von hier aus immer besser wird.
So installieren und verwenden Sie die PSModule-Vorlage.
dotnet new -i Microsoft.PowerShell.Standard.Module.Template
dotnet new psmodule
dotnet build
Import-Module "bin\Debug\netstandard2.0\$module.dll"
Get-Module $module
Diese minimal lebensfähige Vorlage kümmert sich um das Hinzufügen des .NET SDK, der PowerShell-Standardbibliothek und erstellt eine Beispielklasse im Projekt. Sie können es erstellen und sofort ausführen.
Wichtige Details
Bevor wir diesen Artikel beenden, finden Sie hier einige weitere Details, die erwähnt werden sollten.
Entladen von DLLs
Sobald ein binäres Modul geladen wurde, können Sie es nicht wirklich entladen. Die DLL-Datei ist gesperrt, bis Sie sie entladen. Dies kann beim Entwickeln lästig sein, weil die Datei jedes Mal gesperrt wird, wenn Sie eine Änderung vornehmen und sie neu erstellen möchten. Die einzige zuverlässige Möglichkeit, dies zu beheben, besteht darin, die PowerShell-Sitzung zu schließen, die die DLL geladen hat.
VS Code-Aktion „Fenster erneut laden“
Ich erledige den größten Teil meiner PowerShell-Entwicklungsarbeit in VS Code. Wenn ich an einem binärmodul (oder einem Modul mit Klassen) arbeite, habe ich mich jedes Mal, wenn ich builde, in die Gewohnheit gebracht, VS-Code neu zu laden.
Über Ctrl+UMSCHALT+P wird das Befehlsfenster geöffnet, und Reload Window steht in meiner Liste immer ganz oben.
Geschachtelte PowerShell-Sitzungen
Eine andere Option besteht darin, eine gute Pester-Test-Abdeckung zu haben. Anschließend können Sie das build.ps1 Skript anpassen, um eine neue PowerShell-Sitzung zu starten, den Build auszuführen, die Tests auszuführen und die Sitzung zu schließen.
Aktualisieren installierter Module
Diese Sperrung kann störend sein, wenn Sie versuchen, Ihr lokal installiertes Modul zu aktualisieren. Wenn es in einer Sitzung geladen ist, müssen Sie es aufspüren und schließen. Dies ist weniger ein Problem bei der Installation von einer PSGallery, da die Modulversionsverwaltung das neue in einem anderen Ordner platziert.
Sie können eine lokale PSGallery einrichten und diese als Teil Ihres Builds veröffentlichen. Führen Sie dann Ihre lokale Installation von dieser PSGallery aus. Dies klingt wie viel Arbeit, aber dies kann so einfach wie das Starten eines Docker-Containers sein. Eine Möglichkeit dazu beschreibe ich in meinem Beitrag zum Verwenden eines NuGet-Servers für ein PSRepository.
Letzte Gedanken
Ich habe die C#-Syntax zum Erstellen eines Cmdlets nicht behandelt, aber es gibt viele Dokumentationen im Windows PowerShell SDK. Definitiv ist dies etwas, mit dem es sich lohnt, als Ausgangspunkt für einen ernsthafteren Einstieg in C# zu experimentieren.