Hungry for more Windows PowerShell Desired State Configuration Resources?

Hungry for more Windows PowerShell Desired State Configuration Resources?

Rate This
  • Comments 3

Now that you understand the value and need of Windows PowerShell Desired State Configuration (DSC), and how to declaratively express the intent of machine configuration via the new configuration keyword, you might be wondering how the configuration happens.

Configuration on a machine works because of DSC resources. Windows Server 2012 R2 and Windows Management Framework (WMF) 4.0 come with 12 built-in resources, but that’s not all. Like command extensibility of PowerShell, DSC resources are also extensible–you can create new DSC resources to fill the gap. This blog will walk you through the mechanics of DSC resources, and how to create new custom DSC resources.

The Desired State Configuration (DSC) resource is a PowerShell module that is used to model one or more entities that you want to be in a specific, desired state. In the below example, the DSC resource WindowsFeature is modeled to install or uninstall server roles such as Hyper-V, BranchCache, etc. on the target machine.

image  

Resource naming convention

All the contents of a DSC resource are packaged in to a single directory, so you can deploy DSC resources by using x-copy. By convention, the directory in which the DSC resource is packaged should have the same name as that of the DSC resource. This package contains the following files:

Resource definition file

The resource definition file defines the entity that you want to model. In this definition file, you model the properties of the entity that you want to expose with a CIM class definition. The CIM class should inherit from a base CIM class called OMI_BaseResource. The definition file has the same name as the CIM class, with a .schema.mof extension.

In the below example, a DSC resource named MSFT_RoleResource has a CIM class named MSFT_RoleResource that inherits from OMI_BaseResource CimClass.

class MSFT_RoleResource : OMI_BaseResource

{

};

Friendly name

You can give a DSC resource a more user-friendly name for simplicity and readability by adding the FriendlyName attribute to the CIM class; this name represents the contract of the DSC resource. In the below example, MSFT_RoleResource has the friendly name WindowsFeature.

[ClassVersion("1.0.0"), FriendlyName("WindowsFeature")]

class MSFT_RoleResource : OMI_BaseResource

{

};

 

If a friendly name is specified for a DSC resource, then the same friendly name must be used in the configuration document to reference the DSC resource. Using the resource name to reference it in the configuration document is not supported. However if the friendly name is not specified in the resource definition file, then the resource name can be used in the configuration document.

For more information about how resources are used to author the configuration document, refer to the following previous blog.

Qualifiers

Each property in a CIM class can have one or more of the following qualifiers: Key, Required, Read, and Write. The definition of each qualifier is as follows:

  • The Key property is used to uniquely identify the entity that is modeled by the resource. It is a mandatory property, and it must be defined with only one value; it cannot be an array or a collection.
  • The Required property is not a Key property, but is essential for successful execution of the Get, Set, and Test functionalities of the DSC resource. It is mandatory.
  • The Write properties are used to pass information and values from the configuration to the Get, Set, and Test functionality of the resource, which is essential for its execution.
  • The Read properties cannot be specified  in the configuration;  instead, they are returned as results from the execution of Get functionality.

The following Resource implementation section provides more details about Get, Set, Test functionality.

The following is a sample resource definition file for the resource named MSFT_RoleResource in MSFT_RoleResource.schema.mof file: 

[ClassVersion("1.0.0"), FriendlyName("WindowsFeature")]

class MSFT_RoleResource : OMI_BaseResource

{

      [Key] string Name;

      [Write] string Ensure;

      [Read] string DisplayName;

      [Write,EmbeddedInstance("MSFT_Credential")] string Credential;

}; 

The properties of a resource definition can be a complex object such as MSFT_Credential, as shown in the example above. MSFT_Credential is one of the DSC infrastructure CIM classes; it is used for channeling credentials into DSC resources.

Resource implementation file

The resource Implementation File (.psm1) is a typical Windows PowerShell Module file that implements three methods: Get-TargetResource, Test-TargetResource, and Set-TargetResource. The file has the same name as that of its resource, with a .psm1 extension.

In the example below, the DSC resource MSFT_RoleResource is packaged into a directory called MSFT_RoleResource. The resource definition file is named MSFT_RoleResource.schema.mof, and the resource implementation file is named MSFT_RoleResource.psm1.

 

image 

 

Localized content can be imported in to the resource implementation file (.psm1) by using the conventional PowerShell script internationalization approach. Refer to the following MSDN article for script internationalization.

