Freigeben über


Tutorial: Erstellen einer klassenbasierten DSC-Ressource für die Computerkonfiguration

Beginnen Sie mit der Erstellung einer klassenbasierten DSC-Ressource, um eine Konfigurationsdatei mit dem Computerkonfigurationsfeature von Azure Automanage zu verwalten. Wenn Sie dieses Tutorial abschließen, erhalten Sie eine klassenbasierte DSC-Ressource, die mit der Computerkonfiguration kompatibel ist, in einem Modul, das Sie für weiteres Lernen und Anpassen verwenden können.

In diesem Tutorial lernen Sie Folgendes:

  • Gerüstbau eines DSC-Ressourcenmoduls
  • Hinzufügen einer klassenbasierten DSC-Ressource
  • Definieren von DSC-Ressourceneigenschaften
  • Implementieren der DSC-Ressourcenmethoden
  • Exportieren einer DSC-Ressource in einem Modulmanifest
  • Manuelles Testen einer DSC-Ressource

Hinweis

Die Beispielausgabe in diesem Tutorial entspricht PowerShell 7.2 auf einem Windows-Computer. Das Tutorial ist mit Windows PowerShell und PowerShell auf einem Linux- oder macOS-Computer gültig. Nur die Ausgabe ist spezifisch für die Ausführung der Befehle in PowerShell auf einem Windows-Computer.

Voraussetzungen

  • PowerShell oder Windows PowerShell 5.1
  • VS Code mit der PowerShell-Erweiterung

1: Gerüstbau eines DSC-Ressourcenmoduls

DSC-Ressourcen müssen in einem PowerShell-Modul definiert werden.

Erstellen des Modulordners

Erstellen Sie einen neuen Ordner mit dem Namen ExampleResources. Dieser Ordner wird als Stammordner für das Modul und den gesamten Code in diesem Tutorial verwendet.

New-Item -Path './ExampleResources' -ItemType Directory
    Directory: C:\code\dsc

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----            9/8/2022 12:54 PM                ExampleResources

Verwenden von VS Code zum Erstellen des Moduls

Öffnen Sie den Ordner ExampleResources in VS Code. Öffnen Sie das integrierte Terminal in VS Code. Stellen Sie sicher, dass auf Ihrem Terminal PowerShell oder Windows PowerShell ausgeführt wird.

Wichtig

Führen Sie im weiteren Verlauf dieses Tutorials die angegebenen Befehle im integrierten Terminal im Stammverzeichnis des Modulordners aus. Dies ist das Standardarbeitsverzeichnis in VS Code.

Erstellen der Moduldateien

Erstellen Sie das Modulmanifest mit dem New-ModuleManifest Cmdlet. Verwenden Sie ./ExampleResources.psd1 als Pfad. Geben Sie RootModule als ExampleResources.psm1 und DscResourcesToExport als an Tailspin.

$ModuleSettings = @{
    RootModule           = 'ExampleResources.psm1'
    DscResourcesToExport = 'Tailspin'
}

New-ModuleManifest -Path ./ExampleResources.psd1 @ModuleSettings
Get-Module -ListAvailable -Name ./ExampleResources.psd1 | Format-List
Name              : ExampleResources
Path              : C:\code\dsc\ExampleResources\ExampleResources.psd1
Description       :
ModuleType        : Script
Version           : 0.0.1
PreRelease        :
NestedModules     : {}
ExportedFunctions :
ExportedCmdlets   :
ExportedVariables :
ExportedAliases   :

Erstellen Sie die Stammmoduldatei als ExampleResources.psm1.

New-Item -Path ./ExampleResources.psm1
    Directory: C:\code\dsc\ExampleResources

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---            9/8/2022  1:57 PM              0 ExampleResources.psm1

Erstellen Sie eine Skriptdatei mit dem Namen Helpers.ps1.

New-Item -Path ./Helpers.ps1
    Directory: C:\code\dsc\ExampleResources

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---            9/8/2022  1:58 PM              0 Helpers.ps1

Öffnen Sie Helpers.ps1 in VS Code. Fügen Sie die folgende Zeile hinzu.

$env:PSModulePath += "$([System.IO.Path]::PathSeparator)$pwd"

Öffnen Sie ExampleResources.psm1 in VS Code. Das Modul ist jetzt gerüstet und kann eine DSC-Ressource erstellen.

2: Hinzufügen einer klassenbasierten DSC-Ressource

Um eine klassenbasierte DSC-Ressource zu definieren, schreiben wir eine PowerShell-Klasse in einer Moduldatei und fügen ihr das DscResource-Attribut hinzu.

Definieren der -Klasse

Fügen Sie in ExampleResources.psm1 den folgenden Code hinzu:

[DscResource()]
class Tailspin {

}

Dieser Code fügt dem ExampleResources-Modul als klassenbasierte DSC-Ressource hinzuTailspin.

Zeigen Sie auf [DscResource()] die Warnungen, und lesen Sie sie.

Screenshot der Warnungen des DSCResource-Attributs in VS Code.

Wenn Sie auf das DSCResource-Attribut zeigen, werden vier Warnungen angezeigt. 1. Der DSC-Ressource "Tailspin" fehlt eine Set()-Methode, die "[void]" zurückgibt und keine Parameter akzeptiert. 2. Der DSC-Ressource "Tailspin" fehlt eine Get()-Methode, die "[Tailspin]" zurückgibt und keine Parameter akzeptiert. 3. Der DSC-Ressource "Tailspin" fehlt eine "Test()"-Methode, die "[bool]" zurückgibt und keine Parameter akzeptiert. 4. Die DSC-Ressource "Tailspin" muss mindestens eine Schlüsseleigenschaft aufweisen (mit der Syntax "[DscProperty(Key)]".)

In diesen Warnungen werden die Anforderungen aufgeführt, damit die Klasse eine gültige DSC-Ressource sein muss.

Erforderliche Methoden minimal implementieren

Fügen Sie der -Klasse eine minimale Implementierung der Get()Methoden , Test()und Set() hinzu.

class Tailspin {
    [Tailspin] Get() {
        $CurrentState = [Tailspin]::new()
        return $CurrentState
    }

    [bool] Test() {
        return $true
    }

    [void] Set() {}
}

Nachdem die Methoden hinzugefügt wurden, warnt das DscResource-Attribut nur davor, dass die Klasse keine Key-Eigenschaft hat.

3: Definieren von DSC-Ressourceneigenschaften

Sie sollten die Eigenschaften der DSC-Ressource vor den Methoden definieren. Die Eigenschaften definieren die verwaltbaren Einstellungen für die DSC-Ressource. Sie werden in den Methoden verwendet.

Grundlegendes zur TSToy-Anwendung

Bevor Sie die Eigenschaften Ihrer DSC-Ressource definieren können, müssen Sie wissen, welche Einstellungen Sie verwalten möchten.

In diesem Tutorial definieren wir eine DSC-Ressource zum Verwalten der Einstellungen der fiktiven TSToy-Anwendung über die zugehörige Konfigurationsdatei. TSToy ist eine Anwendung, die auf Benutzer- und Computerebene konfiguriert ist. Die DSC-Ressource sollte in der Lage sein, beide Dateien zu konfigurieren.

Die DSC-Ressource sollte Es Benutzern ermöglichen, Folgendes zu definieren:

  • Der Bereich der Konfiguration, die verwaltet wird, entweder Machine oder User
  • Ob die Konfigurationsdatei vorhanden sein soll
  • Gibt an, ob TSToy automatisch aktualisiert werden soll
  • Wie häufig tsToy zwischen 1 und 90 Tagen nach Updates suchen sollte

Hinzufügen der ConfigurationScope-Eigenschaft

Um die Machine Konfigurationsdatei oder User zu verwalten, müssen Sie eine Eigenschaft der DSC-Ressource definieren. Um die $ConfigurationScope -Eigenschaft in der Ressource zu definieren, fügen Sie den folgenden Code in der -Klasse vor den Methoden hinzu:

[DscProperty(Key)] [TailspinScope]
$ConfigurationScope

Dieser Code definiert $ConfigurationScope als Key-Eigenschaft der DSC-Ressource. Eine Key-Eigenschaft wird verwendet, um eine Instanz der DSC-Ressource eindeutig zu identifizieren. Das Hinzufügen dieser Eigenschaft erfüllt eine der Anforderungen, vor die das DscResource-Attribut beim Erstellen eines Gerüsts für die Klasse gewarnt hat.

Außerdem wird angegeben, dass $ConfigurationScopeder Typ tailspinScope ist. Um den TailspinScope-Typ zu definieren, fügen Sie die folgende TailspinScope-Enumeration nach der Klassendefinition in ExampleResources.psm1hinzu:

enum TailspinScope {
    Machine
    User
}

Diese Enumeration macht Machine und User die einzigen gültigen Werte für die $ConfigurationScope Eigenschaft der DSC-Ressource.

Hinzufügen der Ensure-Eigenschaft

