Introduction
In this part, we’ll go ahead and create our own DSC Resource. Why are we doing this? Well, when you start using DSC, you’ll find that you need to do something but cannot find a DSC Resource for it.
Other parts in this series:
- Learn PowerShell DSC Part 1
- Learn PowerShell DSC Part 2
- Learn PowerShell DSC Part 3
- Learn PowerShell DSC Part 4
- Learn PowerShell DSC Part 5
- Learn PowerShell DSC Part 6
Create a new DSC Resource
We’re going to create a simple resource which ensures a folder is present or absent. There’s already a DSC Resource for this but we’re more focussed on the process of creating a DSC resource. An overview of the steps is below:
- Install the DSC Resource Designer Module
- Create the DSC Resource properties
- Create the DSC Resource files
- Create the module manifest
- Add code to the DSC Resource
- Copy the module to the PowerShell module directory
- Test the DSC Resource
Let’s get to it – follow the steps below.
1) Install the DSC Resource Designer module
This module includes the cmdlets we’ll use to create a new DSC resource. These cmdlets include:
- Import-xDscSchema
- New-xDscResource
- New-xDscResourceProperty
- Test-xDscResource
- Test-xDscSchema
- Update-xDscResource
Install it by running the command below:
Install-Module xDscResourceDesigner -Force
2) Create the DSC Resource properties
These DSC Resource properties relate to what can be set when using the DSC Resource as part of a configuration. Our DSC Resource will be quite simple so in this case, we only need two properties:
- Path – this is the path to the folder we will ensure is absent or present
- Ensure – this is what we will do to the folder. It will only be able to be set to Present or Absent.
$Path=New-xDscResourceProperty -Name Path -Type string -Attribute Key
$Ensure=New-xDscResourceProperty -Name Ensure -Type string -Attribute Write -ValidateSet Present, Absent
3) Create the DSC Resource files
We’ll use the New-xDscResource cmdlet to create the file and folder structure for our new DSC Resource which we’ll call DemoFolder. We’ll call our new module DemoModule so we’ll be saving our new DSC Resource in a DemoModule folder:
New-xDscResource -Name DemoFolder -Property $Path, $Ensure -Path ‘C:scriptsDemoModule’
This creates a number of files and folder structure in C:Scripts. We’ll go through this later on.
4) Create the module manifest
As when creating a standard PowerShell module, we need to create a module manifest which includes information about the module. If you want more information on how to create a PowerShell module, see here.
Let’s create our module manifest. We’re going to set a few options here:
- Author: MG
- CompanyName: MG Enterprises
- Description: Demo Module
New-ModuleManifest `
-Path ‘C:ScriptsDemoModuleDemoModule.psd1’ `
-Guid ([GUID]::NewGuid()) `
-ModuleVersion 1.0 `
-Author MG `
-CompanyName ‘MG Enterprises’ `
-Description ‘Demo Module’
5) Add code to the DSC Resource
We should now have the below folder structure and files:
- DemoModule.psd1 – this is the module manifest we created in step 4
- DemoFolder.psm1 – this is the PowerShell module file which will hold our DSC Resource code
- DemoFolder.schema.mof – this is the MOF schema which contains information about the DSC Resource
When we look in the .psm1 file for a particular DSC Resource we’ve created, we’ll see that the DSC resource designer created three empty functions with some parameters which match the properties you created with New-xDscResourceProperty. These are:
- Test-TargetResource – This function checks if the target machine configuration matches the DSC configuration. The function needs to provide a Boolean output (true or false) and it should be fast and lightweight as it will potentially run regularly.
- Set-TargetResource – This is what performs the configuration change if the Test-TargetResource comes back false – i.e. in our case it either creates or deletes the specified folder.
- Get-TargetResource – This must return a hash table of the current configuration. It’s not used when setting or checking the configuration. It’s only used when we use Get-DscConfiguration i.e. when troubleshooting.
Our ’empty’ DemoFolder.psm1 file is below:
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Path
)
#Write-Verbose “Use this cmdlet to deliver information about command processing.”
#Write-Debug “Use this cmdlet to write debug information while troubleshooting.”
<#
$returnValue = @{
Path = [System.String]
Ensure = [System.String]
}
$returnValue
#>
}
function Set-TargetResource
{
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Path,
[ValidateSet(“Present”,“Absent”)]
[System.String]
$Ensure
)
#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
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Path,
[ValidateSet(“Present”,“Absent”)]
[System.String]
$Ensure
)
#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
#>
}
Export-ModuleMember -Function *-TargetResource
Let’s add some code to our DemoFolder.psm1 file. I’m not going to go through each line of code as this will really take some time and this post is all about creating the DSC resource.
Below you can see the completed file where I’ve written out the code.
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Path
)
Write-Verbose “Checking if folder is present”
if(Get-Item $Path -ErrorAction SilentlyContinue -ErrorVariable a)
{
$Ensure=“Present”
if($a.Exception){Write-Debug $a.Exception}
}
else
{
$Ensure=“Absent”
if($a.Exception){Write-Debug $a.Exception}
}
# Create a hashtaable which has path, present and ensure
$returnValue = @{
Path = [System.String]$Path
Ensure = [System.String]$Ensure
}
# Output the hashtable – this is used for troubleshooting
$returnValue
}
function Set-TargetResource
{
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Path,
[ValidateSet(“Present”,“Absent”)]
[System.String]
$Ensure
)
# If ensure is true, create the folder and if false then delete it and its contents
if($Ensure -eq ‘Present’)
{
Write-Verbose “Creating the folder”
New-Item -ItemType Directory -Path $Path -ErrorAction SilentlyContinue -ErrorVariable a | Out-Null
if($a.Exception){Write-Debug $a.Exception}
}
else
{
Write-Verbose “Removing the folder”
Remove-Item $Path -Recurse -Force -ErrorAction SilentlyContinue -ErrorVariable a
if($a.Exception){Write-Debug $a.Exception}
}
#Include this line if the resource requires a system reboot.
#$global:DSCMachineStatus = 1
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Path,
[ValidateSet(“Present”,“Absent”)]
[System.String]
$Ensure
)
# If ensure is true and the folder exists, return true. If folder doesn’t exist then return false.
# If ensure is false and folder exists then return false. If folder doens’t exist then return true.
if($Ensure -eq ‘Present’)
{
Write-Verbose “Checking if the folder exists”
if(Get-Item $Path -ErrorAction SilentlyContinue -ErrorVariable a)
{
$Result = $true
}
else
{
$Result = $false
}
if($a.Exception){Write-Debug $a.Exception}
}
else
{
Write-Verbose “Checking that the folder does not exist”
if(Get-Item $Path -ErrorAction SilentlyContinue -ErrorVariable a)
{
$Result = $false
}
else
{
$Result = $true
}
if($a.Exception){Write-Debug $a.Exception}
}
# Write the boolean output – if false then DSC knows to then run the Set-DSCTargetResource function
$result
}
Export-ModuleMember -Function *-TargetResource
6) Copy the module to the PowerShell module directory
We now need to copy our module directory over to the PowerShell module directory:
Copy-Item C:scriptsDemoModule “C:Program FilesWindowsPowerShellModulesDemoModule” -Recurse
We can now confirm that our new module and DSC Resource is visible to PowerShell:
Get-DscResource DemoFolder
7) Test the DSC Resource
So, we’re done creating our DSC Resource and are ready to create a DSC configuration to test it out.
Our simple test configuration is below – all it does is ensure that the C:TestFolder is present on localhost. If you need a refresher on how to write configurations, then see part 1.
configuration DemoCreateFolder {
param
(
[Parameter(Mandatory=$true)]
[string[]]$ComputerName
)
Import-DscResource -ModuleName DemoModule
Node $ComputerName
{
DemoFolder TestFolder
{
Ensure = “Present”
Path = “C:TestFolder”
}
}
}
We then create the DSC Configuration document (MOF file) as normal:
DemoCreateFolder -ComputerName localhost -OutputPath C:DSCConfigs
Once done, let’s go ahead and push our DSC configuration:
Start-DscConfiguration -Path C:DSCConfigs -Wait -Verbose
We can then confirm our target machine is in the desired state and that our test folder exists:
Test-DscConfiguration -Path C:DSCConfigs
Get-Item C:TestFolder
So, there we have it – we now know how to create DSC Resources. Next time we’ll go through composite resources and how we can save time.
Happy scripting!