Every DSC resource must expose the following three commands:

  • Get-TargetResource: Get-TargetResource is used to get the status of the entity modeled by the resource.
  • Test-TargetResource: Test-TargetResource is used to determine whether the entity modeled by resource is in a desired state or not.
  • Set-TargetResource: Set-TargetResource is used to verify that the entity modeled by resource is in a desired state. If the entity modeled by the resource is not in the desired state, then the functionality of Set-TargetResource is responsible for putting the entity in the desired state.

Rules for authoring Get-TargetResource, Set-TargetResource and Test-TargetResource commands 

  • The Get-TargetResource function implements all Key properties defined in the resource schema file. If a DSC resource requires the Required and/or Write properties to successfully fetch the state of the modeled entity, then Required or Write properties can also be in the Get-TargetResource input parameter list, and the values for these properties are propagated to Get-TargetResource during the command execution.
  • Test-TargetResource and Set-TargetResource functions implement all the Key, Required and Write properties defined in the resource schema file.
  • The parameters exposed by Get, Set, and Test must all exist in the schema file, and should not contain any parameter that is not defined in the schema file.
  • All Key and Required parameters must be authored as mandatory parameters in the corresponding Get, Set, and Test functions.

Get-TargetResource

A sample Get-TargetResource implemented in a resource implementation file (.psm1) is as follows:

 

function Get-TargetResource

{

     param

     (     

        [parameter(Mandatory = $true)]

        [ValidateNotNullOrEmpty()]

        [string]

        $Name,

 

        [Parameter(Mandatory=$false)]

        [System.Management.Automation.PSCredential]

        $Credential

     )

 

 

 

        # Add implementation logic to fetch the status of

        # the entity modeled by the resource

 

        # Add all feature properties to the hash table

        $getTargetResourceResult = @{

                                      Name = $feature.Name;

                                      DisplayName = $feature.DisplayName;

                                      Ensure = $ensureResult;

                                    }

 

 

        $getTargetResourceResult;

 

}

The Get-TargetResource returns the status of the modeled entities in a hash table format. This hash table must contain all properties, including the Read properties (along with their values) that are defined in the resource schema. In the example above, the hash table returned by Get-TargetResource contains Name, DisplayName and Ensure properties, along with their values. These properties also exist in the MSFT_RoleResource CimClass definition that was authored in the resource definition file shown above.

Set-TargetResource

A sample Set-TargetResource implemented in a resource implementation file (.psm1) is as follows:

 

function Set-TargetResource

{   

    [CmdletBinding(SupportsShouldProcess=$true)]

    param

    (      

        [parameter(Mandatory=$true)]

        [ValidateNotNullOrEmpty()]

        [string]

        $Name,

 

        [parameter()]

        [ValidateSet("Present", "Absent")]

        [string]

        $Ensure = "Present",

 

        [Parameter(Mandatory=$false)]

        [System.Management.Automation.PSCredential]

        $Credential

    )

 

        # Add implementation logic to make sure that

        # the entity modeled by resource is put a desired state.

 

        Write-Verbose "Executing Set-TargetResource functionality."

 

        for ($i = 1; $i -le 100; $i++ )

        {

            write-progress -activity "Set execution in Progress" -status "$i%    Complete:" -percentcomplete $i;

        }

}

 The Set-TargetResource method should not return any result to the calling code. 

WhatIf mode

As a best practice, Set-TargetResource should support -WhatIf behavior (WhatIf provides a summary of what action would be taken if Set-TargetResource was executed, without actually performing the command). To support -WhatIf behavior, the SupportShouldProcess attribute must be set to True in the cmdlet binding of the Set-TargetResource function, as shown below.

 

function Set-TargetResource

{   

    [CmdletBinding(SupportsShouldProcess=$true)]

    param

    ( 

    )

  }

In the following example, if Set-TargetResource is executed in WhatIf mode, the description of the operation performed is displayed without actually performing the operation. On the other hand, if Set-TargetResource is executed without adding the -WhatIf parameter, the actual operation is run, and the WhatIf description message is not displayed.

 

function Set-TargetResource

