Schriftgröße: +
5 minutes reading time (949 words)

PowerShell Module als DLL in C# erstellen

Powershell_1024

In den Anfangstagen von PowerShell meinten wir mit PowerShell Cmdlets immer die PowerShell Funktionen, die mit einer DLL importiert werden. Zu diesem Zeitpunkt war das quasi der Standard. Das hat sich heute erheblich geändert. In den seltensten Fällen sehe ich heute Module, die als DLL erstellt wurden. Nun wollte ich gerade einige hardwarenahe Funktionen in PowerShell nutzen, die in der Kernal32 DLL hinterlegt sind. Natürlich kann man das auch alles direkt in PowerShell integrieren aber leider ist mein Antivirus bei einigen Ausdrücken mit einmal recht aggressiv geworden. Klar, als C++ Programm sind hardwarenahen Geschichten ok nur wurden diese Funktionen scheinbar in letzter Zeit in PowerShell für böse Dinge genutzt. Daher habe ich mich entschlossen, alles in eine C# DLL zu verpacken. Dieser Blog beschriebt nun, wie man so etwas macht. Also ein PowerShell Modul als C# DLL.

 

 

Zunächst benötigen wir ein Visual Studion C# Library Projekt wie im Dialog zu sehen.

 Nun benötigen wir für unser Projekt einen Verweis auf die PowerShell referent Assemblies (System.Management.Automation). Unser Modul soll noch für die PowerShell 5 und nicht mit Core genutzt werden. Unter „Tools“ > „NuGet Package Manager“ > „manage NuGet Packages for Solution“ müssen wir Microsoft.PowerShell.5.ReferenceAssemblies bzw. Microsoft.PowerShell.5.1.ReferenceAssemblies suchen und installieren.

 

 

Anschließend findet sich die Referenz im „Solution Explorer“.

Die neue Klasse, die wir erstellen leiten wir von der Klasse Cmdlet an (System.Management.Automation)

 public class NITPerfCmdLets : Cmdlet

 CmdletAttribute

Wir müssen zusätzlich System.Management.Automation.CmdletAttribute mit entsprechenden Argumenten verwenden. Das mit demselben Verb und Substantiv, die in dem definierten Klassennamen verwendet werden. Verben sollten übrigens immer aus der Liste der zugelassenen Verben stammen. Diese können Leich mit der PowerShell nachgeschlagen werden.

 

PS C:\Users\Andreas> Get-Verb

 Verb Group

---- -----

Add Common

Clear Common

Close Common

Copy Common

Enter Common

....

 

In diesem Fall wollen wir das Cmdlet „Get-NITPerf“ und nutzen dafür die folgende Definition vor der Klasse.

 

[Cmdlet(VerbsCommon.Get, "NITPerf")]

public class NITPerfCmd : Cmdlet

 

Das Modulname selber ist der Namen der DLL.

 

Parameter

Für Parameter wird die gleiche Form verwendet, wir auch für PowerShell Funktionen. Also Elemente wie Mandatory=True sind auch im C# Code erlaubt. Ansonsten ist alles , was Public ist ein sichtbarer Parameter.

Erst einmal miss [Parameter] gesetzt sein, damit ein Parameter überhaupt sichtbar ist. Möglich ist weiterhin beispielsweise:

 

[Parameter(ValueFromPipelineByPropertyName = true)]

[Parameter(ValueFromPipelineByPropertyName = true, ValueFromPipeline = true)]

[Parameter(ValueFromPipelineByPropertyName = true)]

 

Also wie man es auch direkt aus den Skripten kennt.

[Parameter]

Public string Myparameter { get => myparameter; set => myparameter = value; }

 

[Parameter(ValueFromPipelineByPropertyName = true, ValueFromPipeline = true)]

Public string Myparameter2 { get => myparameter2; set => myparameter2 = value; }

 

[Parameter]

Public string Myparameter3 { get => myparameter3; set => myparameter3 = value; }

 

Ausgabewerte

Eingaben und Ausgaben für Ihr Cmdlet müssen verwaltet werden. Diese Programme lesen und schreiben nicht von der Konsole, wie Sie es in einem interaktiven Programm tun würden.

Betrachten wir die Ausgaben, gehen wir davon aus, dass Ihr Cmdlet nur eine Art von Ausgabe haben wird. Es passiert oft in PowerShell, dass ein Cmdlet Skript mehrere Ausgabewerte zurück gibt. Gewollt ist jedoch meist genau ein definierter Type oder ein PowerShell Objekt. Get-ChildItem gibt beispielsweise eine Fileinfo- als auch DirectoryInfo zurück. Eir möchten i.d.R. ein komplexes Objekt zurückgeben. Das können wir wiederum als Klasse definieren.

 

public class MyReturn

{

public string Name { get; set; }

public string Description { get; set; }

}

 

Im Kopf der Funktion muss nun auch der Outputtype definiert werden:

