Octopus learning how to write a custom PowerShell DSC Module

Write your own PowerShell Desired State Configuration (DSC) module

Shawn Sesna

Octopus learning how to write a custom PowerShell DSC Module

PowerShell DSC is a fantastic technology to have in your tool-belt for managing Windows-based servers. This post is part of a series:

We also have articles on using PowerShell DSC with Octopus Deploy:


As you gain experience with PowerShell Desired State Configuration (DSC) you might encounter situations where the available modules don’t quite fit what you want to do. You could write your own Script Resources, but they don’t scale well, passing parameters is difficult, and they don’t provide a method for encryption, leaving passwords in clear text, however, you can write your own DSC modules.

In this PowerShell DSC tutorial, I'll cover how to write your first PowerShell DSC module.

A tool to help you write your PowerShell DSC module

Writing your own PowerShell DSC module isn’t really that hard. The most difficult part is getting the files and folders in the correct locations because DSC is quite specific about what goes where. However, Microsoft recognizes this can be quite frustrating and has developed xDscResourceDesigner, a PowerShell module to help you get started. Using this module, you can easily define what properties your resource needs and it will generate the entire module structure for you, including the MOF schema file. If you’re a first-timer, I highly recommend using this module, it could save you quite a bit of frustration (take it from me).

Installing xDscResourceDesigner

Installing the module is no different from installing any other module onto your system:

Install-Module -Name xDscResourceDesigner

As this Microsoft article points out, if you have a version of PowerShell prior to version 5, you may need to install the PowerShellGet module for installation to work.

Using xDscResourceDesigner

Using the xDscResourceDesigner is actually pretty easy, there are only two functions: New-DscResourceProperty and New-xDscResource. New-DscResourceProperty is what you use to define the properties of your DSC resource. After you’ve done that, you send that information to the New-xDscResource function, and it generates everything you need to implement your resource:

# Import the module for use
Import-Module -Name xDscResourceDesigner

# Define properties
$property1 = New-xDscResourceProperty -Name Property1 -Type String -Attribute Key
$property2 = New-xDscResourceProperty -Name Property2 -Type PSCredential -Attribute Write
$property3 = New-xDscResourceProperty -Name Property3 -Type String -Attribute Required -ValidateSet "Present", "Absent"

# Create my DSC Resource
New-xDscResource -Name DemoResource1 -Property $property1, $property2, $property3 -Path 'c:\Program Files\WindowsPowerShell\Modules' -ModuleName DemoModule

And there you have it, your very own DSC module with all the stubs generated.

Understanding the resource Attribute property

For the Attribute component of a Resource Property within DSC, there are four possible values:

  • Key
  • Read
  • Required
  • Write

Key

Every node that uses your resource must have a key that makes the node unique. Similar to database tables, this key doesn’t need to be a single property, but it can be made up of several properties, each bearing the Key attribute. In the example above, Property1 is our Key for the resource. However, it could also be done this way:

# Define properties
$property1 = New-xDscResourceProperty -Name Property1 -Type String -Attribute Key
$property2 = New-xDscResourceProperty -Name Property2 -Type PSCredential -Attribute Write
$property3 = New-xDscResourceProperty -Name Property3 -Type String -Attribute Required -ValidateSet "Present", "Absent"
$property4 = New-xDscResourceProperty -Name Property4 -Type String -Attribute Key
$property5 = New-xDscResourceProperty -Name Property5 -Type String -Attribute Key

In this example, property1, property4, and property5 are what make up the unique value for the node. Key attributes are always writable and are required.

Read

Read attributes are read-only and cannot have values assigned to them.

Required

Required attributes are assignable properties that must be specified when declaring the configuration. Using our example from above when we created our resource, the Property3 property is set to be required.

Write

Write attributes are optional attributes that you specify a value to when defining the node. In the example, Property2 is defined as a Write attribute.

ValidateSet switch

The ValidateSet switch is something that can be used with Key or Write attributes that specify the allowable values for a given property. In our example, we’ve specified that Property3 can only be either Absent or Present. Any other value will result in an error.

DSC module file and folder structure

Whether you decided to do it yourself or use the tool, the folder and file structure will look like the following:

$env:ProgramFiles\WindowsPowerShell\Modules (folder)
    |- DemoModule (folder)
        |- DSCResources (folder)
            |- DemoResource1 (folder)
                |- DemoResource1.psd1 (file, optional)
                |- DemoResource1.psm1 (file, required)
                |- DemoResource1.schema.mof (file, required)

The MOF file

MOF stands for Managed Object Format and is the language used to describe Common Information Model (CIM) classes. Using the example from the Tool to help you write your module section, the resulting MOF file will look like this:

[ClassVersion("1.0.0.0"), FriendlyName("DemoResource1")]
class DemoResource1 : OMI_BaseResource
{
    [Key] String Property1;
    [Write, EmbeddedInstance("MSFT_Credential")] String Property2;
    [Required, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Property3;
};

The MOF file will only contain the properties we will in our module, along with their attributes and data types. Unless we’re adding or removing properties, this is pretty much all we do with the MOF file.

the psm1 file

The psm1 file is where the bulk of our code is going to be. This file will contain three required functions:

  • Get-TargetResource
  • Test-TargetResource
  • Set-TargetResource

Get-TargetResource

The Get-TargetResource function returns the current value(s) of what the resource is responsible for. Our stubbed function from using xDscResourceDesigner looks like the following:

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Property1,

        [parameter(Mandatory = $true)]
        [ValidateSet("Present","Absent")]
        [System.String]
        $Property3
    )

    #Write-Verbose "Use this cmdlet to deliver information about command processing."

    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."


    <#
    $returnValue = @{
    Property1 = [System.String]
    Property2 = [System.Management.Automation.PSCredential]
    Property3 = [System.String]
    }

    $returnValue
    #>
}

Note that the optional parameter (Write attribute) Property2 is not required for this function.

Test-TargetResource

The Test-TargetResource function returns a boolean value indicating whether or not the resource is in the desired state. From our generated example, the function looks like this:

function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Property1,

        [System.Management.Automation.PSCredential]
        $Property2,

        [parameter(Mandatory = $true)]
        [ValidateSet("Present","Absent")]
        [System.String]
        $Property3
    )

    #Write-Verbose "Use this cmdlet to deliver information about command processing."

    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."


    <#
    $result = [System.Boolean]

    $result
    #>
}

Set-TargetResource

The Set-TargetResource function is used to configure the resource to the specified desired state. Our generated example looks like this:

function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Property1,

        [System.Management.Automation.PSCredential]
        $Property2,

        [parameter(Mandatory = $true)]
        [ValidateSet("Present","Absent")]
        [System.String]
        $Property3
    )

    #Write-Verbose "Use this cmdlet to deliver information about command processing."

    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."

    #Include this line if the resource requires a system reboot.
    #$global:DSCMachineStatus = 1
}

Summary

Whether simplistic or complex, the steps for creating your own PowerShell DSC module will be the same. This post is aimed at getting you started in the right direction. From here, you can create your module to fit whatever resource you need to configure and keep in a desired state. For the full example of a working module check out xCertificatePermission on my GitHub repo.

Loading...