Es empfiehlt sich, eine $Ensure Eigenschaft zu definieren, um zu steuern, ob eine Instanz einer DSC-Ressource vorhanden ist. Eine $Ensure Eigenschaft verfügt in der Regel über zwei gültige Werte: Absent und Present.

  • Wenn $Ensure als Presentangegeben ist, erstellt die DSC-Ressource das Element, wenn es nicht vorhanden ist.
  • Wenn $Ensure ist Absent, löscht die DSC-Ressource das Element, sofern vorhanden.

Für die Tailspin DSC-Ressource ist das zu erstellende oder zu löschende Element die Konfigurationsdatei für die angegebene $ConfigurationScope.

Definieren Sie TailspinEnsure als Enumeration nach TailspinScope. Sie sollte die Werte Absent und haben Present.

enum TailspinEnsure {
    Absent
    Present
}

Fügen Sie als Nächstes die $Ensure -Eigenschaft in der -Klasse nach der $ConfigurationScope -Eigenschaft hinzu. Es sollte ein leeres DscProperty-Attribut haben, und sein Typ sollte TailspinEnsure sein. Der Standardwert sollte sein Present.

[DscProperty()] [TailspinEnsure]
$Ensure = [TailspinEnsure]::Present

Hinzufügen der UpdateAutomatically-Eigenschaft

Um automatische Updates zu verwalten, definieren Sie die $UpdateAutomatically -Eigenschaft in der -Klasse nach der $Ensure -Eigenschaft. Das DscProperty-Attribut sollte angeben, dass es obligatorisch und sein Typ boolescher Wert sein sollte.

[DscProperty(Mandatory)] [bool]
$UpdateAutomatically

Hinzufügen der UpdateFrequency-Eigenschaft

Um zu verwalten, wie oft TSToy nach Updates suchen soll, fügen Sie die $UpdateFrequency -Eigenschaft in der -Klasse nach der $UpdateAutomatically -Eigenschaft hinzu. Es sollte über ein leeres DscProperty-Attribut verfügen, und sein Typ sollte int sein. Verwenden Sie das ValidateRange-Attribut , um die gültigen Werte für $UpdateFrequency auf 1 bis 90 zu begrenzen.

[DscProperty()] [int] [ValidateRange(1, 90)]
$UpdateFrequency

Hinzufügen der Reasons-Eigenschaft

Da diese DSC-Ressource für die Verwendung mit dem Azure Automanage-Computerkonfigurationsfeature vorgesehen ist, muss sie über die Reasons-Eigenschaft verfügen, die die folgenden Anforderungen erfüllt:

  • Sie muss mit der NotConfigurable-Eigenschaft für das DscProperty-Attribut deklariert werden.
  • Es muss sich um ein Array von Objekten handeln, die über eine String-Eigenschaft namens Code, eine String-Eigenschaft mit dem Namen Phrase und keine anderen Eigenschaften verfügen.

Die Computerkonfiguration verwendet die Reasons-Eigenschaft , um die Darstellung von Konformitätsinformationen zu standardisieren. Jedes von der Methode für die Get()Reasons-Eigenschaft zurückgegebene Objekt gibt an, wie und warum eine Instanz der DSC-Ressource nicht kompatibel ist.

Die Computerkonfiguration verwendet die Reasons-Eigenschaft , um die Darstellung von Konformitätsinformationen zu standardisieren. Jedes von der Methode für die Get()Reasons-Eigenschaft zurückgegebene Objekt identifiziert eine der Eigenschaften der DSC-Ressource, ihren gewünschten Zustand und ihren tatsächlichen Zustand.

Um die Reasons-Eigenschaft zu definieren, müssen Sie eine Klasse dafür definieren. Definieren Sie die ExampleResourcesReason-Klasse nach der TailspinEnsure-Enumeration . Sie sollte die Eigenschaften Code und Phrase als Zeichenfolgen aufweisen. Beide Eigenschaften sollten über das DscProperty-Attribut verfügen.

Um die Gründe während des manuellen Tests lesbarer anzuzeigen, definieren Sie die ToString() -Methode für die ExampleResourcesReason-Klasse , wie im Codeausschnitt gezeigt.

class ExampleResourcesReason {
    [DscProperty()]
    [string] $Code

    [DscProperty()]
    [string] $Phrase

    [string] ToString() {
        return "`n$($this.Code):`n`t$($this.Phrase)`n"
    }
}

Fügen Sie als Nächstes die $Reasons -Eigenschaft in der Klasse der DSC-Ressource nach der $UpdateFrequency -Eigenschaft hinzu. Es sollte das DscProperty-Attribut mit der NotConfigurable Option angegeben haben, und sein Typ sollte ExampleResourcesReason[] sein.

[DscProperty(NotConfigurable)] [ExampleResourcesReason[]]
$Reasons

Hinzufügen ausgeblendeter Cacheeigenschaften

Fügen Sie als Nächstes zwei ausgeblendete Eigenschaften zum Zwischenspeichern des aktuellen Zustands der Ressource hinzu: $CachedCurrentState und $CachedData. Legen Sie den Typ von $CachedCurrentState auf Tailspin fest, der mit der -Klasse und dem Rückgabetyp für die Get() -Methode identisch ist. Legen Sie den Typ von $CachedData auf PSCustomObject fest. Präfixen Sie beiden Eigenschaften das hidden Schlüsselwort. Geben Sie für beides nicht das DscProperty-Attribut an.

hidden [Tailspin] $CachedCurrentState
hidden [PSCustomObject] $CachedData

Diese ausgeblendeten Eigenschaften werden in den Get() Methoden und Set() verwendet, die Sie später definieren.

Überprüfen der Moduldatei

An diesem Punkt ExampleResources.psm1 sollten Sie Folgendes definieren:

  • Die Tailspin-Klasse mit den Eigenschaften $ConfigurationScope, $Ensure, , $UpdateAutomaticallyund $UpdateFrequency
  • Die TailspinScope-Enumeration mit den Werten Machine und User
  • Die TailspinEnsure-Enumeration mit den Werten Present und Absent
  • Die minimalen Implementierungen der Get()Methoden , Test(), und Set() .
[DscResource()]
class Tailspin {
    [DscProperty(Key)] [TailspinScope]
    $ConfigurationScope

    [DscProperty()] [TailspinEnsure]
    $Ensure = [TailspinEnsure]::Present

    [DscProperty(Mandatory)] [bool]
    $UpdateAutomatically

    [DscProperty()] [int] [ValidateRange(1,90)]
    $UpdateFrequency

    [DscProperty(NotConfigurable)] [ExampleResourcesReason[]]
    $Reasons

    hidden [Tailspin] $CachedCurrentState
    hidden [PSCustomObject] $CachedData

    [Tailspin] Get() {
        $CurrentState = [Tailspin]::new()
        return $CurrentState
    }

    [bool] Test() {
        $InDesiredState = $true
        return $InDesiredState
    }

    [void] Set() {}
}

enum TailspinScope {
    Machine
    User
}

enum TailspinEnsure {
    Absent
    Present
}

class ExampleResourcesReason {
    [DscProperty()]
    [string] $Code

    [DscProperty()]
    [string] $Phrase

    [string] ToString() {
        return "`n$($this.Code):`n`t$($this.Phrase)`n"
    }
}

Da die DSC-Ressource nun die Anforderungen erfüllt, können Sie sie verwenden Get-DscResource , um sie anzuzeigen. Öffnen Sie in VS Code ein neues PowerShell-Terminal.

. ./Helpers.ps1
Get-DscResource -Name Tailspin -Module ExampleResources | Format-List
Get-DscResource -Name Tailspin -Module ExampleResources -Syntax
ImplementationDetail : ClassBased
ResourceType         : Tailspin
Name                 : Tailspin
FriendlyName         :
Module               : ExampleResources
ModuleName           : ExampleResources
Version              : 0.0.1
Path                 : C:\code\dsc\ExampleResources\ExampleResources.psd1
ParentPath           : C:\code\dsc\ExampleResources
ImplementedAs        : PowerShell
CompanyName          : Unknown
Properties           : {ConfigurationScope, UpdateAutomatically, DependsOn, Ensure…}

Tailspin [String] #ResourceName
{
    ConfigurationScope = [string]{ Machine | User }
    UpdateAutomatically = [bool]
    [DependsOn = [string[]]]
    [Ensure = [string]{ Absent | Present }]
    [PsDscRunAsCredential = [PSCredential]]
    [UpdateFrequency = [Int32]]
}

4: Implementieren der DSC-Ressourcenmethoden

Die Methoden der DSC-Ressource definieren, wie sie den aktuellen Zustand einer DSC-Ressource abrufen, anhand des gewünschten Zustands überprüfen und den gewünschten Zustand erzwingen.

Die Get-Methode

Die Get() -Methode ruft den aktuellen Zustand der DSC-Ressource ab. Sie wird verwendet, um eine DSC-Ressource manuell zu überprüfen und von der Test() -Methode aufgerufen.

Die Get() -Methode verfügt über keine Parameter und gibt eine Instanz der -Klasse als Ausgabe zurück. Für die Tailspin DSC-Ressource sieht die minimale Implementierung wie folgt aus:

[Tailspin] Get() {
    $CurrentState = [Tailspin]::new()
    return $CurrentState
}

