Udostępnij za pomocą


Zasoby DSC oparte na klasach

Zasoby DSC oparte na klasach zapewniają uproszczoną implementację zasobów DSC do zarządzania ustawieniami systemu. W tym artykule wyjaśniono ich strukturę i wymagania.

Struktura zasobu DSC opartego na klasach

Zasób DSC oparty na klasach jest zdefiniowany jako klasa programu PowerShell w pliku modułu (.psm1). Zasób DSC oparty na klasach nie ma specjalnych wymagań dotyczących miejsca, w którym jest zdefiniowany. Można go zdefiniować:

Niezależnie od tego, gdzie zasób DSC jest zdefiniowany, zasób DSC musi być wymieniony we właściwości DscResourcesToExport pliku manifestu modułu (.psd1). Polecenie cmdlet Get-DscResource , dynamiczne słowo kluczowe [Import-DSCResource] i sama konfiguracja DSC podczas kompilowania konfiguracji DSC zakończy się niepowodzeniem, jeśli zasób DSC nie jest wymieniony w manifeście.

Aby uzyskać więcej informacji na temat tworzenia manifestu modułu, zobacz New-ModuleManifest. Aby uzyskać więcej informacji na temat ustawień manifestu modułu, zobacz about_Module_Manifests.

Zasób DSC oparty na klasach musi:

  1. Użyj atrybutu DscResource .
  2. Zadeklaruj co najmniej jedną właściwość za pomocą atrybutu DscProperty . Co najmniej jedna z właściwości musi być właściwością klucza .
  3. Zaimplementuj Get()metody , Test()i Set() .
  4. Zdefiniuj konstruktor domyślny, jeśli definiuje on jakiekolwiek konstruktory alternatywne.

Atrybut DscResource

Definicja klasy musi mieć atrybut DscResource . Ten atrybut wskazuje, że klasa definiuje zasób DSC.

Aby dodać atrybut DscResource do klasy, zadeklaruj go w wierszu bezpośrednio przed definicją klasy.

[DscResource()]
class MyDscResource {
}

Oprócz identyfikowania klasy jako zasobu DSC atrybut DscResource stosuje walidację w czasie analizy do zasobu DSC opartego na klasie. Program PowerShell zgłasza błąd analizy dla definicji zasobu DSC opartego na klasach, gdy:

  • Co najmniej jedna z Get()metod , Test()i Set() jest niepoprawnie zdefiniowana lub jej brakuje
  • Klasa nie ma co najmniej jednej właściwości Key
  • Klasa definiuje konstruktor inny niż domyślny bez definiowania konstruktora domyślnego

Atrybut DscResource można również określić za pomocą właściwości RunAsCredential w celu określenia zachowania zasobu DSC opartego na klasie podczas korzystania z właściwości PsDscRunAsCredential :

  • Optional - Użytkownik może używać właściwości PsDscRunAsCredential z tym zasobem DSC. Jest to zachowanie domyślne. To zachowanie można również określić jako Default zamiast Optional.
  • NotSupported - Użytkownik nie może używać właściwości PsDscRunAsCredential z tym zasobem DSC.
  • Mandatory - Użytkownik musi użyć właściwości PsDscRunAsCredential z tym zasobem DSC.

Uwaga / Notatka

Chociaż można ustawić właściwość RunAsCredential dla zasobu DSC opartego na klasie, nie ma ona wpływu w przypadku użycia z DSC w wersji 2.0 lub nowszej. Właściwość PsDscRunAsCredential jest obsługiwana tylko w DSC w wersji 1.1 i wcześniejszych. Jeśli piszesz zasób DSC oparty na klasach i obsługujesz go w DSC w wersji 1.1, określenie tej właściwości w atrybucie DscResource zapewnia pewną przejrzystość i ulepszone środowisko użytkownika dla tego scenariusza.

Właściwości zasobu DSC opartego na klasach

Schemat zasobu DSC opartego na klasach jest definiowany przez właściwości klasy. Aby właściwość została rozpoznana jako część schematu, musi mieć atrybut DscProperty .

Definicja właściwości DscProperty określa, w jaki sposób DSC traktuje tę właściwość:

  • [DscProperty(Key)] - Wskazuje, że ta właściwość jednoznacznie identyfikuje wystąpienie tego zasobu DSC. Każdy zasób DSC musi mieć co najmniej jedną właściwość klucza . Jeśli zasób DSC ma więcej niż jedną właściwość klucza , te właściwości są używane razem w celu jednoznacznego zidentyfikowania wystąpienia zasobu DSC. Jeśli jakiekolwiek właściwości klucza zasobu DSC nie zostaną określone podczas korzystania z Invoke-DscResourcepolecenia cmdlet zgłasza błąd. Jeśli jakiekolwiek właściwości klucza nie zostaną określone podczas tworzenia konfiguracji DSC, skompilowanie konfiguracji spowoduje błąd.
  • [DscProperty(Mandatory)] - Wskazuje, że właściwość musi być określona podczas korzystania z tego zasobu DSC. Jeśli jakiekolwiek obowiązkowe właściwości zasobu DSC nie zostaną określone podczas korzystania z Invoke-DscResourcepolecenia cmdlet zgłasza błąd. Jeśli jakiekolwiek właściwości obowiązkowe nie zostaną określone podczas tworzenia konfiguracji DSC, skompilowanie konfiguracji zgłasza błąd.
  • [DscProperty(NotConfigurable)] - Wskazuje, że właściwość ma wartość ReadOnly. Nie jest to ustawienie, którym można zarządzać tego zasobu DSC, ale będzie zawierać wartość po wywołaniu Get() metody zasobu DSC.
  • [DscProperty()] - Wskazuje, że właściwość jest konfigurowalnym ustawieniem tego zasobu DSC. Określenie tej właściwości jest opcjonalne w przypadku używania Invoke-DscResource lub tworzenia konfiguracji DSC.

