Sdílet prostřednictvím


Vytvoření prostředku DSC založeného na třídě

Prostředek DSC můžete definovat vytvořením třídy PowerShellu. V prostředku DSC založeném na třídě je schéma definováno jako vlastnosti třídy, které je možné upravit pomocí atributů pro určení typu vlastnosti. Prostředek se implementuje pomocí metod Get, Set a Test (rovná se Get-TargetResourcefunkcím , Set-TargetResourcea Test-TargetResource ve skriptu Resource).

V tomto článku vytvoříme minimální prostředek s názvem NewFile , který spravuje soubor v zadané cestě.

Další informace o prostředcích DSC najdete v tématu Prostředky DSC.

Poznámka

Obecné kolekce nejsou podporovány v prostředcích založených na třídách.

Struktura složek pro třídu Resource

Pokud chcete implementovat prostředek DSC s třídou PowerShellu, vytvořte následující strukturu složek. Třída je definována v MyDscResource.psm1 a manifest modulu je definován v MyDscResource.psd1.

$env:ProgramFiles\WindowsPowerShell\Modules (folder)
    |- MyDscResource (folder)
        MyDscResource.psm1
        MyDscResource.psd1

Vytvoření třídy

Klíčové slovo použijete class k vytvoření třídy PowerShellu. Pokud chcete určit, že třída je prostředek DSC, použijte DscResource() atribut . Název třídy je název prostředku DSC.

[DscResource()]
class NewFile {
}

Deklarace vlastností

Schéma prostředku DSC je definováno jako vlastnosti třídy . Deklarujeme tři vlastnosti následujícím způsobem.

[DscProperty(Key)]
[string] $path

[DscProperty(Mandatory)]
[ensure] $ensure

[DscProperty()]
[string] $content

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

Všimněte si, že vlastnosti jsou upravovány atributy. Význam atributů je následující:

  • DscProperty(Klíč): Vlastnost je povinná. Vlastnost je klíč. Hodnoty všech vlastností označených jako klíče se musí kombinovat, aby bylo možné jedinečně identifikovat instanci prostředku v rámci konfigurace.
  • DscProperty(povinné): Vlastnost je povinná.
  • DscProperty(NotConfigurable): Vlastnost je jen pro čtení. Vlastnosti označené tímto atributem není možné nastavit konfigurací, ale naplní se metodou Get .
  • DscProperty(): Vlastnost je konfigurovatelná, ale není povinná.

Vlastnosti Path a SourcePath jsou řetězce. CreationTime je vlastnost DateTime. Vlastnost Ensure je typ výčtu definovaný následujícím způsobem.

enum Ensure {
    Absent
    Present
}

Vkládání tříd

Pokud chcete zahrnout nový typ s definovanými vlastnostmi, které můžete použít v rámci prostředku DSC, vytvořte třídu s typy vlastností, jak je popsáno výše.

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

    [DscProperty()]
    [string] $Phrase
}

Poznámka

Třída MyDscResourceReason je zde deklarována s názvem modulu jako předponou. I když můžete vloženým třídám dát libovolný název, pokud dva nebo více modulů definují třídu se stejným názvem a oba se použijí v konfiguraci, Vyvolá PowerShell výjimku.

Abyste se vyhnuli výjimkám způsobeným konflikty názvů v DSC, před názvy vložených tříd zadejte název modulu. Pokud je již název vložené třídy nepravděpodobné, že by došlo ke konfliktu, můžete jej použít bez předpony.

Pokud je váš prostředek DSC navržený pro použití s funkcí konfigurace počítače služby Azure Automanage, pro vlastnost Důvody vždy zadejte předponu názvu vložené třídy, kterou vytvoříte.

Veřejné a soukromé funkce

Ve stejném souboru modulu můžete vytvářet funkce PowerShellu a používat je v metodách třídy prostředku DSC. Funkce se musí exportovat jako členy modulu v nastavení FunctionsToExport manifestu modulu. Bloky skriptu v rámci těchto funkcí mohou volat nevyexportované funkce.