Das einzige, was diese Implementierung tut, ist, eine Instanz der Tailspin-Klasse zu erstellen und zurückzugeben. Sie können die -Methode mit Invoke-DscResource aufrufen, um dieses Verhalten anzuzeigen.

Invoke-DscResource -Name Tailspin -Module ExampleResources -Method Get -Property @{
    ConfigurationScope  = 'User'
    UpdateAutomatically = $true
}
ConfigurationScope  Ensure UpdateAutomatically UpdateFrequency
------------------  ------ ------------------- ---------------
           Machine Present               False               0

Die Eigenschaften des zurückgegebenen Objekts sind alle auf ihren Standardwert festgelegt. Der Wert von $ConfigurationScope sollte immer der vom Benutzer angegebene Wert sein. Damit die Get() Methode nützlich ist, muss sie den tatsächlichen Zustand der DSC-Ressource zurückgeben.

[Tailspin] Get() {
    $CurrentState = [Tailspin]::new()

    $CurrentState.ConfigurationScope = $this.ConfigurationScope

    $this.CachedCurrentState = $CurrentState

    return $CurrentState
}

Die $this Variable verweist auf die Arbeitsinstanz der DSC-Ressource. Wenn Sie nun erneut verwenden Invoke-DscResource , $ConfigurationScope hat sie den richtigen Wert.

Invoke-DscResource -Name Tailspin -Module ExampleResources -Method Get -Property @{
    ConfigurationScope  = 'User'
    UpdateAutomatically = $true
}
ConfigurationScope  Ensure UpdateAutomatically UpdateFrequency
------------------  ------ ------------------- ---------------
              User Present               False               0

Als Nächstes muss die DSC-Ressource ermitteln, ob die Konfigurationsdatei vorhanden ist. Wenn dies der Fall ist, $Ensure sollte .Present Wenn dies nicht der Fall ist, $Ensure sollte .Absent

Der Speicherort der Konfigurationsdateien von TSToy hängt vom Betriebssystem und dem Konfigurationsbereich ab:

  • Für Windows-Computer:
    • Die Machine Konfigurationsdatei lautet %PROGRAMDATA%\TailSpinToys\tstoy\tstoy.config.json
    • Die User Konfigurationsdatei lautet %APPDATA%\TailSpinToys\tstoy\tstoy.config.json
  • Für Linux-Computer:
    • Die Machine Konfigurationsdatei lautet /etc/xdg/TailSpinToys/tstoy/tstoy.config.json
    • Die User Konfigurationsdatei lautet ~/.config/TailSpinToys/tstoy/tstoy.config.json
  • Für macOS-Computer:
    • Die Machine Konfigurationsdatei lautet /Library/Preferences/TailSpinToys/tstoy/tstoy.config.json
    • Die User Konfigurationsdatei lautet ~/Library/Preferences/TailSpinToys/tstoy/tstoy.config.json

Um diese Pfade zu behandeln, müssen Sie eine Hilfsmethode erstellen, GetConfigurationFile().

[string] GetConfigurationFile() {
    $FilePaths = @{
        Linux = @{
            Machine   = '/etc/xdg/TailSpinToys/tstoy/tstoy.config.json'
            User      = '~/.config/TailSpinToys/tstoy/tstoy.config.json'
        }
        MacOS = @{
            Machine   = '/Library/Preferences/TailSpinToys/tstoy/tstoy.config.json'
            User      = '~/Library/Preferences/TailSpinToys/tstoy/tstoy.config.json'
        }
        Windows = @{
            Machine = "$env:ProgramData\TailSpinToys\tstoy\tstoy.config.json"
            User    = "$env:APPDATA\TailSpinToys\tstoy\tstoy.config.json"
        }
    }

    $Scope = $this.ConfigurationScope.ToString()

    if ($Global:PSVersionTable.PSVersion.Major -lt 6 -or $Global:IsWindows) {
        return $FilePaths.Windows.$Scope
    } elseif ($Global:IsLinux) {
        return $FilePaths.Linux.$Scope
    } else {
        return $FilePaths.MacOS.$Scope
    }
}

Um diese neue Methode zu testen, führen Sie die using -Anweisung aus, um die Klassen und Enumerationen des ExampleResources-Moduls in Ihre aktuelle Sitzung zu laden.

using module ./ExampleResources.psd1
$Example = [Tailspin]::new()
$Example
$Example.GetConfigurationFile()
$Example.ConfigurationScope = 'User'
$Example.GetConfigurationFile()
Ensure  ConfigurationScope UpdateAutomatically UpdateFrequency
------- ------------------ ------------------- ---------------
Present            Machine               False               0

C:\ProgramData\TailSpinToys\tstoy\tstoy.config.json

C:\Users\mikey\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json

Öffnen Sie Helpers.ps1 in VS Code. Kopieren Sie die Pfade für die Konfigurationsdateien, fügen Sie sie in das Skript ein, und weisen Sie sie und zu $TSToyMachinePath$TSToyUserPath. Die Datei sollte wie folgt aussehen:

$env:PSModulePath += "<separator>$pwd"
$TSToyMachinePath = '<machine configuration file path>'
$TSToyUserPath = '<user configuration file path>'

Beenden Sie das Terminal in VS Code, und öffnen Sie ein neues Terminal. Punktquelle Helpers.ps1.

. ./Helpers.ps1

Jetzt können Sie den Rest der Get() Methode schreiben.

[Tailspin] Get() {
    $CurrentState = [Tailspin]::new()

    $CurrentState.ConfigurationScope = $this.ConfigurationScope

    $FilePath = $this.GetConfigurationFile()

    if (!(Test-Path -Path $FilePath)) {
        $CurrentState.Ensure = [TailspinEnsure]::Absent

        $this.CachedCurrentState = $CurrentState

        return $CurrentState
    }

    $Data = Get-Content -Raw -Path $FilePath |
        ConvertFrom-Json -ErrorAction Stop

    $this.CachedData = $Data

    if ($null -ne $Data.Updates.Automatic) {
        $CurrentState.UpdateAutomatically = $Data.Updates.Automatic
    }

    if ($null -ne $Data.Updates.CheckFrequency) {
        $CurrentState.UpdateFrequency = $Data.Updates.CheckFrequency
    }

    $this.CachedCurrentState = $CurrentState

    return $CurrentState
}

Nachdem Sie den Pfad der $ConfigurationScope Konfigurationsdatei festgelegt und ermittelt haben, überprüft die Methode, ob die Datei vorhanden ist. Wenn es nicht vorhanden ist, müssen Sie das Ergebnis auf festlegen $EnsureAbsent und zurückgeben.

Wenn die Datei vorhanden ist, muss die Methode den Inhalt aus JSON konvertieren, um den aktuellen Zustand der Konfiguration zu erstellen. Als Nächstes überprüft die -Methode, ob die Schlüssel über einen Wert verfügen, bevor sie sie den Eigenschaften des aktuellen Zustands zuweisen. Wenn sie nicht angegeben werden, muss die DSC-Ressource sie als nicht festgelegt und im Standardzustand betrachten.

An diesem Punkt speichert die DSC-Ressource die Daten zwischen. Das Zwischenspeichern der Daten ermöglicht es Ihnen, die Daten während der Entwicklung zu überprüfen und ist bei der Implementierung der Set() Methode nützlich.

Sie können dieses Verhalten lokal überprüfen.

$GetParameters = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Method   = 'Get'
    Property = @{
        ConfigurationScope = 'User'
    }
}

Invoke-DscResource @GetParameters
New-Item -Path $TSToyUserPath -Force
Invoke-DscResource @GetParameters
ConfigurationScope Ensure UpdateAutomatically UpdateFrequency
------------------ ------ ------------------- ---------------
              User Absent               False               0

    Directory: C:\Users\mikey\AppData\Roaming\TailSpinToys\tstoy

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           9/15/2022  3:43 PM              0 tstoy.config.json

ConfigurationScope  Ensure UpdateAutomatically UpdateFrequency
------------------  ------ ------------------- ---------------
              User Present               False               0

Öffnen Sie die User Bereichskonfigurationsdatei in VS Code.

code $TSToyUserPath

Kopieren Sie diese JSON-Konfiguration in die Datei, und speichern Sie sie.

{
    "unmanaged_key": true,
    "updates": {
        "automatic": true,
        "checkFrequency": 30
    }
}

Rufen Sie erneut auf Invoke-DscResource , und sehen Sie sich die Werte in den Ergebnissen an.

Invoke-DscResource @GetParameters
ConfigurationScope  Ensure UpdateAutomatically UpdateFrequency
------------------  ------ ------------------- ---------------
              User Present                True              30

Die Get() Methode gibt jetzt genaue Informationen über den aktuellen Zustand der DSC-Ressource zurück.

Behandlungsgründe

Für computerkonfigurationsfähige DSC-Ressourcen muss die Get() Methode auch die Reasons-Eigenschaft auffüllen. Erstellen Sie zu diesem Zweck die GetReasons() -Methode. Es sollte ein Array von ExampleResourcesReason-Objekten zurückgeben und ein einzelnes Tailspin-Objekt als Eingabe verwenden.

[ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
    [ExampleResourcesReason[]]$DefinedReasons = @()

    return $DefinedReasons
}