Podobnie jak wszystkie właściwości klasy programu PowerShell, właściwości zasobu DSC opartego na klasach muszą określać typ. Ten typ służy do sprawdzania poprawności określonego ustawienia podczas wywoływania Invoke-DscResource lub kompilowania konfiguracji DSC.

Rozważmy ten fragment definicji zasobu DSC opartego na MyDscResource klasach:

[DscResource()]
class MyDscResource {
    [DscProperty(Key)]
    [string] $Path

    [DscProperty(Mandatory)]
    [hashtable]$Settings

    [DscProperty(NotConfigurable)]
    [datetime] $LastModified

    [DscProperty()]
    [string] $Format = 'YAML'
}

Definiuje on cztery właściwości:

  • Path jest kluczową właściwością zasobu DSC i oczekuje, że uzyska ciąg dla jego wartości.
  • Settings jest obowiązkową właściwością zasobu DSC i oczekuje, że jego wartość zostanie pobrana z tabeli skrótów .
  • LastModified jest właściwością ReadOnly zasobu DSC i oczekuje, że uzyska wartość DateTime dla jej wartości z Get() metody.
  • Format jest opcjonalną właściwością zasobu DSC i oczekuje na pobranie ciągu dla jego wartości.

Domyślne wartości właściwości

Po utworzeniu wystąpienia zasobu DSC opartego na klasach używany jest domyślny konstruktor bez parametrów. O ile nie zastąpisz tego zachowania, domyślny konstruktor bez parametrów inicjalizuje każdą właściwość do wartości domyślnej dla jej typu. Jeśli właściwość jest zdefiniowana z jawną wartością domyślną, zamiast niej jest używana ta wartość. Aby uzyskać więcej informacji na temat konstruktorów dla zasobów DSC opartych na klasach, zobacz Konstruktory.

To, czy właściwość jest typem referencyjnym , czy typem wartości , określa wartość domyślną. Typy referencyjne są inicjowane na $null. Typy wartości są inicjowane do wartości określonej w ich definicji.

W przeciwieństwie do innych implementacji zasoby DSC oparte na klasach zarządzają wszystkimi zdefiniowanymi właściwościami, które mają atrybut DscProperty , nawet jeśli nie określisz tej właściwości w konfiguracji DSC lub podczas korzystania z Invoke-DscResource. Ponieważ właściwości typu wartości mają wartość domyślną inną niż null, nie ma możliwości, aby zasób DSC oparty na klasach odróżnił właściwość, która nie została określona, od takiej, która została określona jako wartość domyślna.

Ważne

W przypadku korzystania z zasobu DSC opartego na klasach wszystkie właściwości typu wartości, które nie są jawnie ustawione, są zawsze ustawiane na wartość domyślną zdefiniowaną w zasobie DSC.

Nie można użyć zasobu DSC opartego na klasach bez zarządzania każdą właściwością typu wartości zdefiniowaną dla tego zasobu DSC. W przeciwieństwie do innych zasobów DSC usunięcie właściwości z konfiguracji DSC lub z wywołania to Invoke-DscResource nie ignoruje stanu tej właściwości. Resetuje go do ustawień domyślnych.

Tylko właściwości typu referencyjnego mogą być niezarządzane dla zasobu DSC opartego na klasach.

Możesz sprawdzić, czy typ jest typem odwołania, czy wartości, sprawdzając jego BaseType.

function Test-IsValueType ($Object) {
    $base = $Object.GetType().BaseType
    while ($true) {
        switch ($base.FullName) {
            'System.Object' { return $false }
            'System.ValueType' { return $true }
            default {
                $base = $base.BaseType
            }
        }
    }
}

Test-IsValueType 'foo'
Test-IsValueType 5
False
True

Ta tabela zawiera kilka typów często używanych w zasobach DSC. Informuje, czy są to typy referencyjne, czy wartości, a jeśli są to typy wartości, jaka jest ich wartość domyślna po zainicjowaniu zasobu DSC.

Name Typ Wartość domyślna
System.Enum Wartość 0
System.Int32 Wartość 0
System.Double Wartość 0
System.DateTime Wartość 1 stycznia 0001 12:00:00
System.TimeSpan Wartość We wszystkich polach ustawiono wartość 0.
System.String Reference $null
System.Management.Automation.PSCredential Reference $null

Atrybuty właściwości walidacji

Właściwości zasobu DSC opartego na klasach mogą również używać atrybutów walidacji w celu ograniczenia wartości określonych przez użytkownika dla właściwości. Walidacja jest stosowana podczas kompilowania konfiguracji DSC lub wywoływania Invoke-DSCResource. VS Code nie weryfikuje wartości określonych w konfiguracji DSC podczas jej edytowania.

Ostrzeżenie

W przypadku korzystania z Invoke-DscResourceprogramu błędy walidacji właściwości nie zatrzymują polecenia cmdlet przed wywołaniem Get()metody , Test()or Set() . Aby zapobiec wywoływaniu metody przez polecenie cmdlet, gdy dane wejściowe nie powiodą się z atrybutem walidacji właściwości, określ wartość ErrorActionPreference jako Stop.

Definiowanie atrybutów walidacji właściwości jest prostsze niż implementowanie tej samej logiki w metodzie i jest wykrywalnymi metadanymi dotyczącymi klasy, która definiuje zasób DSC. Tam, gdzie to możliwe, lepiej jest jawnie określić wartości akceptowane przez właściwości zasobu DSC. Upraszcza to użytkowanie i zapewnia bezpieczniejsze i bardziej niezawodne działanie.

Rozważmy ten fragment definicji zasobu DSC opartego na MyDscResource klasach:

