Blog Post

Creating a Custom PowerShell DSC Resource

PowerShell DSC

We’ve been using PowerShell Desired State Configuration (DSC) to automate the deployment of GigaCloud on Azure and on-premises Hyper-V virtual machines. Most of what we do with DSC comes from the open-source, Microsoft-supervised PowerShell DSC modules found on NuGet, and available to see at https://github.com/PowerShell. For some of our configuration tasks, though, we need custom functionality to get things installed and configured. For those, we’ve created DSC resources using PowerShell.

The Script resource

If you’re familiar with DSC, you’ll know about the Script resource. With the Script resource, you can specify any PowerShell code you want, either in-line, or by specifying a ScriptBlock variable, and run it just like you’d run any DSC resource, including scheduling it using the DependsOn property. It’s certainly convenient to do small things with the Script resource, but by using it we lose the ability to specify properties to pass into the resource. We also lose the familiar Test-then-Set rhythm of the other DSC resources. For these reasons, we chose not to use it.

The Resource Designer

The PowerShell team has provided a neat little tool to help us create custom resources: The Resource Designer Kit. The Kit is shipped as a module named xDSCResourceDesigner, and it consists of a set of cmdlets that help us create the PowerShell functions, and the .MOF file, for new, custom resources.

You can install it from NuGet:

<code block – monospaced font with source code coloring like StackOverflow>

Find-Module xDSCResourceDesigner | Install-Module

</code block>

Once installed, you’ll have access to six cmdlets.

<code block>

gcm -Module xDSCResourceDesigner | Select-Object Name


Name

----

Import-xDscSchema

New-xDscResource

New-xDscResourceProperty

Test-xDscResource

Test-xDscSchema

Update-xDscResource

</code block>

The ones I want to focus on right now are New-xDscResourceProperty, and New-xDscResource.

First, create the properties

Although it’s possible to create a resource with no custom properties (it would still support standard properties like PsDscRunAsCredential), it’s rare that you would want to. A block of code that doesn’t require any parameters is likely a good candidate for a Script resource, rather than a custom resource.

It may seem backwards at first to define the properties, and then the resource, but, as you’ll see, we give the properties as input to the New-xDscResource cmdlet so PowerShell can generate the starter code and .MOF files for our resource.

I’ll use the example of a resource that creates server clusters. To define our custom properties, we’ll use the New-xDscResourceProperty cmdlet and store them in variables:

<code block>

$NLBClusterName = New-xDscResourceProperty -Name NLBClusterName -Type String -Attribute Key -Description 'The name of the NLB cluster to create.'

$ClusterIPAddress = New-xDscResourceProperty -Name ClusterIPAddress -Type String -Attribute Required -Description 'The IP address of the cluster.'

$ClusterIPSubnetMask = New-xDscResourceProperty -Name ClusterIPSubnetMask -Type String -Attribute Required -Description 'The IP subnet mask of the cluster.'

</code block>

For each property, we specify the Name, the Type, the Attributes of the property, and an optional description that is written to the generated code. In our example, both parameters are of type String, but the Type can be any type, including structs and classes, that can be rendered using the .MOF type system. (Bottom line: if you stick to the basics – strings, numbers, structs/classes, and arrays/hashtables – you’ll be fine.)

When it runs, the output of the New-xDscResourceProperty cmdlet is a DscResourceProperty variable that we’ll pass in when we create our custom resource:

<code block>

New-xDscResource -Name cNLBCluster -Property $NLBClusterName, $ClusterIPAddress, $ClusterIPSubnetMask

</code block>

Running this creates two files: a .psm1 file for your PowerShell code; and the .schema.mof file that defines the interface for the resource and its properties.

Next, fill in the custom code

The .psm1 file will have the skeleton code for you resource, with Get-TargetResource, Set-TargetResource, and Test-TargetResource already defined.

This code will be highly custom to your application, but a few things to keep in mind when you write it:

  • The return type of Get-TargetResource is a hashtable, so if you don’t feel like implementing it at all, you can simply have @{} as your code block.
  • The return type of Test-TargetResource is a Boolean: $true if the resource is already in the desired state, and $false if the resource needs to run the Set function to put the machine into the desired state.
  • In all of your code, use Write-Verbose liberally. The verbose messages show up when you run Start-DscConfiguration with -Verbose.

Deploying the Custom Resource

Deploying the custom resource to the machines that will need it to perform DSC tasks is simple. Use your favorite way to copy the module that holds the custom resources, and its subdirectories, to C:\Program Files\WindowsPowerShell\DSCResources. I don’t care how you do it, even with XCOPY, it’s just a file copy to install it.

Using the Custom Resource

Using the new custom resource is just like using any other DSC Resource:

<code block>

        cNLBCluster CreateRMSCluster

        {

            NLBClusterName = $RMSClusterName

            ClusterIPAddress = $RmsClusterIPAddress

            ClusterIPSubnetMask = $RmsClusterIPSubnetMask

            DependsOn = @("[WindowsFeature]NLB")

        }

</code block>

Go create a custom resource!

Creating your own custom resources is one of the best ways to create reusable components to help you get machines into desired state. In many organizations, a library of only two or three dozen simple custom resources will be enough to stand up servers in almost any required configuration.

We’ve been enjoying our experience with custom resources, and with PowerShell DSC, to help us create an automated way to deploy GigaCloud. We’ll continue to share more about our journey with DSC in the coming weeks and months.