Als Nächstes muss die Methode die Gültigkeit jeder konfigurierbaren Einstellung überprüfen. Für jede Einstellung muss die -Methode einen ExampleResourcesReason-Wert zurückgeben, der den Zustand identifiziert und beschreibt.

Die erste zu überprüfende Einstellung ist die $Ensure -Eigenschaft. Wenn $Ensure der Zustand nicht vorhanden ist, sind alle anderen Eigenschaften falsch, da die Konfigurationsdatei vorhanden ist, wenn sie nicht oder nicht vorhanden ist, wenn sie sollte.

Die -Methode muss einen Grund mit dem richtigen Code und einem sinnvollen Ausdruck definieren. Der Code hat immer das Format <ResourceName>.<ResourceName>.<PropertyName>. Der Ausdruck ist immer ein Satz, der die Überprüfung beschreibt, gefolgt von Sätzen, die den erwarteten Zustand und den tatsächlichen Zustand beschreiben.

[ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
    [ExampleResourcesReason[]]$DefinedReasons = @()

    $FilePath = $this.GetConfigurationFile()

    if ($this.Ensure -eq [TailspinEnsure]::Present) {
        $Expected = "Expected configuration file to exist at '$FilePath'."
    } else {
        $Expected = "Expected configuration file not to exist at '$FilePath'."
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Present) {
        $Actual = "The configuration file exists at '$FilePath'."
    } else {
        $Actual = "The configuration file was not found at '$FilePath'."
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.Ensure"
        Phrase = @(
            "Checked existence of the TSToy configuration file in the $($this.ConfigurationScope) scope."
            $Expected
            $Actual
        ) -join "`n`t"
    }

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $DefinedReasons
    }

    return $DefinedReasons
}

Wenn $Ensure sich der Zustand nicht nicht befindet, sollte die -Methode überprüfen, ob der gewünschte Zustand ist Absent. Wenn dies der Fall ist, gibt es keine anderen Eigenschaften, die nicht im Zustand sein können, da die Konfigurationsdatei nicht vorhanden ist und nicht vorhanden sein sollte.

[ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
    [ExampleResourcesReason[]]$DefinedReasons = @()

    $FilePath = $this.GetConfigurationFile()

    if ($this.Ensure -eq [TailspinEnsure]::Present) {
        $Expected = "Expected configuration file to exist at '$FilePath'."
    } else {
        $Expected = "Expected configuration file not to exist at '$FilePath'."
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Present) {
        $Actual = "The configuration file exists at '$FilePath'."
    } else {
        $Actual = "The configuration file was not found at '$FilePath'."
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.Ensure"
        Phrase = @(
            "Checked existence of the TSToy configuration file in the $($this.ConfigurationScope) scope."
            $Expected
            $Actual
        ) -join "`n`t"
    }

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $DefinedReasons
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $DefinedReasons
    }

    return $DefinedReasons
}

Wenn $Ensure ist und die Datei vorhanden ist Present , muss die Methode die verbleibenden konfigurierbaren Eigenschaften überprüfen.

Die Überprüfung der $UpdateAutomatically Eigenschaft ist einfach, da es sich um einen obligatorischen und booleschen Wert handelt.

[ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
    [ExampleResourcesReason[]]$DefinedReasons = @()

    $FilePath = $this.GetConfigurationFile()

    if ($this.Ensure -eq [TailspinEnsure]::Present) {
        $Expected = "Expected configuration file to exist at '$FilePath'."
    } else {
        $Expected = "Expected configuration file not to exist at '$FilePath'."
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Present) {
        $Actual = "The configuration file exists at '$FilePath'."
    } else {
        $Actual = "The configuration file was not found at '$FilePath'."
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.Ensure"
        Phrase = @(
            "Checked existence of the TSToy configuration file in the $($this.ConfigurationScope) scope."
            $Expected
            $Actual
        ) -join "`n`t"
    }

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $DefinedReasons
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $DefinedReasons
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.UpdateAutomatically"
        Phrase = (@(
                "Checked value of the 'updates.automatic' key in the TSToy configuration file."
                "Expected boolean value of '$($this.UpdateAutomatically)'"
                "Actual boolean value of '$($CurrentState.UpdateAutomatically)'"
            ) -join "`n`t")
    }

    return $DefinedReasons
}

Die letzte zu überprüfende Eigenschaft ist $UpdateFrequency. Diese Überprüfung kann kurzgeschlossen werden, wenn der Wert der -Eigenschaft ist 0. Wenn die Eigenschaft angegeben ist, liegt sie immer zwischen 1 und 90. Das bedeutet, dass ein Wert von 0 angibt, dass die Eigenschaft nicht verwaltet wird.

[ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
    [ExampleResourcesReason[]]$DefinedReasons = @()

    $FilePath = $this.GetConfigurationFile()

    if ($this.Ensure -eq [TailspinEnsure]::Present) {
        $Expected = "Expected configuration file to exist at '$FilePath'."
    } else {
        $Expected = "Expected configuration file not to exist at '$FilePath'."
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Present) {
        $Actual = "The configuration file exists at '$FilePath'."
    } else {
        $Actual = "The configuration file was not found at '$FilePath'."
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.Ensure"
        Phrase = @(
            "Checked existence of the TSToy configuration file in the $($this.ConfigurationScope) scope."
            $Expected
            $Actual
        ) -join "`n`t"
    }

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $DefinedReasons
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $DefinedReasons
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.UpdateAutomatically"
        Phrase = (@(
                "Checked value of the 'updates.automatic' key in the TSToy configuration file."
                "Expected boolean value of '$($this.UpdateAutomatically)'"
                "Actual boolean value of '$($CurrentState.UpdateAutomatically)'"
            ) -join "`n`t")
    }

    return $DefinedReasons

    # Short-circuit the check; UpdateFrequency isn't defined by caller
    if ($this.UpdateFrequency -eq 0) {
        return $DefinedReasons
    }
}

Schließlich muss die Methode den gewünschten und aktuellen Zustand der $UpdateFrequency -Eigenschaft vergleichen und einen Grund definieren, wenn sie sich nicht im Zustand befinden.

[ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
    [ExampleResourcesReason[]]$DefinedReasons = @()

    $FilePath = $this.GetConfigurationFile()

    if ($this.Ensure -eq [TailspinEnsure]::Present) {
        $Expected = "Expected configuration file to exist at '$FilePath'."
    } else {
        $Expected = "Expected configuration file not to exist at '$FilePath'."
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Present) {
        $Actual = "The configuration file exists at '$FilePath'."
    } else {
        $Actual = "The configuration file was not found at '$FilePath'."
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.Ensure"
        Phrase = @(
            "Checked existence of the TSToy configuration file in the $($this.ConfigurationScope) scope."
            $Expected
            $Actual
        ) -join "`n`t"
    }

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $DefinedReasons
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $DefinedReasons
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.UpdateAutomatically"
        Phrase = (@(
                "Checked value of the 'updates.automatic' key in the TSToy configuration file."
                "Expected boolean value of '$($this.UpdateAutomatically)'"
                "Actual boolean value of '$($CurrentState.UpdateAutomatically)'"
            ) -join "`n`t")
    }

    # Short-circuit the check; UpdateFrequency isn't defined by caller
    if ($this.UpdateFrequency -eq 0) {
        return $DefinedReasons
    }

    $DefinedReasons += [ExampleResourcesReason]@{
        Code   = "Tailspin.Tailspin.UpdateFrequency"
        Phrase = (@(
                "Checked value of the 'updates.checkFrequency' key in the TSToy configuration file."
                "Expected integer value of '$($this.UpdateFrequency)'."
                "Actual integer value of '$($CurrentState.UpdateFrequency)'."
            ) -join "`n`t")
    }

    return $DefinedReasons
}

Wenn die GetReasons() -Methode implementiert ist, muss die Get() -Methode aktualisiert werden, um sie aufzurufen, bevor der aktuelle Zustand zurückgegeben wird.

[Tailspin] Get() {
    $CurrentState = [Tailspin]::new()

    $CurrentState.ConfigurationScope = $this.ConfigurationScope

    $FilePath = $this.GetConfigurationFile()

    if (!(Test-Path -Path $FilePath)) {
        $CurrentState.Ensure = [TailspinEnsure]::Absent
        $CurrentState.Reasons = $this.GetReasons($CurrentState)

        $this.CachedCurrentState = $CurrentState

        return $CurrentState
    }

    $Data = Get-Content -Raw -Path $FilePath |
    ConvertFrom-Json -ErrorAction Stop

    $this.CachedData = $Data

    if ($null -ne $Data.Updates.Automatic) {
        $CurrentState.UpdateAutomatically = $Data.Updates.Automatic
    }

    if ($null -ne $Data.Updates.CheckFrequency) {
        $CurrentState.UpdateFrequency = $Data.Updates.CheckFrequency
    }

    $CurrentState.Reasons = $this.GetReasons($CurrentState)

    $this.CachedCurrentState = $CurrentState

    return $CurrentState
}

Wenn die Implementierung aktualisiert wird, können Sie das Verhalten überprüfen und feststellen, dass die Gründe gemeldet werden:

$SharedParameters = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        Ensure              = 'Present'
        UpdateAutomatically = $false
    }
}

Invoke-DscResource -Method Get @SharedParameters

$SharedParameters.Property.UpdateAutomatically = $true
Invoke-DscResource -Method Get @SharedParameters

$SharedParameters.Property.UpdateFrequency = 1
Invoke-DscResource -Method Get @SharedParameters
ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 1
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'False'
                        Actual boolean value of 'True'
                      }

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 1
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'True'
                      }

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 1
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'True'
                      ,
                      Tailspin.Tailspin.UpdateFrequency:
                        Checked value of the 'updates.checkFrequency' key in
                      the TSToy configuration file.
                        Expected integer value of '1'.
                        Actual integer value of '1'.
                      }

Die Testmethode

Wenn die Get() -Methode implementiert ist, können Sie überprüfen, ob der aktuelle Zustand mit dem gewünschten Zustand kompatibel ist.

Die Test() minimale Implementierung der Methoden gibt immer zurück $true.

[bool] Test() {
    return $true
}

Sie können dies überprüfen, indem Sie Invoke-DscResource ausführen.

$SharedParameters = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope = 'User'
        UpdateAutomatically = $false
    }
}

Invoke-DscResource -Method Get @SharedParameters
Invoke-DscResource -Method Test @SharedParameters
ConfigurationScope  Ensure UpdateAutomatically UpdateFrequency
------------------  ------ ------------------- ---------------
              User Present                True              30

InDesiredState
--------------
          True

Sie müssen die Test() Methode genau angeben, ob sich die DSC-Ressource im gewünschten Zustand befindet. Die Test() -Methode sollte immer die Get() -Methode aufrufen, damit der aktuelle Zustand mit dem gewünschten Zustand verglichen werden kann. Überprüfen Sie dann, ob die $Ensure Eigenschaft richtig ist. Wenn dies nicht der Fall ist, geben Sie sofort zurück $false . Wenn sich die $Ensure Eigenschaft außerhalb des gewünschten Zustands befindet, sind keine weiteren Überprüfungen erforderlich.

[bool] Test() {
    $CurrentState = $this.Get()

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $false
    }

    return $true
}

Jetzt können Sie das aktualisierte Verhalten überprüfen.

$TestParameters = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        UpdateAutomatically = $false
        Ensure              = 'Absent'
    }
}

Invoke-DscResource -Method Test @TestParameters

$TestParameters.Property.Ensure = 'Present'

Invoke-DscResource -Method Test @TestParameters
InDesiredState
--------------
         False

InDesiredState
--------------
          True

Überprüfen Sie als Nächstes, ob der Wert von $Ensure ist Absent. Wenn die Konfigurationsdatei nicht vorhanden ist und nicht vorhanden sein sollte, gibt es keinen Grund, die verbleibenden Eigenschaften zu überprüfen.

[bool] Test() {
    $CurrentState = $this.Get()

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $false
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $true
    }

    return $true
}

Als Nächstes muss die -Methode den aktuellen Status der Eigenschaften vergleichen, die das Updateverhalten von TSToy verwalten. Überprüfen Sie zunächst, ob sich die $UpdateAutomatically Eigenschaft im richtigen Zustand befindet. Wenn dies nicht der Fall ist, geben Sie zurück $false.

[bool] Test() {
    $CurrentState = $this.Get()

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $false
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $true
    }

    if ($CurrentState.UpdateAutomatically -ne $this.UpdateAutomatically) {
        return $false
    }

    return $true
}

Um zu vergleichen $UpdateFrequency, müssen wir ermitteln, ob der Benutzer den Wert angegeben hat. Da $UpdateFrequency mit 0 initialisiert wird und das ValidateRange-Attribut der Eigenschaft angibt, dass es zwischen 1 und 90sein muss, wissen wir, dass der Wert von 0 angibt, dass die Eigenschaft nicht angegeben wurde.

Mit diesen Informationen sollte die Test() -Methode:

  1. Zurückgeben $true , wenn der Benutzer nicht angegeben hat $UpdateFrequency
  2. Gibt zurück $false , wenn der Benutzer angegeben $UpdateFrequency hat und der Wert des Systems nicht dem vom Benutzer angegebenen Wert entspricht.
  3. Rückgabe $true , wenn keine der vorherigen Bedingungen erfüllt war
[bool] Test() {
    $CurrentState = $this.Get()

    if ($CurrentState.Ensure -ne $this.Ensure) {
        return $false
    }

    if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
        return $true
    }

    if ($CurrentState.UpdateAutomatically -ne $this.UpdateAutomatically) {
        return $false
    }

    if ($this.UpdateFrequency -eq 0) {
        return $true
    }

    if ($CurrentState.UpdateFrequency -ne $this.UpdateFrequency) {
        return $false
    }

    return $true
}

Test() Die -Methode verwendet nun die folgende Reihenfolge der Vorgänge:

  1. Rufen Sie den aktuellen Status der TSToy-Konfiguration ab.
  2. Gibt zurück $false , wenn die Konfiguration vorhanden ist, wenn sie nicht vorhanden sein soll oder nicht vorhanden ist, wenn sie sollte.
  3. Gibt zurück $true , wenn die Konfiguration nicht vorhanden ist und nicht vorhanden sein soll.
  4. Gibt zurück $false , wenn die Einstellung für die automatische Aktualisierung der Konfiguration nicht mit der gewünschten Einstellung übereinstimmt.
  5. Gibt zurück $true , wenn der Benutzer keinen Wert für die Einstellung für die Updatehäufigkeit angegeben hat.
  6. Gibt zurück $false , wenn der vom Benutzer für die Einstellung für die Updatehäufigkeit angegebene Wert nicht mit der Einstellung der Konfiguration übereinstimmt.
  7. Gibt zurück $true , wenn keine der vorherigen Bedingungen erfüllt war.

Sie können die Test() Methode lokal überprüfen:

$SharedParameters = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        Ensure              = 'Present'
        UpdateAutomatically = $false
    }
}

Invoke-DscResource -Method Get @SharedParameters

Invoke-DscResource -Method Test @SharedParameters

$SharedParameters.Property.UpdateAutomatically = $true
Invoke-DscResource -Method Test @SharedParameters

$SharedParameters.Property.UpdateFrequency = 1
Invoke-DscResource -Method Test @SharedParameters
ConfigurationScope  Ensure UpdateAutomatically UpdateFrequency
------------------  ------ ------------------- ---------------
              User Present                True              30

InDesiredState
--------------
         False

InDesiredState
--------------
          True

InDesiredState
--------------
         False

Mit diesem Code kann die Test() -Methode genau bestimmen, ob sich die Konfigurationsdatei im gewünschten Zustand befindet.

Die Set-Methode

Nachdem die Get() Methoden und Test() nun zuverlässig funktionieren, können Sie die Set() Methode definieren, um den gewünschten Zustand tatsächlich zu erzwingen.

In der minimalen Implementierung bewirkt die Set() -Methode nichts.

[void] Set() {}

Zunächst muss ermittelt werden, Set() ob die DSC-Ressource erstellt, aktualisiert oder entfernt werden muss.

[void] Set() {
    if ($this.Test()) {
            return
    }

    $CurrentState = $this.CachedCurrentState

    $IsAbsent = $CurrentState.Ensure -eq [TailspinEnsure]::Absent
    $ShouldBeAbsent = $this.Ensure -eq [TailspinEnsure]::Absent

    if ($IsAbsent) {
        # Create
    } elseif ($ShouldBeAbsent) {
        # Remove
    } else {
        # Update
    }
}

Set() ruft zuerst die Test() -Methode auf, um festzustellen, ob tatsächlich etwas getan werden muss. Einige Tools wie das Computerkonfigurationsfeature von Azure Automanage stellen sicher, dass die Set() -Methode nur nach der Test() -Methode aufgerufen wird. Eine solche Garantie gibt es jedoch nicht, wenn Sie das Invoke-DscResource Cmdlet verwenden.

Da die Test() -Methode aufruft Get(), die den aktuellen Zustand zwischenspeichert, kann die DSC-Ressource auf den zwischengespeicherten aktuellen Zustand zugreifen, ohne die Get() -Methode erneut aufrufen zu müssen.

Als Nächstes muss die DSC-Ressource zwischen dem Erstellen, Entfernen und Aktualisieren der Konfigurationsdatei unterscheiden. Wenn die Konfigurationsdatei nicht vorhanden ist, wissen wir, dass sie erstellt werden sollte. Wenn die Konfigurationsdatei vorhanden ist und nicht, wissen wir, dass sie entfernt werden muss. Wenn die Konfigurationsdatei vorhanden ist und vorhanden sein sollte, wissen wir, dass sie aktualisiert werden muss.

Erstellen Sie drei neue Methoden, um diese Vorgänge zu verarbeiten, und rufen Sie sie bei Bedarf in der Set() -Methode auf. Der Rückgabetyp für alle drei sollte void sein.

[void] Set() {
    if ($this.Test()) {
            return
    }

    $CurrentState = $this.CachedCurrentState

    $IsAbsent = $CurrentState.Ensure -eq [TailspinEnsure]::Absent
    $ShouldBeAbsent = $this.Ensure -eq [TailspinEnsure]::Absent

    if ($IsAbsent) {
        $this.Create()
    } elseif ($ShouldBeAbsent) {
        $this.Remove()
    } else {
        $this.Update()
    }
}