[DscResource()]
class MyDscResource {
    [DscProperty()]
    [string]
    [ValidateSet('JSON', 'YAML')]
    $Format
}

Używa atrybutu ValidateSet w celu ograniczenia prawidłowych wartości właściwości Format do JSON i YAML. Jeśli użyjesz Invoke-DscResource z nieprawidłową wartością w polu Format, polecenie cmdlet wystąpi w błędzie:

$Parameters = @{
    Name       = 'MyDscResource'
    ModuleName = 'MyDscResources'
    Method     = 'Get'
    Property   = @{
        Path     = '/Dsc/Example/config.yaml'
        Format   = 'Incorrect'
        Settings = @{
            Foo = 'Bar'
        }
    }
}
Invoke-DscResource @Parameters -ErrorAction Stop
Invoke-DscClassBasedResource: Exception setting "Format": "The argument
"Incorrect" does not belong to the set "YAML,JSON" specified by the
ValidateSet attribute. Supply an argument that is in the set and then
try the command again."

Aby uzyskać więcej informacji na temat atrybutów weryfikacji, zobacz about_Functions_Advanced_Parameters.

Właściwości wyliczenia

Aby uzyskać lepsze środowisko tworzenia i użytkownika niż przy użyciu atrybutu ValidateSet , można zdefiniować wyliczenie określające zestaw prawidłowych wartości.

Można na przykład zdefiniować wyliczenie FormatOption i użyć go jako typu właściwości Format zasobu DSC opartego na klasach:

enum FormatOption {
    JSON
    YAML
}

[DscResource()]
class MyDscResource {
    [DscProperty()]
    [FormatOption]
    $Format
}

Komunikat o błędzie dla nieprawidłowej wartości wyliczenia jest krótszy i bardziej przejrzysty niż w przypadku ValidateSet:

$Parameters = @{
    Name       = 'MyDscResource'
    ModuleName = 'MyDscResources'
    Method     = 'Get'
    Property   = @{
        Path     = '/Dsc/Example/config.yaml'
        Format   = 'Incorrect'
        Settings = @{}
    }
}
Invoke-DscResource @Parameters -ErrorAction Stop
Invoke-DscClassBasedResource: Exception setting "Format": "Cannot
convert value "Incorrect" to type "FormatOption". Error: "Unable to
match the identifier name Incorrect to a valid enumerator name. Specify
one of the following enumerator names and try again: JSON, YAML""

Wyliczenia są również przydatne, gdy trzeba użyć tej samej właściwości w kilku zasobach DSC opartych na klasach. Wyliczenie można zdefiniować raz i używać go wszędzie tam, gdzie jest to potrzebne, natomiast w przypadku atrybutu ValidateSet należy zaktualizować każdy zasób DSC, który współużytkuje właściwość.

Aby uzyskać więcej informacji na temat wyliczeń w programie PowerShell, zobacz about_Enum.

Właściwość Ensure

Wiele zasobów DSC ma właściwość Ensure , która kontroluje stan wystąpienia zasobu DSC. Na przykład zasób DSC w module PSDscResources ma właściwość Ensure , która przyjmuje wartości Present (wskazujące, że użytkownik powinien istnieć) i Absent (wskazujące, User że użytkownik nie powinien istnieć).

W przypadku zasobów DSC opartych na klasach sugerowanym rozwiązaniem jest utworzenie wyliczenia Ensure i użycie go dla wszystkich możliwych do zapewnienia zasobów DSC jako typu właściwości o nazwie Ensure. Przykład:

enum Ensure {
    Absent
    Present
}

[DscResource()]
class MyDscResource {
    [DscProperty()]
    [Ensure]
    $Ensure
}

Chociaż często zdarza się, że wyliczenie Ensure definiuje wartości Absent i Present, może definiować dowolne wartości, które mają sens dla zasobu DSC.

Korzystając z zasobu SimpleConfig DSC tego artykułu jako przykładu, zamiast tylko mieć Absent (plik konfiguracji nie powinien istnieć) i Present, możesz zdefiniować Upewnij się, że masz następujące wartości:

  • Absent - Konfiguracja nie powinna istnieć w określonej ścieżce. Jeśli tak się stanie, zasób DSC powinien usunąć go z systemu.
  • Exactly - Konfiguracja powinna istnieć w określonej ścieżce z ustawieniami zdefiniowanymi tylko we właściwości Ustawienia . Jeśli jakiekolwiek ustawienia mają nieprawidłową wartość, zasób DSC powinien je poprawić. Jeśli plik konfiguracyjny zawiera jakiekolwiek ustawienia, które nie zostały określone we właściwości Settings , powinien je usunąć.
  • Include - Konfiguracja powinna istnieć w określonej ścieżce z ustawieniami zdefiniowanymi we właściwości Ustawienia . Jeśli jakiekolwiek ustawienia mają nieprawidłową wartość, zasób DSC powinien je poprawić. Jeśli plik konfiguracyjny zawiera jakiekolwiek ustawienia, które nie zostały określone we właściwości Ustawienia , powinien je zignorować.
  • Present - Konfiguracja powinna istnieć w określonej ścieżce. Jeśli tak się nie stanie, zasób DSC powinien go utworzyć z ustawieniami zdefiniowanymi we właściwości Settings . Jeśli tak się stanie, zasób DSC powinien zgłosić wystąpienie jako będące w żądanym stanie, nawet jeśli ustawienia nie są zgodne z ustawieniami określonymi we właściwości Ustawienia .

To wyliczenie można zdefiniować w następujący sposób:

enum Ensure {
    Absent
    Exactly
    Include
    Present
}

Złożone właściwości

Niektóre właściwości zasobu DSC mogą mieć właściwości podrzędne. Na przykład właściwość Settings zasobu DSC tego artykułu SimpleConfig została określona wcześniej w tym artykule z typem Hashtable . Dzięki temu użytkownik może określić dowolne nazwy kluczy i dowolne typy wartości dla każdego klucza.