[OutputType(typeof(MyReturn))]

 

Funktionen im CmdLet

Für die Funktionen eines Cmdlets überschreiben wir die folgenden Standardmethoden:

 

BeginProcessing (um die Initialisierung durchzuführen),

ProcessRecord (um jedes Element in der Pipeline zu verarbeiten),

EndProcessing (für die Finalisierung)

StopProcessing (zur Behandlung eines abnormalen Abbruchs).

 

Manch einer kennt die Funktionen auch aus PowerShell Skripten. Hier entspricht BeginProcessing() dem Begin{} Block.

Meistens ist die Methode ProcessRecord zu füllen.

Diese Methode wird einmal pro verarbeitetem Element aufgerufen. Wenn Sie z. B. Daten über eine Pipeline an Ihr Cmdlet weiterleiten, wird sie für jedes Element, das von der Pipeline übergeben wird, einmal aufgerufen. Dies ist typischerweise der Ort, an dem Sie den Großteil Ihrer Arbeit in Ihrem Cmdlet erledigen.

 

function Verb-Noun

{

[CmdletBinding()]

[Alias()]

[OutputType([int])]

Param

(

# Param1 help description

[Parameter(Mandatory=$true,

ValueFromPipelineByPropertyName=$true,

Position=0)]

$Param1,

 

# Param2 help description

[int]

$Param2

)

 

Begin

{

}

Process

{

}

End

{

}

}

  

ANMERKUNG: Jedes PowerShell CMDLet in C# ist dementsprechend immer eine eigene Klasse.

 

Paketmanifest

 Im Stammverzeichnis des Projekts können wir diesen Befehl ausführen, um das benötigte Modulmanifest zu erstellen.

 PowerShell

 Kopieren

 $manifestSplat = @{

Path = „.\$module\$module.psd1“

Author = ‚Andreas Nick‘

NestedModules = @(‚bin\MyModule.dll‘)

RootModule = „$module.psm1“

FunctionsToExport = @(‚Resolve-MyCmdlet‘)

}

 New-ModuleManifest @manifestSplat

Hier das komplette Beispiel

using System;
using System.Collections.Generic;
using System.Management.Automation;

namespace NickIT { 
public class MyReturn
{
    public string Name { get; set; }
    public string Description { get; set; }
}

    [Cmdlet(VerbsCommon.Get, "NITPerf")]
    [OutputType(typeof(MyReturn))]
    public class NITPerfCmd : Cmdlet
    {

        private string myparameter;
        private string myparameter2;
        private string myparameter3;

        [Parameter]
        public string Myparameter { get => myparameter; set => myparameter = value; }
        
        [Parameter(ValueFromPipelineByPropertyName = true, ValueFromPipeline = true)]
        public string Myparameter2 { get => myparameter2; set => myparameter2 = value; }
       
        [Parameter]
        public string Myparameter3 { get => myparameter3; set => myparameter3 = value; }
        protected override void ProcessRecord()
        {

            /*
            Console.WriteLine("Hello World3");
            var re = new MyReturn();
            re.Name = "A1";
            re.Description = "Beschreibung";
            */

            Random ro = new Random();

            List<MyReturn> returnList = new List<MyReturn>();
            for (int i = 0; i < 10; i++){
                var r1 = new MyReturn();
                r1.Name = ro.Next().ToString();
                r1.Description = ro.Next().ToString();
                WriteObject(r1);
                // returnList.Add(r1);
            }

           // ReadOnlyCollection<MyReturn> re = new ReadOnlyCollection<MyReturn>(returnList);
            //WriteObject(returnList);
        }
    }
}

 

 Nun noch das PowerShell Skript, um die DLL anzusprechen

Import-Module<PATHTO>\NITPerfCmdLets.dll -Force

Get-Command -module NITPerfCmdLets
get-help Get-NITPerf 
$a = Get-NITPerf 
$a.GetType()

 

Nein, App-V ist 2026 nicht End of Life!
Fehlercodes von App-V 5 Paketen
 

Kommentare

Derzeit gibt es keine Kommentare. Schreibe den ersten Kommentar!
Bereits registriert? Hier einloggen
Samstag, 12. Oktober 2024

Sicherheitscode (Captcha)

Nick Informationstechnik GmbH
Dribusch 2
30539 Hannover

+49 (0) 511 165 810 190
+49 (0) 511 165 810 199

infonick-it.de

Newsletter

Anmeldung zum deutschen M.A.D. Newsletter mit Informationen zur Anwendungsvirtualisierung!

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell für den Betrieb der Seite, während andere uns helfen, diese Website und die Nutzererfahrung zu verbessern (Tracking Cookies). Sie können selbst entscheiden, ob Sie die Cookies zulassen möchten. Bitte beachten Sie, dass bei einer Ablehnung womöglich nicht mehr alle Funktionalitäten der Seite zur Verfügung stehen.