[void] Create() {}
[void] Remove() {}
[void] Update() {}

Erstellen Sie außerdem eine neue Methode namens ToConfigJson(). Der Rückgabetyp sollte Zeichenfolge sein. Diese Methode konvertiert die DSC-Ressource in den JSON-Code, den die Konfigurationsdatei erwartet. Sie können mit der folgenden minimalen Implementierung beginnen:

[string] ToConfigJson() {
    $config = @{}

    return ($config | ConvertTo-Json)
}

Die ToConfigJson-Methode

Die minimale Implementierung gibt ein leeres JSON-Objekt als Zeichenfolge zurück. Damit es nützlich ist, muss die tatsächliche JSON-Darstellung der Einstellungen in der TSToy-Konfigurationsdatei zurückgegeben werden.

Füllen Sie zunächst die $config Hashtabelle mit der Einstellung für obligatorische automatische Updates vor, indem Sie den Schlüssel mit seinem updates Wert als Hashtabelle hinzufügen. Die Hashtabelle sollte den automatic Schlüssel enthalten. Weisen Sie dem Schlüssel den Wert der -Eigenschaft der automatic Klasse $UpdateAutomatically zu.

[string] ToConfigJson() {
    $config = @{
        updates = @{
            automatic = $this.UpdateAutomatically
        }
    }

    return ($config | ConvertTo-Json)
}

Dieser Code übersetzt die DSC-Ressourcendarstellung der TSToy-Einstellungen in die Struktur, die die TSToy-Konfigurationsdatei erwartet.

Als Nächstes muss die -Methode überprüfen, ob die -Klasse die Daten aus einer vorhandenen Konfigurationsdatei zwischengespeichert hat. Die zwischengespeicherten Daten ermöglichen es der DSC-Ressource, die definierten Einstellungen zu verwalten, ohne nicht verwaltete Einstellungen zu überschreiben oder zu entfernen.

[string] ToConfigJson() {
    $config = @{
        updates = @{
            automatic = $this.UpdateAutomatically
        }
    }

    if ($this.CachedData) {
        # Copy unmanaged settings without changing the cached values
        $this.CachedData |
            Get-Member -MemberType NoteProperty |
            Where-Object -Property Name -NE -Value 'updates' |
            ForEach-Object -Process {
                $setting = $_.Name
                $config.$setting = $this.CachedData.$setting
            }

        # Add the checkFrequency to the hashtable if it is set in the cache
        if ($frequency = $this.CachedData.updates.checkFrequency) {
            $config.updates.checkFrequency = $frequency
        }
    }

    # If the user specified an UpdateFrequency, use that value
    if ($this.UpdateFrequency -ne 0) {
        $config.updates.checkFrequency = $this.UpdateFrequency
    }

    return ($config | ConvertTo-Json)
}

Wenn die -Klasse die Einstellungen aus einer vorhandenen Konfiguration zwischengespeichert hat, erfolgt Folgendes:

  1. Überprüft die Eigenschaften der zwischengespeicherten Daten und sucht nach Eigenschaften, die von der DSC-Ressource nicht verwaltet werden. Wenn diese gefunden werden, fügt die Methode diese nicht verwalteten Eigenschaften in die $config Hashtabelle ein.

    Da die DSC-Ressource nur die Updateeinstellungen verwaltet, wird jede Einstellung mit Ausnahme von updates eingefügt.

  2. Überprüft, ob die checkFrequency Einstellung in updates festgelegt ist. Wenn er festgelegt ist, fügt die Methode diesen Wert in die $config Hashtabelle ein.

    Dieser Vorgang ermöglicht es der DSC-Ressource, die $UpdateFrequency Eigenschaft zu ignorieren, wenn der Benutzer sie nicht angibt.

  3. Schließlich muss die -Methode überprüfen, ob der Benutzer die $UpdateFrequency -Eigenschaft angegeben hat, und sie in die $config Hashtabelle einfügen.

Mit diesem Code ist die -Methode wie folgt ToConfigJson() :

  1. Gibt eine genaue JSON-Darstellung des gewünschten Zustands zurück, den die TSToy-Anwendung in ihrer Konfigurationsdatei erwartet.
  2. Berücksichtigt alle Einstellungen von TSToy, die von der DSC-Ressource nicht explizit verwaltet werden.
  3. Berücksichtigt den vorhandenen Wert für die Updatehäufigkeit von TSToy, wenn der Benutzer keinen angegeben hat, einschließlich der Nichtdefinition in der Konfigurationsdatei.

Um diese neue Methode zu testen, schließen Sie Ihr VS Code-Terminal, und öffnen Sie ein neues. Führen Sie die using -Anweisung aus, um die Klassen und Enumerationen des ExampleResources-Moduls in Ihre aktuelle Sitzung zu laden und das Skript zu helpers.ps1 dotieren.

using module ./ExampleResources.psd1
. ./Helpers.ps1
$Example = [Tailspin]::new()
Get-Content -Path $TSToyUserPath
$Example.ConfigurationScope = 'User'
$Example.ToConfigJson()

Bevor die Get() -Methode aufgerufen wird, ist der einzige Wert in der Ausgabe der ToJsonConfig-Methode der konvertierte Wert für die $UpdateAutomatically -Eigenschaft.

{
    "unmanaged_key": true,
    "updates": {
        "automatic": false,
        "checkFrequency": 30
    }
}

{
  "updates": {
    "automatic": false
  }
}
$Example.Get()
$Example.ToConfigJson()

Nachdem Sie aufgerufen Get()haben, enthält die Ausgabe einen nicht verwalteten Schlüssel der obersten Ebene, unmanaged_key. Es enthält auch die vorhandene Einstellung in der Konfigurationsdatei für $UpdateFrequency , da sie nicht explizit für die DSC-Ressource festgelegt wurde.

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : False
UpdateFrequency     : 30
Reasons             : {}

{
  "unmanaged_key": true,
  "updates": {
    "automatic": false,
    "checkFrequency": 30
  }
}
$Example.UpdateFrequency = 7
$Example.ToConfigJson()

Nachdem $UpdateFrequency festgelegt wurde, spiegelt die Ausgabe den angegebenen Wert wider.

{
  "unmanaged_key": true,
  "updates": {
    "automatic": false,
    "checkFrequency": 7
  }
}

Die Create-Methode

Um die Create() -Methode zu implementieren, müssen wir die vom Benutzer angegebenen Eigenschaften für die DSC-Ressource in den JSON-Code konvertieren, den TSToy in der Konfigurationsdatei erwartet, und sie in diese Datei schreiben.

[void] Create() {
    $ErrorActionPreference = 'Stop'

    $Json = $this.ToConfigJson()

    $FilePath   = $this.GetConfigurationFile()
    $FolderPath = Split-Path -Path $FilePath

    if (!(Test-Path -Path $FolderPath)) {
        New-Item -Path $FolderPath -ItemType Directory -Force
    }

    Set-Content -Path $FilePath -Value $Json -Encoding utf8 -Force
}

Die -Methode verwendet die ToConfigJson() -Methode, um den JSON-Code für die Konfigurationsdatei abzurufen. Es überprüft, ob der Ordner der Konfigurationsdatei vorhanden ist, und erstellt ihn bei Bedarf. Schließlich wird die Konfigurationsdatei erstellt und der JSON-Code in sie geschrieben.

Die Remove-Methode

Die Remove() -Methode weist das einfachste Verhalten auf. Wenn die Konfigurationsdatei vorhanden ist, löschen Sie sie.

[void] Remove() {
    Remove-Item -Path $this.GetConfigurationFile() -Force -ErrorAction Stop
}

Die Update-Methode

Die Update() Implementierung der Methode ähnelt der Create-Methode . Es muss die vom Benutzer angegebenen Eigenschaften für die DSC-Ressource in den JSON-Code konvertieren, den TSToy in seiner Konfigurationsdatei erwartet, und die Einstellungen in dieser Datei ersetzen.

[void] Update() {
    $ErrorActionPreference = 'Stop'

    $Json = $this.ToConfigJson()
    $FilePath   = $this.GetConfigurationFile()

    Set-Content -Path $FilePath -Value $Json -Encoding utf8 -Force
}

5: Manuelles Testen einer DSC-Ressource

Nachdem die DSC-Ressource vollständig implementiert ist, können Sie ihr Verhalten jetzt testen.

Schließen Sie vor dem Testen Ihr VS Code-Terminal, und öffnen Sie ein neues Terminal. Punktquelle für das Helpers.ps1 Skript. Erstellen Sie für jedes Testszenario die Hashtabelle, die $DesiredState die freigegebenen Parameter enthält, und rufen Sie die Methoden in der folgenden Reihenfolge auf:

  1. Get(), um den Anfangszustand der DSC-Ressource abzurufen
  2. Test(), um zu sehen, ob die DSC-Ressource den gewünschten Zustand ansieht
  3. Set(), um den gewünschten Zustand zu erzwingen
  4. Test(), um zu sehen, ob die DSC-Ressource es als richtig festgelegt betrachtet
  5. Get(), um den endgültigen Zustand der DSC-Ressource zu bestätigen

