Schrijven van een single instance DSC-resource (aanbevolen)Writing a single-instance DSC resource (best practice)

Opmerking: in dit onderwerp beschrijft aanbevolen procedure voor het definiëren van een DSC-resource waarmee slechts één exemplaar in een configuratie.Note: This topic describes a best practice for defining a DSC resource that allows only a single instance in a configuration. Er is momenteel geen ingebouwde DSC-functie om dit te doen.Currently, there is no built-in DSC feature to do this. Dat kan worden gewijzigd in de toekomst.That might change in the future.

Zijn er situaties waarin u niet wilt toestaan dat een resource toe aan meerdere keren worden gebruikt in een configuratie.There are situations where you don't want to allow a resource to be used multiple times in a configuration. Bijvoorbeeld in een eerdere implementatie van de xTimeZone resource, een configuratie kan aanroepen de resource meerdere keren als u de tijdzone op een andere instelling in elk blok resource:For example, in a previous implementation of the xTimeZone resource, a configuration could call the resource multiple times, setting the time zone to a different setting in each resource block:

Configuration SetTimeZone 
{ 
    Param 
    ( 
        [String[]]$NodeName = $env:COMPUTERNAME 

    ) 

    Import-DSCResource -ModuleName xTimeZone 


    Node $NodeName 
    { 
         xTimeZone TimeZoneExample 
         { 

            TimeZone = 'Eastern Standard Time' 
         } 

         xTimeZone TimeZoneExample2
         {

            TimeZone = 'Pacific Standard Time'

         }        

    } 
} 

Dit is vanwege de manier waarop DSC-resource sleutels werkt.This is because of the way DSC resource keys work. Een bron moet ten minste één sleuteleigenschap hebben.A resource must have at least one key property. Een resource-instantie wordt beschouwd als uniek zijn als de combinatie van de waarden van alle van de sleuteleigenschappen uniek is.A resource instance is considered unique if the combination of the values of all of its key properties is unique. In de vorige implementatie de xTimeZone resource had u slechts één eigenschap--tijdzone, wat een sleutel is vereist.In its previous implementation, the xTimeZone resource had only one property--TimeZone, which was required to be a key. Als gevolg hiervan, zou een configuratie zoals hierboven compileren en uitvoeren zonder waarschuwing.Because of this, a configuration such as the one above would compile and run without warning. Elk van de xTimeZone resource blokken wordt beschouwd als uniek.Each of the xTimeZone resource blocks is considered unique. Hierdoor zou de configuratie van meerdere malen worden toegepast op het knooppunt, functioneert de tijdzone heen en weer.This would cause the configuration to be repeatedly applied to the node, cycling the timezone back and forth.

Om ervoor te zorgen dat een configuratie kan de tijdzone instellen voor een doelknooppunt slechts een keer de resource is bijgewerkt voor het toevoegen van een tweede eigenschap IsSingleInstance, die de sleuteleigenschap is geworden.To ensure that a configuration could set the time zone for a target node only once, the resource was updated to add a second property, IsSingleInstance, that became the key property. De IsSingleInstance is beperkt tot een enkele waarde 'Ja' met behulp van een ValueMap.The IsSingleInstance was limited to a single value, "Yes" by using a ValueMap. Het oude MOF-schema voor de resource is:The old MOF schema for the resource was:

[ClassVersion("1.0.0.0"), FriendlyName("xTimeZone")]
class xTimeZone : OMI_BaseResource
{
    [Key, Description("Specifies the TimeZone.")] String TimeZone;
};

Het bijgewerkte MOF-schema voor de resource is:The updated MOF schema for the resource is:

[ClassVersion("1.0.0.0"), FriendlyName("xTimeZone")]
class xTimeZone : OMI_BaseResource
{
    [Key, Description("Specifies the resource is a single instance, the value must be 'Yes'"), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance;
    [Required, Description("Specifies the TimeZone.")] String TimeZone;
};

De resource-script is ook bijgewerkt voor het gebruik van de nieuwe parameter.The resource script was also updated to use the new parameter. Dit is de oude resource-script:Here is the old resource script:

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('Yes')]
        [String]
        $IsSingleInstance,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TimeZone
    )

    #Get the current TimeZone
    $CurrentTimeZone = Get-TimeZone

    $returnValue = @{
        TimeZone = $CurrentTimeZone
        IsSingleInstance = 'Yes'
    }

    #Output the target resource
    $returnValue
}


function Set-TargetResource
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('Yes')]
        [String]
        $IsSingleInstance,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TimeZone
    )

    #Output the result of Get-TargetResource function.
    $CurrentTimeZone = Get-TimeZone

    if($PSCmdlet.ShouldProcess("'$TimeZone'","Replace the System Time Zone"))
    {
        try
        {
            if($CurrentTimeZone -ne $TimeZone)
            {
                Write-Verbose -Verbose "Setting the TimeZone"
                Set-TimeZone -TimeZone $TimeZone}
            else
            {
                Write-Verbose -Verbose "TimeZone already set to $TimeZone"
            }
        }
        catch
        {
            $ErrorMsg = $_.Exception.Message
            Write-Verbose -Verbose $ErrorMsg
        }
    }
}


function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([Boolean])]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('Yes')]
        [String]
        $IsSingleInstance, 

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TimeZone
    )

    #Output from Get-TargetResource
    $CurrentTimeZone = Get-TimeZone

    if($TimeZone -eq $CurrentTimeZone)
    {
        return $true
    }
    else
    {
        return $false
    }
}

Function Get-TimeZone {
    [CmdletBinding()]
    param()

    & tzutil.exe /g
}

Function Set-TimeZone {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [System.String]
        $TimeZone
    )

    try
    {
        & tzutil.exe /s $TimeZone
    }
    catch
    {
        $ErrorMsg = $_.Exception.Message
        Write-Verbose $ErrorMsg
    }
}

Export-ModuleMember -Function *-TargetResource

U ziet dat de tijdzone eigenschap is niet langer een sleutel.Notice that the TimeZone property is no longer a key. Nu als een configuratie probeert in te stellen de tijdzone tweemaal (met behulp van twee verschillende xTimeZone blokken met verschillende tijdzone waarden), een fout opgetreden bij het compileren van de configuratie wordt:Now, if a configuration attempts to set the time zone twice (by using two different xTimeZone blocks with different TimeZone values), attempting to compile the configuration will cause an error:

Test-ConflictingResources : A conflict was detected between resources '[xTimeZone]TimeZoneExample (::15::10::xTimeZone)' and 
'[xTimeZone]TimeZoneExample2 (::22::10::xTimeZone)' in node 'CONTOSO-CLIENT'. Resources have identical key properties but there are differences in the 
following non-key properties: 'TimeZone'. Values 'Eastern Standard Time' don't match values 'Pacific Standard Time'. Please update these property 
values so that they are identical in both cases.
At line:271 char:9
+         Test-ConflictingResources $keywordName $canonicalizedValue $k ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Write-Error], InvalidOperationException
    + FullyQualifiedErrorId : ConflictingDuplicateResource,Test-ConflictingResources
Errors occurred while processing configuration 'SetTimeZone'.
At C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psm1:3705 char:5
+     throw $ErrorRecord
+     ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (SetTimeZone:String) [], InvalidOperationException
    + FullyQualifiedErrorId : FailToProcessConfiguration