Zamiast tego, aby kontrolować prawidłowe opcje, można napisać klasę, która reprezentuje złożoną właściwość. Aby właściwości tej klasy były rozpoznawane przez DSC jako właściwości podrzędne, muszą mieć atrybut DscProperty .

class SimpleConfigSettings {
    [DscProperty()] [string]
    $ProfileName

    [DscProperty()] [string]
    $Description

    [DscProperty()] [int]
    [ValidateRange(0,90)]
    $CheckForUpdates
}

Klasa SimpleConfigSettings definiuje trzy ustawienia: ProfileName jako ciąg, Description jako ciąg i CheckForUpdates jako liczbę niepełną , której wartość musi należeć do zakresu od 0 do 90.

Uwaga / Notatka

Mimo że właściwości złożone są definiowane jako klasy, a ich właściwości podrzędne muszą mieć atrybut DscProperty , atrybut właściwości zasobu DSC jest jedynym, który stosuje wszelkie zmiany zachowania we właściwościach. Oznaczenie właściwości podrzędnych jako Klucz, Obowiązkowe lub Niekonfigurowalne nie ma wpływu na zachowanie certyfikatu DSC podczas kompilowania konfiguracji DSC lub używania Invoke-DscResourceprogramu .

Po zdefiniowaniu klasy może ona służyć jako właściwość zasobu DSC:

[DscResource()]
class SimpleConfig {
    [DscProperty(Mandatory)] [SimpleConfigSettings]
    $Settings
}

Po zdefiniowaniu ustawień jako typu SimpleConfigSettings użytkownicy uzyskują jasne informacje o wartości, którą muszą podać.

$Parameters = @{
    Name       = 'MyDscResource'
    ModuleName = 'MyDscResources'
    Method     = 'Get'
    Property   = @{
        Path   = '/Dsc/Example/config.yaml'
        Format = 'YAML'
        Settings  = @{ Name = 'Foo' }
    }
}

Invoke-DscResource @Parameters -ErrorAction Stop
Invoke-DscClassBasedResource: Exception setting "Settings": "Cannot
create object of type "SimpleConfigSettings". The Name property was not
found for the SimpleConfigSettings object. The available property is:
[ProfileName <System.String>] , [Description <System.String>] ,
[CheckForUpdates <System.Int32>]"

Właściwości złożone mogą mieć właściwości, które są również właściwościami złożonymi. Nie ma ograniczeń co do poziomu zagnieżdżenia, którego można użyć. Aby uzyskać najlepsze wrażenia użytkownika, ogranicz głębokość złożonych właściwości do trzech poziomów.

class SimpleConfigUpdateSettings {
    [DscProperty()] [int]
    [ValidateRange(0,90)]
    $Interval

    [DscProperty()] [string]
    $Url
}

class SimpleConfigSettings {
    [DscProperty()] [string]
    $ProfileName

    [DscProperty()] [string]
    $Description

    [DscProperty()] [SimpleConfigUpdateSettings]
    $Updates
}

[DscResource()]
class SimpleConfig {
    [DscProperty(Mandatory)] [SimpleConfigSettings]
    $Settings
}

W tym przykładzie pokazano, jak definiowanie zagnieżdżonych właściwości złożonych zapewnia walidację. Ta walidacja zawiera przydatne komunikaty o błędach podczas wywoływania Invoke-DscResource.

$Parameters = @{
    Name       = 'MyDscResource'
    ModuleName = 'MyDscResources'
    Method     = 'Get'
    Property   = @{
        Path     = '/Dsc/Example/config.yaml'
        Format   = 'YAML'
        Settings = @{
            ProfileName = 'Foo'
            Updates = @{
                Interval = 30
                Oops = 'Invalid property'
            }
        }
    }
}

Invoke-DscResource @Parameters -ErrorAction Stop
Invoke-DscClassBasedResource: Exception setting "Settings": "Cannot
create object of type "SimpleConfigSettings". Cannot create object of
type "SimpleConfigUpdateSettings". The Interval property was not found
for the SimpleConfigUpdateSettings object. The available property is:
[UpdateInterval <System.Int32>] , [UpdateUrl <System.String>]"

Właściwość Powody

Jeśli zasób DSC oparty na klasach jest przeznaczony do użycia z konfiguracją maszyny platformy Azure, zasób DSC musi mieć właściwość Reasons spełniającą następujące wymagania:

  • Musi być zadeklarowany z właściwością NotConfigurable w atrybucie DscProperty .
  • Musi to być tablica obiektów, które mają właściwość String o nazwie Code, właściwość String o nazwie Phrase i nie mają żadnych innych właściwości. Możesz zdefiniować typ obiektu jako tabelę skrótów lub utworzyć obiekt jako właściwość złożoną.

Konfiguracja komputera używa właściwości Przyczyny w celu ustandaryzowania sposobu prezentowania informacji o zgodności. Każdy obiekt zwrócony Get() przez metodę dla właściwości Reasons identyfikuje, jak i dlaczego wystąpienie zasobu DSC nie jest zgodne.

Konfiguracja maszyny oczekuje właściwości Code i Phrase . Właściwość Phrase powinna być ciągiem czytelnym dla człowieka, który wyjaśnia, w jaki sposób wystąpienie nie jest w pożądanym stanie. Właściwość Code musi być specjalnie sformatowana, aby konfiguracja komputera mogła wyraźnie wyświetlać informacje inspekcji zasobu DSC.

Właściwość Code używa tego formatowania bez żadnych spacji:

<ResourceName>:<ResourceName>:<Identifier>