Szenario: TSToy sollte im Benutzerbereich nicht automatisch aktualisiert werden

In diesem Szenario muss die vorhandene Konfiguration im Benutzerbereich so konfiguriert werden, dass sie nicht automatisch aktualisiert wird. Alle anderen Einstellungen sollten unverändert bleiben.

. ./Helpers.ps1

$DesiredState = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        UpdateAutomatically = $false
        Ensure              = 'Present'
    }
}

Get-Content -Path $TSToyUserPath

Invoke-DscResource @DesiredState -Method Get
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Set
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Get

Get-Content -Path $TSToyUserPath
{
    "unmanaged_key": true,
    "updates": {
        "automatic": true,
        "checkFrequency": 30
    }
}

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 30
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'False'
                        Actual boolean value of 'True'
                      }

InDesiredState : False

RebootRequired : False

InDesiredState : True

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : False
UpdateFrequency     : 30
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'False'
                        Actual boolean value of 'False'
                      }

{
  "unmanaged_key": true,
  "updates": {
    "automatic": false,
    "checkFrequency": 30
  }
}

Szenario: Tailspin sollte nach jedem Zeitplan im Benutzerbereich automatisch aktualisiert werden.

In diesem Szenario muss die vorhandene Konfiguration im Benutzerbereich so konfiguriert werden, dass sie automatisch aktualisiert wird. Alle anderen Einstellungen sollten unverändert bleiben.

. ./Helpers.ps1

$DesiredState = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        UpdateAutomatically = $true
        Ensure              = 'Present'
    }
}

Get-Content -Path $TSToyUserPath

Invoke-DscResource @DesiredState -Method Get
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Set
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Get

Get-Content -Path $TSToyUserPath
{
  "unmanaged_key": true,
  "updates": {
    "automatic": false,
    "checkFrequency": 30
  }
}

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : False
UpdateFrequency     : 30
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'False'
                      }

InDesiredState : False

RebootRequired : False

InDesiredState : True

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 30
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'True'
                      }

{
  "unmanaged_key": true,
  "updates": {
    "automatic": true,
    "checkFrequency": 30
  }
}

Szenario: TSToy sollte im Benutzerbereich täglich automatisch aktualisiert werden.

In diesem Szenario muss die vorhandene Konfiguration im Benutzerbereich so konfiguriert werden, dass sie automatisch und täglich aktualisiert wird. Alle anderen Einstellungen sollten unverändert bleiben.

. ./Helpers.ps1

$DesiredState = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        UpdateAutomatically = $true
        UpdateFrequency     = 1
        Ensure              = 'Present'
    }
}

Get-Content -Path $TSToyUserPath

Invoke-DscResource @DesiredState -Method Get
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Set
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Get

Get-Content -Path $TSToyUserPath
{
  "unmanaged_key": true,
  "updates": {
    "automatic": true,
    "checkFrequency": 30
  }
}

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 30
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'True'
                      ,
                      Tailspin.Tailspin.UpdateFrequency:
                        Checked value of the 'updates.checkFrequency' key in
                      the TSToy configuration file.
                        Expected integer value of '1'.
                        Actual integer value of '30'.
                      }

InDesiredState : False

RebootRequired : False

InDesiredState : True

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 1
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file to exist at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'True'
                      ,
                      Tailspin.Tailspin.UpdateFrequency:
                        Checked value of the 'updates.checkFrequency' key in
                      the TSToy configuration file.
                        Expected integer value of '1'.
                        Actual integer value of '1'.
                      }

{
  "unmanaged_key": true,
  "updates": {
    "checkFrequency": 1,
    "automatic": true
  }
}

Szenario: TSToy sollte keine Benutzerbereichskonfiguration haben

In diesem Szenario sollte die Konfigurationsdatei für TSToy im Benutzerbereich nicht vorhanden sein. Wenn dies der Fall ist, sollte die DSC-Ressource die Datei löschen.

. ./Helpers.ps1

$DesiredState = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'User'
        UpdateAutomatically = $false
        Ensure              = 'Absent'
    }
}

Get-Content -Path $TSToyUserPath

Invoke-DscResource @DesiredState -Method Get
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Set
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Get

Test-Path -Path $TSToyUserPath
{
  "unmanaged_key": true,
  "updates": {
    "checkFrequency": 1,
    "automatic": true
  }
}

ConfigurationScope  : User
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 1
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file not to exist at 'C:\Users\ml
                      ombardi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.j
                      son'.
                        The configuration file exists at 'C:\Users\mlombardi\App
                      Data\Roaming\TailSpinToys\tstoy\tstoy.config.json'.
                      }

InDesiredState : False

RebootRequired : False

InDesiredState : True

ConfigurationScope  : User
Ensure              : Absent
UpdateAutomatically : False
UpdateFrequency     : 0
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the User scope.
                        Expected configuration file not to exist at 'C:\Users\ml
                      ombardi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.j
                      son'.
                        The configuration file was not found at 'C:\Users\mlomba
                      rdi\AppData\Roaming\TailSpinToys\tstoy\tstoy.config.json'
                      .
                      }

False

Szenario: TSToy sollte automatisch jede Woche im Computerbereich aktualisiert werden.

In diesem Szenario gibt es keine definierte Konfiguration im Computerbereich. Der Computerbereich muss so konfiguriert werden, dass er automatisch und täglich aktualisiert wird. Die DSC-Ressource sollte die Datei und alle übergeordneten Ordner nach Bedarf erstellen.

. ./Helpers.ps1

$DesiredState = @{
    Name     = 'Tailspin'
    Module   = 'ExampleResources'
    Property = @{
        ConfigurationScope  = 'Machine'
        UpdateAutomatically = $true
        Ensure              = 'Present'
    }
}

Test-Path -Path $TSToyMachinePath, (Split-Path -Path $TSToyMachinePath)

Invoke-DscResource @DesiredState -Method Get
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Set
Invoke-DscResource @DesiredState -Method Test
Invoke-DscResource @DesiredState -Method Get

Get-Content -Path $TSToyMachinePath
False
False

ConfigurationScope  : Machine
Ensure              : Absent
UpdateAutomatically : False
UpdateFrequency     : 0
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the Machine scope.
                        Expected configuration file to exist at
                      'C:\ProgramData\TailSpinToys\tstoy\tstoy.config.json'.
                        The configuration file was not found at
                      'C:\ProgramData\TailSpinToys\tstoy\tstoy.config.json'.
                      }

InDesiredState : False

RebootRequired : False

InDesiredState : True

ConfigurationScope  : Machine
Ensure              : Present
UpdateAutomatically : True
UpdateFrequency     : 0
Reasons             : {
                      Tailspin.Tailspin.Ensure:
                        Checked existence of the TSToy configuration file in
                      the Machine scope.
                        Expected configuration file to exist at
                      'C:\ProgramData\TailSpinToys\tstoy\tstoy.config.json'.
                        The configuration file exists at
                      'C:\ProgramData\TailSpinToys\tstoy\tstoy.config.json'.
                      ,
                      Tailspin.Tailspin.UpdateAutomatically:
                        Checked value of the 'updates.automatic' key in the
                      TSToy configuration file.
                        Expected boolean value of 'True'
                        Actual boolean value of 'True'
                      }

{
  "updates": {
    "automatic": true
  }
}

Überprüfung

In diesem Tutorial:

  1. Erstellen eines Gerüsts für ein PowerShell-Modul und Implementieren der Tailspin klassenbasierten DSC-Ressource
  2. Definiert die Eigenschaften der DSC-Ressource zum Verwalten des Updateverhaltens der TSToy-Anwendung im Computer- und Benutzerbereich mit Überprüfung für diese Eigenschaften
  3. Implementierte Enumerationen für die $Ensure Eigenschaften und $ConfigurationScope
  4. Implementieren der ExampleResourcesReason -Klasse zum Melden von Zustandsüberschreitungen einer Ressource in der Computerkonfiguration
  5. Implementierung der GetConfigurationFile() Hilfsmethode, um den Speicherort der TSToy-Anwendungskonfiguration im Computer- und Benutzerbereich plattformübergreifend zuverlässig zu ermitteln
  6. Get() Die -Methode wurde implementiert, um den aktuellen Zustand der DSC-Ressource abzurufen und zur Verwendung in den Test() Methoden und Set() zwischenzuspeichern.
  7. GetReasons() Die Hilfsmethode wurde implementiert, um zu überprüfen, ob sich die DSC-Ressource im gewünschten Zustand befindet, und, falls dies nicht der Fall ist, um aufzulisten, wie sich der Zustand nicht befindet.
  8. Test() Die -Methode wurde implementiert, um den aktuellen Status des TSToy-Updateverhaltens in einem bestimmten Bereich anhand des gewünschten Zustands zu überprüfen.
  9. Die ToConfigJson-Methode wurde implementiert, um den gewünschten Zustand der DSC-Ressource in das JSON-Objekt zu konvertieren, das die TSToy-Anwendung für ihre Konfigurationsdatei benötigt, wobei nicht verwaltete Einstellungen berücksichtigt werden.
  10. Implementierung der Set() Methode und der Hilfsmethoden Create, Remove und Update , um den gewünschten Zustand für das Updateverhalten von TSToy in einem bestimmten Bereich zu erzwingen, um sicherzustellen, dass die DSC-Ressource keine unerwünschten Nebenwirkungen hat
  11. Manuell getestete gängige Verwendungsszenarien für die DSC-Ressource