<#
   Public Functions
#>

function Get-File {
    param(
        [ensure]$ensure,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$path,

        [String]$content
    )

    $fileContent        = [MyDscResourceReason]::new()
    $fileContent.code   = 'file:file:content'

    $filePresent        = [MyDscResourceReason]::new()
    $filePresent.code   = 'file:file:path'

    $ensureReturn = 'Absent'

    $fileExists = Test-Path -Path $path -ErrorAction SilentlyContinue

    if ($fileExists) {
        $filePresent.phrase     = @(
            "The file was expected to be: $ensure"
            "The file exists at path: $path"
        ) -join "`n"

        $existingFileContent    = Get-Content $path -Raw
        if ([string]::IsNullOrEmpty($existingFileContent)) {
            $existingFileContent = ''
        }

        if (![string]::IsNullOrEmpty($content)) {
            $content = $content | ConvertTo-SpecialChars
        }

        $fileContent.phrase = @(
            "The file was expected to contain: $content"
            "The file contained: $existingFileContent"
        ) -join "`n"

        if ($content -eq $existingFileContent) {
            $ensureReturn = 'Present'
        }
    } else {
        $filePresent.phrase = @(
            "The file was expected to be: $ensure"
            "The file does not exist at path: $path"
        ) -join "`n"
        $path = 'file not found'
    }

    @{
        Ensure  = $ensureReturn
        Path    = $path
        Content = $existingFileContent
        Reasons = @($filePresent,$fileContent)
    }
}

function Set-File {
    param(
        [ensure]$ensure = "Present",

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$path,

        [String]$content
    )

    Remove-Item $path -Force -ErrorAction SilentlyContinue

    if ($ensure -eq "Present") {
        New-Item $path -ItemType File -Force
        if ([ValidateNotNullOrEmpty()]$content) {
            $content | ConvertTo-SpecialChars | Set-Content $path -NoNewline -Force
        }
    }
}

function Test-File {
    param(
        [ensure]$ensure = "Present",

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$path,

        [String]$content
    )

    $test = $false
    $get = Get-File @PSBoundParameters

    if ($get.ensure -eq $ensure) {
        $test = $true
    }

    $test
}

<#
   Private Functions
#>

function ConvertTo-SpecialChars {
    param(
        [parameter(Mandatory = $true,ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$string
    )

    $specialChars = @{
        '`n'  = "`n"
        '\\n' = "`n"
        '`r'  = "`r"
        '\\r' = "`r"
        '`t'  = "`t"
        '\\t' = "`t"
    }

    foreach ($char in $specialChars.Keys) {
        $string = $string -replace ($char,$specialChars[$char])
    }

    $string
}

Implementace metod

Metody Get, Set a Test jsou podobné funkcím Get-TargetResource, Set-TargetResourcea Test-TargetResource ve skriptu Resource.

Osvědčeným postupem je omezit množství kódu v rámci implementace třídy. Přesuňte většinu kódu do exportovaných funkcí modulu, které můžete nezávisle testovat.

<#
    This method is equivalent of the Get-TargetResource script function.
    The implementation should use the keys to find appropriate
    Resources. This method returns an instance of this class with the
    updated key properties.
#>
[NewFile] Get() {
    $get = Get-File -ensure $this.ensure -path $this.path -content $this.content
    return $get
}

<#
    This method is equivalent of the Set-TargetResource script function.
    It sets the Resource to the desired state.
#>
[void] Set() {
    $set = Set-File -ensure $this.ensure -path $this.path -content $this.content
}

<#
    This method is equivalent of the Test-TargetResource script
    function. It should return True or False, showing whether the
    Resource is in a desired state.
#>
[bool] Test() {
    $test = Test-File -ensure $this.ensure -path $this.path -content $this.content
    return $test
}

Úplný soubor

Následuje kompletní soubor třídy.

enum ensure {
    Absent
    Present
}

<#
    This class is used within the DSC Resource to standardize how data
    is returned about the compliance details of the machine. Note that
    the class name is prefixed with the module name - this helps prevent
    errors raised when multiple modules with DSC Resources define the
    Reasons property for reporting when they're out-of-state.
#>
class MyDscResourceReason {
    [DscProperty()]
    [string] $Code

    [DscProperty()]
    [string] $Phrase
}

<#
   Public Functions
#>

function Get-File {
    param(
        [ensure]$ensure,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$path,

        [String]$content
    )

    $fileContent        = [MyDscResourceReason]::new()
    $fileContent.code   = 'file:file:content'

    $filePresent        = [MyDscResourceReason]::new()
    $filePresent.code   = 'file:file:path'

    $ensureReturn = 'Absent'

    $fileExists = Test-Path -Path $path -ErrorAction SilentlyContinue

    if ($fileExists) {
        $filePresent.phrase     = @(
            "The file was expected to be: $ensure"
            "The file exists at path: $path"
        ) -join "`n"

        $existingFileContent    = Get-Content $path -Raw

        if ([string]::IsNullOrEmpty($existingFileContent)) {
            $existingFileContent = ''
        }

        if (![string]::IsNullOrEmpty($content)) {
            $content = $content | ConvertTo-SpecialChars
        }

        $fileContent.phrase     = @(
            "The file was expected to contain: $content"
            "The file contained: $existingFileContent"
        ) -join "`n"

        if ($content -eq $existingFileContent) {
            $ensureReturn = 'Present'
        }
    } else {
        $filePresent.phrase     = @(
            "The file was expected to be: $ensure"
            "The file does not exist at path: $path"
        ) -join "`n"
        $path = 'file not found'
    }

    @{
        ensure  = $ensureReturn
        path    = $path
        content = $existingFileContent
        Reasons = @($filePresent,$fileContent)
    }
}

function Set-File {
    param(
        [ensure]$ensure = "Present",

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$path,

        [String]$content
    )

    Remove-Item $path -Force -ErrorAction SilentlyContinue

    if ($ensure -eq "Present") {
        New-Item $path -ItemType File -Force
        if ([ValidateNotNullOrEmpty()]$content) {
            $content | ConvertTo-SpecialChars | Set-Content $path -NoNewline -Force
        }
    }
}

function Test-File {
    param(
        [ensure]$ensure = "Present",

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$path,

        [String]$content
    )

    $test = $false
    $get = Get-File @PSBoundParameters

    if ($get.ensure -eq $ensure) {
        $test = $true
    }

    return $test
}

<#
   Private Functions
#>

function ConvertTo-SpecialChars {
    param(
        [parameter(Mandatory = $true,ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$string
    )
    $specialChars = @{
        '`n'  = "`n"
        '\\n' = "`n"
        '`r'  = "`r"
        '\\r' = "`r"
        '`t'  = "`t"
        '\\t' = "`t"
    }
    foreach ($char in $specialChars.Keys) {
        $string = $string -replace ($char,$specialChars[$char])
    }
    return $string
}

<#
    This Resource manages the file in a specific path.
    [DscResource()] indicates the class is a DSC Resource
#>

[DscResource()]
class NewFile {

    <#
        This property is the fully qualified path to the file that is
        expected to be present or absent.

        The [DscProperty(Key)] attribute indicates the property is a
        key and its value uniquely identifies a Resource instance.
        Defining this attribute also means the property is required
        and DSC will ensure a value is set before calling the Resource.

        A DSC Resource must define at least one key property.
    #>
    [DscProperty(Key)]
    [string] $path

    <#
        This property indicates if the settings should be present or absent
        on the system. For present, the Resource ensures the file pointed
        to by $Path exists. For absent, it ensures the file point to by
        $Path does not exist.

        The [DscProperty(Mandatory)] attribute indicates the property is
        required and DSC will guarantee it is set.

        If Mandatory is not specified or if it is defined as
        Mandatory=$false, the value is not guaranteed to be set when DSC
        calls the Resource.  This is appropriate for optional properties.
    #>
    [DscProperty(Mandatory)]
    [ensure] $ensure

    <#
        This property is optional. When provided, the content of the file
        will be overwridden by this value.
    #>
    [DscProperty()]
    [string] $content

    <#
        This property reports the reasons the machine is or is not compliant.

        [DscProperty(NotConfigurable)] attribute indicates the property is
        not configurable in DSC configuration.  Properties marked this way
        are populated by the Get() method to report additional details
        about the Resource when it is present.
    #>
    [DscProperty(NotConfigurable)]
    [MyDscResourceReason[]] $Reasons

    <#
        This method is equivalent of the Get-TargetResource script function.
        The implementation should use the keys to find appropriate
        Resources. This method returns an instance of this class with the
        updated key properties.
    #>
    [NewFile] Get() {
        $get = Get-File -ensure $this.ensure -path $this.path -content $this.content
        return $get
    }

    <#
        This method is equivalent of the Set-TargetResource script function.
        It sets the Resource to the desired state.
    #>
    [void] Set() {
        $set = Set-File -ensure $this.ensure -path $this.path -content $this.content
    }

    <#
        This method is equivalent of the Test-TargetResource script
        function. It should return True or False, showing whether the
        Resource is in a desired state.
    #>
    [bool] Test() {
        $test = Test-File -ensure $this.ensure -path $this.path -content $this.content
        return $test
    }
}

Vytvoření manifestu

Pokud chcete zpřístupnit prostředek DSC založený na třídě, musíte do souboru manifestu zahrnout DscResourcesToExport příkaz, který modulu dává pokyn k exportu prostředku DSC. Manifest vypadá takto:

@{

    # Script module or binary module file associated with this manifest.
    RootModule = 'NewFile.psm1'

    # Version number of this module.
    ModuleVersion = '1.0.0'

    # ID used to uniquely identify this module
    GUID = 'fad0d04e-65d9-4e87-aa17-39de1d008ee4'

    # Author of this module
    Author = 'Microsoft Corporation'

    # Company or vendor of this module
    CompanyName = 'Microsoft Corporation'

    # Copyright statement for this module
    Copyright = ''

    # Description of the functionality provided by this module
    Description = 'Create and set content of a file'

    # Minimum version of the Windows PowerShell engine required by this module
    PowerShellVersion = '5.0'

    # Functions to export from this module
    FunctionsToExport = @('Get-File','Set-File','Test-File')

    # DSC Resources to export from this module
    DscResourcesToExport = @('NewFile')

    # Private data to pass to the module specified in RootModule/ModuleToProcess.
    # This may also contain a PSData hashtable with additional module metadata used by PowerShell.
    PrivateData = @{

        PSData = @{

            # Tags applied to this module. These help with module discovery in online galleries.
            # Tags = @(Power Plan, Energy, Battery)

            # A URL to the license for this module.
            # LicenseUri = ''

            # A URL to the main website for this project.
            # ProjectUri = ''

            # A URL to an icon representing this module.
            # IconUri = ''

            # ReleaseNotes of this module
            # ReleaseNotes = ''

        } # End of PSData hashtable

    }
}

Testování prostředku

Po uložení souborů třídy a manifestu do výše popsané struktury složek můžete vytvořit konfiguraci DSC, která používá nový prostředek DSC. Následující Configuration příkaz zkontroluje, jestli soubor na adrese /tmp/test.txt existuje a jestli obsah odpovídá řetězci poskytnutému vlastností Content. Pokud ne, zapíše se celý soubor.

Configuration MyConfig {
    Import-DSCResource -ModuleName NewFile
    NewFile testFile {
        Path = "/tmp/test.txt"
        Content = "DSC Rocks!"
        Ensure = "Present"
    }
}

MyConfig

Deklarace více prostředků DSC založených na třídě v modulu

Modul může definovat více prostředků DSC založených na třídě. Musíte deklarovat všechny třídy ve stejném .psm1 souboru a zahrnout do manifestu .psd1 všechny názvy.

$env:ProgramFiles\PowerShell\Modules (folder)
    |- MyDscResource (folder)
        |- MyDscResource.psm1
            MyDscResource.psd1

Viz také