W tym formatowaniu zastąp <ResourceName> ciąg rzeczywistą nazwą zasobu DSC i <Identifier> krótką nazwą określającą, dlaczego zasób DSC jest poza stanem. Właściwość Code nie może zawierać żadnych białych znaków. Jeśli na przykład zasób DSC o nazwie Tailspin był niezgodny, ponieważ plik konfiguracji nie istnieje, kod może mieć wartość Tailspin:Tailspin:ConfigFileNotFound.

Ten fragment kodu pokazuje, jak można zdefiniować właściwość Reasons jako tabelę skrótów:

class MyDscResource {
    [DscProperty(NotConfigurable)]
    [hashtable[]] $Reasons
}

Aby zdefiniować właściwość Reasons jako właściwość złożoną, należy zdefiniować dla niej klasę, a następnie dodać ją do zasobu DSC:

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

    [DscProperty()]
    [string] $Phrase
}

class MyDscResource {
    [DscProperty(NotConfigurable)]
    [MyModuleReason[]] $Reasons
}

Uwaga / Notatka

Klasa zdefiniowana dla właściwości Reasons ma nazwę MyModuleReason zamiast Reason, używając nazwy modułu jako prefiksu. Chociaż można nadać klasie dowolną nazwę, jeśli co najmniej dwa moduły definiują klasę o tej samej nazwie i są używane w konfiguracji, program PowerShell zgłasza wyjątek.

Aby uniknąć wyjątków spowodowanych konfliktami nazw w konfiguracji DSC i maszyny, zawsze poprzedzaj nazwę klasy zdefiniowanej dla właściwości Reasons .

Właściwości niezwiązane z zasobami

Podczas definiowania zasobu DSC opartego na klasach można dodać właściwości, które nie mają atrybutu DscProperty . Tych właściwości nie można używać bezpośrednio z Invoke-DscResource konfiguracją DSC ani w niej. Mogą być używane wewnętrznie przez klasę lub bezpośrednio przez użytkownika, który sam tworzy instancję klasy.

Aby uzyskać więcej informacji na temat właściwości klasy, zobacz about_Classes.

Metody zasobów DSC oparte na klasach

Zasoby DSC oparte na klasach muszą implementować trzy metody:

  • Get() , aby pobrać bieżący stan zasobu DSC
  • Test() , aby sprawdzić, czy zasób DSC jest w żądanym stanie
  • Set() , aby wymusić żądany stan zasobu DSC

Podpis metody jest definiowany przez oczekiwany typ danych wyjściowych i parametry. Klasa nie zostanie rozpoznana jako prawidłowy zasób DSC, jeśli nie zawiera poprawnych podpisów dla tych metod.

Metody klas programu PowerShell różnią się od funkcji na kilka ważnych sposobów. Na potrzeby pisania zasobu DSC opartego na klasach są to najważniejsze elementy:

  • W metodach klas żadne obiekty nie są wysyłane do potoku poza tymi wymienionymi w instrukcji return . Nie ma przypadkowych danych wyjściowych potoku z kodu. Jeśli metoda ma typ wyjściowy inny niż Void, należy określić instrukcję, aby return wyemitować obiekt tego typu.
  • Błędy niepowodujące zakończenia zapisane w strumieniu błędów z wnętrza metody klasy nie są przekazywane. Aby wyświetlić błąd zakończenia, należy użyć throw.
  • Aby uzyskać dostęp do wartości właściwości instancji klasy, należy użyć $this.<PropertyName>. Nie ustawiaj ani nie aktualizuj żadnych właściwości klasy, które mają atrybut DscProperty . Są one ustawiane, gdy użytkownik określi parametr Property za pomocą Invoke-DscResource lub podczas definiowania bloku zasobów DSC w konfiguracji DSC.

Aby uzyskać więcej informacji na temat metod klas, zobacz about_Classes.

Metody mogą wywoływać polecenia cmdlet i polecenia natywne, w tym zdefiniowane w tym samym module co zasób DSC oparty na klasach.

Pobierz

Ta Get() metoda służy do pobierania bieżącego stanu zasobu DSC i zwracania go jako obiektu. Musi zdefiniować swoje dane wyjściowe jako samą klasę i nie przyjmować żadnych parametrów.

Na przykład zasób DSC oparty na klasach o nazwie MyDscResource musi mieć następujący podpis:

[MyDscResource] Get() {
    # Implementation here
}

Aby metoda zwracała Get() poprawny obiekt, należy utworzyć instancję klasy. Następnie można wypełnić właściwości tego wystąpienia bieżącymi wartościami z systemu. Na koniec użyj return słowa kluczowego, aby wyświetlić bieżący stan.

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

    if (Test-Path -Path $this.Path) {
        $CurrentState.Ensure = [Ensure]::Present
        $CurrentState.Path   = $this.Path
    } else {
        $CurrentState.Ensure = [Ensure]::Absent
    }

    return $CurrentState
}

W przykładowej implementacji Get() metoda inicjuje $CurrentState zmienną z domyślnym konstruktorem MyDscResource klasy. Sprawdza, czy plik określony we właściwości Path istnieje. Jeśli tak, metoda ustawia właściwości Ensure i Path na $CurrentStatePresent i odpowiednią ścieżkę. Jeśli tak się nie stanie, metoda ustawia wartość Ensure na Absent. Na koniec metoda używa instrukcji do wysłania return bieżącego stanu jako danych wyjściowych.

Test

Metoda Test() służy do sprawdzania, czy zasób DSC jest w żądanym stanie i zwraca $true wartość, jeśli jest w żądanym stanie, czy $false nie. Musi definiować dane wyjściowe wartości logicznej i nie przyjmować żadnych parametrów.

Podpis Test() metody powinien zawsze pasować do tego:

[bool] Test() {
    # Implementation here
}

Zamiast ponownie implementować logikę z Get() metody, wywołaj Get() metodę i przypisz jej dane wyjściowe do zmiennej.

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

    $CurrentState = $this.Get()

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

    # Check remaining properties as needed.

    return $InDesiredState
}

W przykładowej implementacji Test() metoda inicjuje zmienną, $InDesiredStatetak jak $true przed ustawieniem $CurrentState danych wyjściowych Get() metody dla zasobu DSC opartego na klasie.

Następnie sprawdza wartości właściwości $CurrentState względem tych określonych w wystąpieniu zasobu DSC, ustawiając $InDesiredState wartość $false Jeśli jakiekolwiek właściwości nie są w żądanym stanie.

Na koniec wyprowadza, czy wystąpienie zasobu DSC jest w żądanym stanie za pomocą instrukcji return .

Ustawienie

Ta Set() metoda służy do wymuszania żądanego stanu zasobu DSC. Nie ma żadnych danych wyjściowych i nie przyjmuje żadnych parametrów.

Podpis Set() metody powinien zawsze pasować do tego:

[void] Set() {
    # Implementation here
}

Implementacja Set() metody nie może używać żadnych return instrukcji. Powinien być zapisany tak, aby idempotycznie wymuszać żądany stan.

Uwaga / Notatka

Może być konieczne pobranie bieżącego stanu za pomocą metody, Get() jeśli chcesz wymusić żądany stan w zależności od bieżącego stanu systemu.

Na przykład możesz mieć logikę tworzenia usługi, gdy nie istnieje, zamiast korygować nieprawidłową wartość właściwości.

Dlatego też ważne jest, aby podczas używania Invoke-DscResource wywoływać Test() metodę i wywoływać metodę tylko wtedy, Set() gdy Test() zwraca $false. Chociaż wszystkie zasoby DSC powinny być idempotentne, nie masz gwarancji, że jakikolwiek zasób DSC jest naprawdę idempotentny, bez przejrzenia jego implementacji.

Metody opcjonalne

Poza wymaganymi Get()metodami , Test()i Set() zasób DSC oparty na klasach może definiować dowolną liczbę dodatkowych metod. Jednym z przypadków użycia tego jest zdefiniowanie metod pomocniczych, takich jak kod używany w więcej niż jednej z wymaganych metod.

Jest to również przydatne podczas definiowania klasy, która reprezentuje komponent oprogramowania nie tylko dla konfiguracji. Można na przykład zdefiniować klasę, która jest zarówno zasobem DSC, umożliwiając idempotentną konfigurację aplikacji, jak i wywołując samą aplikację w celu wykonywania zadań. Umożliwiłoby to jednokrotne zdefiniowanie klasy i użycie jej zarówno z DSC, jak i funkcjami wyeksportowanymi z modułu w celu korzystania z aplikacji.

Konstruktory

Konstruktor to metoda, która tworzy nową instancję klasy. Nazwa metody jest zawsze taka sama jak nazwa klasy i nie definiuje typu danych wyjściowych.

Nie jest obowiązkowe definiowanie żadnych konstruktorów dla zasobu DSC opartego na klasach. Jeśli konstruktor nie zostanie zdefiniowany, zostanie użyty domyślny konstruktor bez parametrów. Ten konstruktor inicjuje wszystkie elementy członkowskie do ich wartości domyślnych. Typy obiektów i ciągi mają wartości null.

Podczas definiowania konstruktora nie jest tworzony żaden domyślny konstruktor bez parametrów. Zasób DSC oparty na klasach musi mieć konstruktor bez parametrów, więc jeśli zdefiniujesz jakiekolwiek konstruktory niestandardowe, co najmniej jeden z nich musi być zdefiniowany bez żadnych parametrów.

W przypadku używania Invoke-DscResource lub kompilowania konfiguracji DSC zasób DSC jest tworzony za pomocą konstruktora bez parametrów, a następnie każda określona właściwość jest ustawiana w wystąpieniu.

Uwaga / Notatka

Podczas definiowania konstruktora powinien on zgłaszać wyjątek tylko wtedy, gdy zasób DSC jest z jakiegoś powodu nieprawidłowy w systemie. Na przykład zasób DSC oparty na klasach, który działa tylko w systemie Windows, może zgłosić wyjątek, jeśli zostanie utworzony w systemie innym niż Windows.

Aby uzyskać więcej informacji na temat konstruktorów, zobacz about_Classes

Definiowanie konstruktora domyślnego

Zasoby DSC oparte na klasach wymagają, aby klasa nie implementowała żadnych konstruktorów lub jeden z tym podpisem:

<DscResourceClassName>() {
    # Implementation here
}

Jeśli nie ma wymaganej logiki do wykonania, takiej jak ustawianie wartości domyślnych na podstawie systemu operacyjnego, nie musisz pisać żadnego kodu w konstruktorze. W poniższym przykładzie przedstawiono minimalną definicję konstruktora domyślnego:

MyDscResource() {}

Możesz dodać kod do konstruktora, aby ustawić wartości domyślne dla właściwości klasy. Na przykład możesz chcieć ustawić wartość na podstawie docelowego systemu operacyjnego:

MyDscResource() {
    if ($IsWindows) {
        $this.Format = 'JSON'
    } else {
        $this.Format = 'YAML'
    }
}

Uwaga / Notatka

Pamiętaj, że walidacja właściwości w DSC odbywa się po użyciu konstruktora, a nie w trakcie. Nie próbuj weryfikować żadnych właściwości w konstruktorze.

Definiowanie konstruktora niestandardowego

DSC wywołuje tylko konstruktor bez parametrów. Można jednak zdefiniować inne konstruktory z parametrami, jeśli klasa jest używana w innych okolicznościach, na przykład przez funkcje w module.

Aby uzyskać więcej informacji na temat definiowania konstruktorów, zobacz about_Classes

Najlepsze rozwiązania