Am Ende der Implementierung sieht Ihre Moduldefinition wie folgt aus:

[DscResource()]
class Tailspin {
    [DscProperty(Key)] [TailspinScope]
    $ConfigurationScope

    [DscProperty()] [TailspinEnsure]
    $Ensure = [TailspinEnsure]::Present

    [DscProperty(Mandatory)] [bool]
    $UpdateAutomatically

    [DscProperty()] [int] [ValidateRange(1, 90)]
    $UpdateFrequency

    [DscProperty(NotConfigurable)] [ExampleResourcesReason[]]
    $Reasons

    hidden [Tailspin] $CachedCurrentState
    hidden [PSCustomObject] $CachedData

    [Tailspin] Get() {
        $CurrentState = [Tailspin]::new()

        $CurrentState.ConfigurationScope = $this.ConfigurationScope

        $FilePath = $this.GetConfigurationFile()

        if (!(Test-Path -Path $FilePath)) {
            $CurrentState.Ensure = [TailspinEnsure]::Absent
            $CurrentState.Reasons = $this.GetReasons($CurrentState)

            $this.CachedCurrentState = $CurrentState

            return $CurrentState
        }

        $Data = Get-Content -Raw -Path $FilePath |
        ConvertFrom-Json -ErrorAction Stop

        $this.CachedData = $Data

        if ($null -ne $Data.Updates.Automatic) {
            $CurrentState.UpdateAutomatically = $Data.Updates.Automatic
        }

        if ($null -ne $Data.Updates.CheckFrequency) {
            $CurrentState.UpdateFrequency = $Data.Updates.CheckFrequency
        }

        $CurrentState.Reasons = $this.GetReasons($CurrentState)

        $this.CachedCurrentState = $CurrentState

        return $CurrentState
    }

    [bool] Test() {
        $CurrentState = $this.Get()

        if ($CurrentState.Ensure -ne $this.Ensure) {
            return $false
        }

        if ($CurrentState.UpdateAutomatically -ne $this.UpdateAutomatically) {
            return $false
        }

        if ($this.UpdateFrequency -eq 0) {
            return $true
        }

        if ($CurrentState.UpdateFrequency -ne $this.UpdateFrequency) {
            return $false
        }

        return $true
    }

    [void] Set() {
        if ($this.Test()) {
            return
        }

        $CurrentState = $this.CachedCurrentState

        $IsAbsent = $CurrentState.Ensure -eq [TailspinEnsure]::Absent
        $ShouldBeAbsent = $this.Ensure -eq [TailspinEnsure]::Absent

        if ($IsAbsent) {
            $this.Create()
        }
        elseif ($ShouldBeAbsent) {
            $this.Remove()
        }
        else {
            $this.Update()
        }
    }

    [string] GetConfigurationFile() {
        $FilePaths = @{
            Linux   = @{
                Machine = '/etc/xdg/TailSpinToys/tstoy/tstoy.config.json'
                User    = '~/.config/TailSpinToys/tstoy/tstoy.config.json'
            }
            MacOS   = @{
                Machine = '/Library/Preferences/TailSpinToys/tstoy/tstoy.config.json'
                User    = '~/Library/Preferences/TailSpinToys/tstoy/tstoy.config.json'
            }
            Windows = @{
                Machine = "$env:ProgramData\TailSpinToys\tstoy\tstoy.config.json"
                User    = "$env:APPDATA\TailSpinToys\tstoy\tstoy.config.json"
            }
        }

        $Scope = $this.ConfigurationScope.ToString()

        if ($Global:PSVersionTable.PSVersion.Major -lt 6 -or $Global:IsWindows) {
            return $FilePaths.Windows.$Scope
        }
        elseif ($Global:IsLinux) {
            return $FilePaths.Linux.$Scope
        }
        else {
            return $FilePaths.MacOS.$Scope
        }
    }

    [ExampleResourcesReason[]] GetReasons([Tailspin]$CurrentState) {
        [ExampleResourcesReason[]]$DefinedReasons = @()

        $FilePath = $this.GetConfigurationFile()

        if ($this.Ensure -eq [TailspinEnsure]::Present) {
            $Expected = "Expected configuration file to exist at '$FilePath'."
        } else {
            $Expected = "Expected configuration file not to exist at '$FilePath'."
        }

        if ($CurrentState.Ensure -eq [TailspinEnsure]::Present) {
            $Actual = "The configuration file exists at '$FilePath'."
        } else {
            $Actual = "The configuration file was not found at '$FilePath'."
        }

        $DefinedReasons += [ExampleResourcesReason]@{
            Code   = "Tailspin.Tailspin.Ensure"
            Phrase = @(
                "Checked existence of the TSToy configuration file in the $($this.ConfigurationScope) scope."
                $Expected
                $Actual
            ) -join "`n`t"
        }

        if ($CurrentState.Ensure -ne $this.Ensure) {
            return $DefinedReasons
        }

        if ($CurrentState.Ensure -eq [TailspinEnsure]::Absent) {
            return $DefinedReasons
        }

        $DefinedReasons += [ExampleResourcesReason]@{
            Code   = "Tailspin.Tailspin.UpdateAutomatically"
            Phrase = (@(
                    "Checked value of the 'updates.automatic' key in the TSToy configuration file."
                    "Expected boolean value of '$($this.UpdateAutomatically)'"
                    "Actual boolean value of '$($CurrentState.UpdateAutomatically)'"
                ) -join "`n`t")
        }

        # Short-circuit the check; UpdateFrequency isn't defined by caller
        if ($this.UpdateFrequency -eq 0) {
            return $DefinedReasons
        }

        $DefinedReasons += [ExampleResourcesReason]@{
            Code   = "Tailspin.Tailspin.UpdateFrequency"
            Phrase = (@(
                    "Checked value of the 'updates.checkFrequency' key in the TSToy configuration file."
                    "Expected integer value of '$($this.UpdateFrequency)'."
                    "Actual integer value of '$($CurrentState.UpdateFrequency)'."
                ) -join "`n`t")
        }

        return $DefinedReasons
    }

    [void] Create() {
        $ErrorActionPreference = 'Stop'

        $Json = $this.ToConfigJson()

        $FilePath = $this.GetConfigurationFile()

        $FolderPath = Split-Path -Path $FilePath

        if (!(Test-Path -Path $FolderPath)) {
            New-Item -Path $FolderPath -ItemType Directory -Force
        }

        Set-Content -Path $FilePath -Value $Json -Encoding utf8 -Force
    }

    [void] Remove() {
        Remove-Item -Path $this.GetConfigurationFile() -Force -ErrorAction Stop
    }

    [void] Update() {
        $ErrorActionPreference = 'Stop'

        $Json = $this.ToConfigJson()
        $FilePath = $this.GetConfigurationFile()

        Set-Content -Path $FilePath -Value $Json -Encoding utf8 -Force
    }

    [string] ToConfigJson() {
        $config = @{
            updates = @{
                automatic = $this.UpdateAutomatically
            }
        }

        if ($this.CachedData) {
            $this.CachedData |
                Get-Member -MemberType NoteProperty |
                Where-Object -Property Name -NE -Value 'updates' |
                ForEach-Object -Process {
                    $setting = $_.Name
                    $config.$setting = $this.CachedData.$setting
                }

            if ($frequency = $this.CachedData.updates.CheckFrequency) {
                $config.updates.checkFrequency = $frequency
            }
        }

        if ($this.UpdateFrequency -ne 0) {
            $config.updates.checkFrequency = $this.UpdateFrequency
        }

        return ($config | ConvertTo-Json)
    }
}

enum TailspinScope {
    Machine
    User
}

enum TailspinEnsure {
    Absent
    Present
}

class ExampleResourcesReason {
    [DscProperty()]
    [string] $Code

    [DscProperty()]
    [string] $Phrase

    [string] ToString() {
        return "`n$($this.Code):`n`t$($this.Phrase)`n"
    }
}

Bereinigen

Wenn Sie dieses Modul nicht weiter verwenden möchten, löschen Sie den ExampleResources Ordner und die darin enthaltenen Dateien.

Nächste Schritte

  1. Erfahren Sie mehr über klassenbasierte DSC-Ressourcen, erfahren Sie, wie sie funktionieren, und überlegen Sie, warum die DSC-Ressource in diesem Tutorial auf diese Weise implementiert ist.
  2. Informieren Sie sich über das Computerkonfigurationsfeature von Azure Automanage , um zu verstehen, wie Sie damit Ihre Systeme überwachen und konfigurieren können.
  3. Überlegen Sie, wie diese DSC-Ressource verbessert werden kann. Gibt es Edgefälle oder Features, die nicht verarbeitet werden? Aktualisieren Sie die Implementierung, um sie zu behandeln.