Conceptualize Desired State Configuration: Part 7

Summary: MVP, Will Anderson, wraps up his series by discussing how to add DSC resources to existing Windows PowerShell modules.

Ed Wilson here, bringing you MVP, Will Anderson, and the conclusion of his week of blogging about Desired State Configuration. 

  Note   This is a seven-part series that includes the following posts:

The code used in this series can be downloaded from the Script Center Repository:
Conceptualize Desired State Configuration – Reference Script

Adding additional resources to existing modules

Our DSC resource has been repopulated and it's ready for testing. But first, I'm going to add in an additional DSC resource for creating a new partition. We'll be adding this DSC resource into the DiskSize module that we created for the DiskResize resource.

$DiskNumber = New-xDscResourceProperty -Name DiskNumber -Type String -Attribute Key

$DriveLetter = New-xDscResourceProperty -Name DriveLetter -Type String -Attribute Required

$Ensure = New-xDscResourceProperty –Name Ensure -Type String -Attribute Write –ValidateSet “Present”, “Absent”

New-xDscResource -Name DiskPartition -Property $DiskNumber,$DriveLetter,$Ensure -Path 'C:\Program Files\WindowsPowerShell\Modules\' -ModuleName DiskSize

Like in our previous example, we'll be using the New-xDscResource and New-xDscResourceProperty cmdlets to generate the resource. We'll call the new resource DiskPartition, and direct it to the already existing DiskSize module. Here’s how to execute and then re-import the module:

PS C:\Windows\system32> Get-DscResource -Module DiskSize

ImplementedAs Name      ModuleName      Version Properties         

————- —-      ———-      ——- ———-         

PowerShell  DiskPartition    DiskSize      1.0.0.0 {DiskNumber, DriveLetter, DependsOn, Ensure…}

PowerShell  DiskResize    DiskSize      1.0.0.0 {DiskSize, DriveLetter, DependsOn, Ensure…}

You'll see that we now have the DiskPartition resource in the manifest! So now we can edit the .psm1 file with our code. Remember:

  • Get-TargetResource must return a hash table. This validates our inputs.
  • Test-TargetResource is the go/no-go switch. It must return a boolean True or False.
  • Set-TargetResource is the “make it so” button. This is where our execution will take place.

We've already done this, so I'm going to post only the code I inserted into the DiskPartition .psm1 file:

function Get-TargetResource

{

 [CmdletBinding()]

 [OutputType([System.Collections.Hashtable])]

 param

 (

  [parameter(Mandatory = $true)]

  [System.String]

  $DiskNumber,

  [parameter(Mandatory = $true)]

  [System.String]

  $DriveLetter

 )

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

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

 $returnValue = @{

 DiskNumber = [System.String]

 DriveLetter = [System.String]

 Ensure = [System.String]

 }

 $returnValue

}

function Set-TargetResource

{

 [CmdletBinding()]

 param

 (

  [parameter(Mandatory = $true)]

  [System.String]

  $DiskNumber,

  [parameter(Mandatory = $true)]

  [System.String]

  $DriveLetter,

  [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."

 New-Partition -DiskNumber $DiskNumber -UseMaximumSize -DriveLetter $DriveLetter | Format-Volume -FileSystem NTFS -Confirm:$false

 #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]

  $DiskNumber,

  [parameter(Mandatory = $true)]

  [System.String]

  $DriveLetter,

  [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."

 (Get-Partition -DiskNumber $DiskNumber | Where-Object ({$PSItem.DriveLetter -eq $DriveLetter})).DriveLetter -eq $DriveLetter

}

Export-ModuleMember -Function *-TargetResource

So now I save the file and re-import the module. Let's take a look at the DSC resources we've created:

PS C:\Windows\system32> Get-DscResource -Module DiskSize -Syntax

DiskPartition [String] #ResourceName

{

 DiskNumber = [string]

 DriveLetter = [string]

 [DependsOn = [string[]]]

 [Ensure = [string]{ Absent | Present }]

 [PsDscRunAsCredential = [PSCredential]]

}

DiskResize [String] #ResourceName

{

 DiskSize = [UInt64]

 DriveLetter = [string]

 [DependsOn = [string[]]]

 [Ensure = [string]{ Absent | Present }]

 [PsDscRunAsCredential = [PSCredential]]

}

Awesome! Now let's import the module. We’ll test the DiskResize resource first because we need to resize the C partition before we can create the new partition. We'll place this as the first step in our configuration.

configuration CMDPConfig

{

 Import-DscResource -ModuleName @{ModuleName = 'DiskSize'; ModuleVersion = '1.0.0.0'}

 Import-DscResource -ModuleName @{ModuleName = 'PSDesiredStateConfiguration'; ModuleVersion = '1.1' }

 Import-DscResource -ModuleName @{ModuleName = 'xNetworking'; ModuleVersion = '2.5.0.0'}

 Node ("LWINCM02")

 {

  # Call Resource Provider

  # E.g: WindowsFeature, File

  #Remove GUI Tools

  LocalConfigurationManager

  {

   RebootNodeIfNeeded = $true

   ConfigurationMode = "ApplyAndAutoCorrect"

  }

  DiskResize CDrive

  {

   DiskSize = "40GB"

   DriveLetter = 'C'

   Ensure = 'Present'

  }

We’ll generate a new .mof file for our test machine. Remember to copy the new module to the test system because we're still using push configuration. And now we execute, and check our partition size:

Image of command output

Finally, let's update our configuration with the new partition resource provider and push our configuration to the target server.

Image of command output

We have success!

We've managed to take our Windows PowerShell configuration script and create a DSC configuration from it. We've even added some things to our configuration that we didn't previously have in the script by creating some new DSC resources for it.

There's still plenty of cleanup that needs to be done with our configuration and resources, such as adding error handling and some parameterization so we can further automate our deployments. By now, though, you should have a better understanding of how you can use Desired State Configuration to create basic configurations for your environment.

~Will

Wow! What a week. Thanks, Will, for seven days of DSC greatness. This is some really cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Also check out my Microsoft Operations Management Suite Blog. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy