Egyéni DSC-erőforrás írása PowerShell-osztályokkal

A következőre vonatkozik: Windows PowerShell 5.0

A PowerShell-osztályok Windows PowerShell 5.0-s verziójának bevezetésével mostantól definiálhat egy DSC-erőforrást egy osztály létrehozásával. Az osztály meghatározza az erőforrás sémáját és implementálását is, így nincs szükség külön MOF-fájl létrehozására. Az osztályalapú erőforrások mappastruktúrája is egyszerűbb, mert nincs szükség DSCResources mappára .

Egy osztályalapú DSC-erőforrásban a séma az osztály tulajdonságaiként van definiálva, amely attribútumokkal módosítható a tulajdonságtípus megadásához. Az erőforrást a , Set()és metódusok implementálják Get()(egyenértékűek a szkripterőforrásban lévő Get-TargetResource, Set-TargetResourceés Test-TargetResource függvényekkelTest()).

Ebben a cikkben létrehozunk egy NewFile nevű egyszerű erőforrást, amely egy megadott elérési úton kezeli a fájlokat.

További információ a DSC-erőforrásokról: Egyéni Windows PowerShell Desired State Configuration-erőforrások létrehozása

Megjegyzés

Az általános gyűjtemények nem támogatottak az osztályalapú erőforrásokban.

Osztályerőforrás mappastruktúrája

Ha egyéni DSC-erőforrást szeretne implementálni egy PowerShell-osztálysal, hozza létre a következő mappastruktúrát. Az osztály a-ban MyDscResource.psm1 van definiálva, a modul jegyzékfájlja pedig a következőben van definiálva: MyDscResource.psd1.

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

Az osztály létrehozása

Az osztály kulcsszóval hozhat létre Egy PowerShell-osztályt. Ha meg szeretné adni, hogy egy osztály egy DSC-erőforrás, használja az DscResource() attribútumot. Az osztály neve a DSC-erőforrás neve.

[DscResource()]
class NewFile {
}

Tulajdonságok deklarálása

A DSC-erőforrásséma az osztály tulajdonságaiként van definiálva. Három tulajdonságot deklarálunk az alábbiak szerint.

[DscProperty(Key)]
[string] $path

[DscProperty(Mandatory)]
[ensure] $ensure

[DscProperty()]
[string] $content

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

Figyelje meg, hogy a tulajdonságokat attribútumok módosítják. Az attribútumok jelentése a következő:

  • DscProperty(Key): A tulajdonság megadása kötelező. A tulajdonság egy kulcs. A kulcsként megjelölt összes tulajdonság értékeinek egyesítenie kell a konfigurációban lévő erőforráspéldány egyedi azonosításához.
  • DscProperty(Kötelező): A tulajdonság megadása kötelező.
  • DscProperty(NotConfigurable): A tulajdonság írásvédett. Az ezzel az attribútummal megjelölt tulajdonságokat nem lehet konfigurációval beállítani, de a Get() metódus tölti fel, amikor jelen van.
  • DscProperty(): A tulajdonság konfigurálható, de nem szükséges.

A $Path és $SourcePath a tulajdonság mindkét sztring. Az $CreationTime egy DateTime tulajdonság. A $Ensure tulajdonság egy enumerálási típus, amely a következőképpen van definiálva.

enum Ensure
{
    Absent
    Present
}

Osztályok beágyazása

Ha olyan új típust szeretne hozzáadni, amely definiált tulajdonságokkal rendelkezik, amelyeket az erőforráson belül használhat, hozzon létre egy tulajdonságtípusokkal rendelkező osztályt a fent leírtak szerint.

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

    [DscProperty()]
    [string] $Phrase
}

Megjegyzés

Az MyDscResourceReason osztály itt van deklarálva, a modul neve előtagként. Bár a beágyazott osztályoknak bármilyen nevet adhat, ha két vagy több modul azonos nevű osztályt definiál, és mindkettőt egy konfigurációban használják, a PowerShell kivételt okoz.

A DSC-ben a névütközések által okozott kivételek elkerülése érdekében a modulnévvel előtagként adja meg a beágyazott osztályok nevét. Ha a beágyazott osztály neve már nem valószínű, hogy ütközik, előtag nélkül is használhatja.

Ha a DSC-erőforrást az Azure Automanage gépkonfigurációs funkciójával való használatra tervezték, mindig előtagként adja meg az Okok tulajdonsághoz létrehozott beágyazott osztály nevét.

Nyilvános és privát függvények

PowerShell-függvényeket ugyanabban a modulfájlban hozhat létre, és használhatja őket a DSC-osztály erőforrásának metódusai között. A függvényeket nyilvánosként kell deklarálni, de a nyilvános függvények szkriptblokkja privát függvényeket is meghívhat. Az egyetlen különbség az, hogy szerepelnek-e a FunctionsToExport moduljegyzék tulajdonságában.

<#
   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 -ErrorAction SilentlyContinue

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

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

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

        $fileContent.phrase     = "The file was expected to contain: $content`nThe file contained: $existingFileContent"

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

    return @{
        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
}

A módszerek implementálása

A Get(), Set()és Test() metódusok hasonlóak a Get-TargetResourceszkripterőforrás , és Test-TargetResourceSet-TargetResourcefüggvényeihez.

Ajánlott eljárásként minimalizálja a kód mennyiségét az osztály implementációjában. Ehelyett helyezze át a kód nagy részét a modul nyilvános függvényeibe, amelyek ezután egymástól függetlenül tesztelhetők.

<#
    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
}

A teljes fájl

A teljes osztályfájl a következő.

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 -ErrorAction SilentlyContinue

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

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

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

        $fileContent.phrase     = "The file was expected to contain: $content`nThe file contained: $existingFileContent"

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

    return @{
        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
    }
}

Jegyzék létrehozása

Ha elérhetővé szeretne tenni egy osztályalapú erőforrást a DSC-motor számára, egy utasítást kell felvennie DscResourcesToExport a jegyzékfájlba, amely utasítja a modult az erőforrás exportálására. A jegyzék a következőképpen néz ki:

@{

    # 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

    }
}

Az erőforrás tesztelése

Miután mentette az osztály- és jegyzékfájlokat a mappastruktúrában a korábban leírtak szerint, létrehozhat egy konfigurációt, amely az új erőforrást használja. A DSC-konfigurációk futtatásával kapcsolatos információkért lásd: Konfigurációk telepítése. Az alábbi konfiguráció ellenőrzi, hogy a fájl /tmp/test.txt létezik-e, és hogy a tartalom megegyezik-e a "Content" tulajdonság által megadott sztringgel. Ha nem, a teljes fájl meg lesz írva.

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

PsDscRunAsCredential támogatása

[Megjegyzés] A PsDscRunAsCredential a PowerShell 5.0-s és újabb verzióiban támogatott.

A PsDscRunAsCredential tulajdonság használható a DSC-konfigurációk erőforrásblokkjában annak megadásához, hogy az erőforrást egy megadott hitelesítőadat-készlet alatt kell futtatni. További információ: DSC futtatása felhasználói hitelesítő adatokkal.

PsDscRunAsCredential megkövetelése vagy letiltása az erőforráshoz

Az DscResource() attribútum egy választható RunAsCredential paramétert vesz igénybe. Ez a paraméter a következő három érték egyikét veszi fel:

  • OptionalA PsDscRunAsCredential nem kötelező az erőforrást meghívó konfigurációkhoz. Ez az alapértelmezett érték.
  • MandatoryA PsDscRunAsCredentialt minden olyan konfigurációhoz használni kell, amely meghívja ezt az erőforrást.
  • NotSupported Az erőforrást meghívó konfigurációk nem használhatják a PsDscRunAsCredential parancsot.
  • Default Ugyanaz, mint a Optional.

Az alábbi attribútummal például megadhatja, hogy az egyéni erőforrás nem támogatja-e a PsDscRunAsCredential használatát:

[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}

Több osztályerőforrás deklarálása egy modulban

Egy modul több osztályalapú DSC-erőforrást is definiálhat. Csak deklarálnia kell az összes osztályt ugyanabban .psm1 a fájlban, és minden nevet bele kell foglalnia a .psd1 jegyzékbe.

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

A felhasználói környezet elérése

Ha egyéni erőforráson belülről szeretné elérni a felhasználói környezetet, használja az automatikus változót $global:PsDscContext.

A következő kód például azt a felhasználói környezetet írja meg, amely alatt az erőforrás a részletes kimeneti streamre fut:

if (PsDscContext.RunAsUser) {
    Write-Verbose "User: $global:PsDscContext.RunAsUser";
}

Lásd még:

Egyéni Windows PowerShell Desired State Configuration-erőforrások létrehozása