Jest to niewyczerpująca lista najlepszych rozwiązań dotyczących tworzenia wysokiej jakości zasobów DSC opartych na klasach, które są idempotentne, bezpieczne i łatwe w utrzymaniu. Uzupełnia ona listę kontrolną tworzenia zasobów DSC, która definiuje bardziej ogólne wskazówki dotyczące tworzenia zasobów DSC. Praktyki opisane w tej sekcji są specyficzne dla zasobów DSC opartych na klasach.

Używanie atrybutów walidacji

Jeśli można sprawdzić poprawność właściwości za pomocą co najmniej jednego z atrybutów walidacji, należy to zrobić. Ta walidacja jest sprawdzana przed wywołaniem dowolnej metody za pomocą Invoke-DscResource i podczas kompilowania konfiguracji DSC. Wcześniejsze zgłoszenie błędu zmniejsza prawdopodobieństwo, że zasób DSC zakończy się niepowodzeniem w nieprzewidywalny sposób podczas wymuszania stanu.

Błędy zgłaszane przez wbudowane atrybuty walidacji są również jasne co do tego, która właściwość miała nieprawidłową wartość i w jaki sposób wartość była nieprawidłowa.

Uwaga / Notatka

Atrybutów sprawdzania poprawności należy używać tylko w celu upewnienia się, że dane wejściowe użytkownika dla właściwości są prawidłowe, a nie w celu sprawdzenia, czy właściwość jest w prawidłowym stanie. Do tego właśnie służy ta Test() metoda.

Na przykład nie sprawdzaj, czy wartość ścieżki już istnieje, chyba że jest to wymagane, aby pozostała część logiki zasobu DSC działała. Jeśli zasób DSC tworzy plik w tej lokalizacji, nie weryfikuj jego istnienia w deklaracji właściwości.

Jeśli używasz jakichkolwiek złożonych właściwości, pamiętaj, aby zastosować atrybuty walidacji również do tych właściwości podrzędnych. Te właściwości podrzędne są weryfikowane w tym samym czasie co ich właściwość nadrzędna.

Używanie wyliczeń zamiast ValidateSet

Jeśli właściwość zasobu DSC opartego na klasie ma listę prawidłowych wartości, które akceptuje, zdefiniuj ją jako właściwość wyliczeniową zamiast używać atrybutu ValidateSet .

Daje to użytkownikom lepszy komunikat o błędach i ułatwia konserwację, jeśli używasz tych wartości w dowolnym innym miejscu w module. Zamiast aktualizować każde polecenie cmdlet lub sprawdzać tę właściwość, możesz zaktualizować definicję wyliczenia.

Należy pamiętać, że wyliczenia są właściwościami typu wartości. Są one domyślnie ustawione na 0 moment utworzenia wystąpienia zasobu DSC opartego na klasach. Jeśli ustawisz jawną wartość domyślną dla właściwości wyliczenia, nie można cofnąć zarządzania tym wyliczeniem. Jeśli użytkownik nie określi właściwości, zasób DSC zachowuje się tak samo, jak gdyby użytkownik jawnie określił wartość domyślną.

Aby obsługiwać właściwości niezarządzanego wyliczenia, upewnij się, że nie zdefiniowano etykiety dla 0 wartości. Domyślnie, jeśli nie określisz wartości całkowitej dla żadnych etykiet podczas korzystania z instrukcji enum , pierwsza zadeklarowana etykieta ma wartość 0. Zamiast tego zdefiniuj pierwszą etykietę z wartością 1 (lub dowolną wyższą wartością).

Przykład:

enum OptionalSetting {
    FirstOption = 1
    SecondOption
    ThirdOption
}

Następnie w Test() metodach i Set() można zignorować właściwość enum, jeśli wartość to 0. W Test(), jeśli właściwość enum ma wartość 0, zignoruj bieżący stan zasobu DSC w systemie. Nie zgłaszaj zasobu DSC jako niepożądanego stanu, jeśli bieżący stan jest prawidłową wartością. W Set()programie upewnij się, że logika modyfikowania stanu systemu ignoruje właściwość enum, jeśli jest 0to .

Uwaga / Notatka

Ta metoda implementowania właściwości wyliczenia, które mogą być niezarządzane, działa tylko wtedy, gdy podstawowa wartość etykiet wyliczenia nie ma znaczenia lub gdy 0 nie jest prawidłową wartością podstawową.

Jawne definiowanie wartości domyślnych dla właściwości typu wartości

Podczas tworzenia zasobu DSC opartego na klasach upewnij się, że właściwości określają poprawne wartości domyślne dla każdej właściwości typu wartości. Musisz upewnić się, że wartości domyślne pozostają zsynchronizowane z wartościami składnika, którym zarządza zasób DSC.

Udokumentuj zachowanie tych właściwości dla użytkowników. Upewnij się, że dokumentacja wyjaśnia, że te właściwości są ustawione na wartości domyślne, jeśli użytkownik nie określi ich podczas korzystania z zasobu DSC.

Upewnij się, że zasób DSC respektuje właściwości niezarządzanego typu odwołania

Ponieważ właściwości typu referencyjnego są inicjowane do , w przeciwieństwie do $nullwłaściwości typu wartości, zasób DSC może rozróżniać, czy właściwość typu referencyjnego została określona, czy nie. Upewnij się, że zasoby DSC ignorują właściwości niezarządzanego typu odwołania w metodach Test() and Set() .

W Test(), jeśli właściwość typu odwołania ma wartość $null, zignoruj bieżący stan zasobu DSC w systemie. Nie zgłaszaj zasobu DSC jako niepożądanego stanu, jeśli bieżący stan to nie $null.

W Set()programie upewnij się, że logika modyfikowania stanu systemu ignoruje wszystkie właściwości typu odwołania, które są $null.

Używanie niestandardowego atrybutu walidacji zamiast ValidateScript

W przypadku właściwości, które wymagają bardziej złożonej walidacji, rozważ zdefiniowanie własnego atrybutu, który dziedziczy z klasy ValidateArgumentsAttribute lub jednej z jej pochodnych.

Daje to znacznie większą kontrolę nad walidacją właściwości i komunikatami, gdy określona wartość zakończy się niepowodzeniem.

Na przykład ta definicja atrybutu ValidateHttpsUrl gwarantuje, że określona wartość jest prawidłowym adresem URL protokołu HTTPS.

using namespace System.Management.Automation

class ValidateHttps : ValidateArgumentsAttribute {
    [void]  Validate([object]$Url, [EngineIntrinsics]$engineIntrinsics) {
        [uri]$Uri = $Url

        if($Uri.Scheme -ne 'https') {
            $Message = @(
                "Specified value '$Url' is not a valid HTTPS URL."
                "Specify an absolute URL that begins with 'https://'."
            ) -join ' '

            throw [System.ArgumentException]::new($Message)
        }
    }
}

Po zastosowaniu do właściwości zasób DSC zgłasza przydatny komunikat o błędzie:

$Parameters = @{
    Name       = 'MyDscResource'
    ModuleName = 'MyDscResources'
    Method     = 'Get'
    Property   = @{
      Url = 'http://contoso.com/updater'
    }
}

Invoke-DscResource @Parameters -ErrorAction Stop
Invoke-DscClassBasedResource: Exception setting "Url": "Specified value
'http://contoso.com/updater'  is not a valid HTTPS URL. Specify an absolute
URL that begins with 'https://'."

Uwaga / Notatka

Ze względu na ograniczenia w DSC nie można zdefiniować i użyć niestandardowego atrybutu walidacji w tym samym module co zasób DSC oparty na klasach. Zamiast tego należy zdefiniować niestandardowy atrybut walidacji w osobnym .psm1 pliku, dodać go do manifestu modułu głównego w ustawieniu NestedModules i określić instrukcję using w pliku, w którym zdefiniowano zasób DSC oparty na klasie.

Jeśli na przykład zdefiniowano atrybut ValidateHttps w Validators.psm1programie , musisz mieć go w manifeście modułu:

{
    NestedModules = @(
        'Validators.psm1'
    )
}

W górnej części pliku modułu, w którym zdefiniujesz zasób DSC oparty na klasach:

using module ./Validators.psm1

W tym przykładzie Validators.psm1 znajduje się w tym samym folderze co moduł, w którym zdefiniowano zasób DSC oparty na klasach. Jeśli pliki znajdują się w różnych folderach, należy określić ścieżkę względną do modułu, który definiuje atrybut walidacji.

Używanie złożonych właściwości zamiast tabel skrótów

Jeśli zasób DSC ma właściwość ze znanymi właściwościami podrzędnymi, utwórz dla niej klasę i zdefiniuj te właściwości podrzędne w tej klasie. Zapewnia to bardziej wykrywalną powierzchnię dla ustawień i umożliwia zastosowanie walidacji do właściwości podrzędnych. Aby uzyskać więcej informacji, zobacz właściwości złożone.

Dodawanie metody walidacji, jeśli właściwości są współzależne

Być może masz zasób DSC, który ma właściwości, które muszą zostać połączone w celu zweryfikowania. Tych właściwości nie można zweryfikować za pomocą atrybutu walidacji. Dodaj metodę walidacji do zasobu DSC opartego na klasach i wywołaj ją na początku Get()Test(), i Set() metod.

Jeśli na przykład zasób DSC do zarządzania plikiem konfiguracji ma właściwości Path (Ścieżka ) i Extension (Rozszerzenie ), może być konieczne zweryfikowanie:

  • Rozszerzenie pliku określone jako ścieżka jest zgodne z wartością rozszerzenia lub rozszerzenia nie jest określone
  • To rozszerzenie jest określone, jeśli wartość Path jest folderem, a nie plikiem

Metoda walidacji powinna mieć jednoznaczną nazwę, nie zwracać żadnych danych wyjściowych i zgłaszać, jeśli walidacja wystąpienia zakończy się niepowodzeniem.

[void] ValidatePath() {
    $ExtensionSpecified = ![string]::IsNullOrEmpty($this.Extension)
    $PathExtension = Split-Path -Path $this.Path -Extension

    if (
        $PathExtension -and
        $ExtensionSpecified -and
        ($PathExtension -ne $this.Extension)
    ) {
        $Message = @(
            "Specified Path '$($this.Path)' has an extension ('$PathExtension')"
            "which doesn't match the value of the Extension property"
            "'$($this.Extension)'. When specifying the Extension property with"
            "the Path property as a specific file, the extension of Path's"
            "value must be the same as the value of Extension or Extension must"
            "not be specified."
        ) -join ' '

        throw [System.ArgumentException]::new($Message)
    } elseif (!$ExtensionSpecified) {
        $Message = @(
            "Specified Path '$($this.Path)' has no extension and the Extension"
            "property wasn't specified. When the value of Path is a folder, the"
            "Extension property is mandatory. Specify a value for Extension."
        ) -join ' '

        throw [System.ArgumentException]::new($Message)
    }
}

Jeśli musisz zweryfikować kilka różnych parametrów lub grup parametrów w ten sposób, zdefiniuj ogólną metodę walidacji, która wywołuje inne. Użyj tej metody w Get(), Test()i .Set()

Wyodrębnianie kodu udostępnionego do metod lub funkcji

Jeśli metody są długie ze złożoną logiką lub ponownie używają tego samego kodu między nimi, utwórz metodę lub funkcję pomocniczą i zamiast tego przenieś tam kod. Ułatwia to testowanie i konserwację zasobu DSC. Sprawia to również, że metody zasobu DSC są łatwiejsze do odczytania i zrozumienia.