{   

    [CmdletBinding(SupportsShouldProcess=$true)]

    param

    (      

        [parameter(Mandatory=$true)]

        [ValidateNotNullOrEmpty()]

        [string]

        $Name,

 

        [parameter()]

        [ValidateSet("Present", "Absent")]

        [string]

        $Ensure = "Present",

 

        [Parameter(Mandatory=$false)]

        [System.Management.Automation.PSCredential]

        $Credential

    )

 

 

        if($PSCmdlet.ShouldProcess("Description about what operation would be performed if Set-TargetResource would be executed."))

        {

            # Add implementation logic to make sure that

            # the entity modeled by resource is put a desired state.

        }

}

 

For more details about SupportShould parameters, refer to the following documentation:

·         http://msdn.microsoft.com/en-us/magazine/cc163293.aspx

·         http://technet.microsoft.com/en-us/magazine/ff677563.aspx

 

Reboot Status

If the machine must be restarted for the logic in Set-TargetResource to take effect, the resource can notify the DSC engine to restart the target, by setting the global variable $global:DSCMachineStatus to 1 before exiting Set-TargetResource method. The example below shows how restart-required status can be set in the Set-TargetResource functionality.

 

function Set-TargetResource

{   

    [CmdletBinding(SupportsShouldProcess=$true)]

    param

    (      

        [parameter(Mandatory=$true)]

        [ValidateNotNullOrEmpty()]

        [string]

        $Name,

 

        [parameter()]

        [ValidateSet("Present", "Absent")]

        [string]

        $Ensure = "Present",

 

        [Parameter(Mandatory=$false)]

        [System.Management.Automation.PSCredential]

        $Credential

    )

 

        # Add implementation logic to make sure

        # that the entity modeled by resource is

        # put a desired state.

 

       

        # If the machine needs to be rebooted

        # for the Set logic to take effect,

        # set the $global:DSCMachineStatus to 1

 

        Write-Warning "A machine reboot would be required."

        $global:DSCMachineStatus = 1;

}

Test-TargetResource

Test-TargetResource should always return a Boolean value of either $true or $false as the result of the test operation. If the entity modeled by the resource is in a desired state, then Test-TargetResource should return $true; if not, it should return $false.

 

A sample Test-TargetResource implemented in a resource implementation file (.psm1) is as follows:

 

function Test-TargetResource

{

    param

    (      

        [parameter(Mandatory = $true)]

        [ValidateNotNullOrEmpty()]

        [string]

        $Name,

 

        [parameter()]

        [ValidateSet("Present", "Absent")]

        [string]

        $Ensure = "Present",

 

        [Parameter()]

        [System.Management.Automation.PSCredential]

        $Credential

    )

 

    # Add implementation logic to validate

    # if the entity modeled by resource is

    # in a desired state or not.

   

    # In this example Test-TargetResource is

    # reporting that the entity modeled by

    # resource is not in the desired state.

    return $false

}

 

Propagating messages from resource

The DSC resource can channel Verbose, Warning, Debug, Error, and Progress messages back to the client side, in appropriate PowerShell message streams. These messages are also collected in the “Microsoft-Windows-DSC/Analytic” channel on the target machine.

 

Deployment of DSC resource

All custom DSC resources should be x-copy deployed to $env:ProgramFiles\WindowsPowerShell\Modules\<Module Name>\DSCResources\<Resource Name>.

Resource consumption

A configuration document is authored to serve as a blueprint of the desired state of the machine. This configuration document contains one or more resources that are modeled to put their corresponding entities in a desired state. For more information about how resources are used to author the configuration document, refer to the previous blog

For more information about DSC, refer to the following TechNet documentation.

I hope I have helped you understand how to create your custom DSC Resource easily, simply by creating a resource definition file, implementing the functionality through Get/Set/Test-TargetResource, and then packaging your resource as a PowerShell module.

 

Sharath Gopalappa

Software Design Engineer

Microsoft

 

Updated on 11/17/2013: Fixed the formatting to be uniform through out.

Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post
  • Hi,

    Shouldn't there be an enumeration for assigning the correct value to $global:DSCMachineStatus instead of using a magic literal?

    Regards,

    Jason

  • How secure is something like this ? If I attack the machine and deploy a DSC as described, isn't there a huge risc-factor involved ? Okay, if I succefully attack you could argue that the machine is compromised anyway, but this kind of stuff will make it extremely easy for an attacker to put the machine into "his desired state" !

  • @Bart, it's important to remember that DSC uses PS Remoting behind the scenes. Therefore your argument really boils down to what an attacker can do to the machine via PS Remoting. It's no less secure than performing other PS remoting tasks.

Page 1 of 1 (3 items)