Pseudo-Splatting DSC Resources

Here’s a quick function to allow you something close to splatting with DSC resources:


function Get-DscSplattedResource {
[CmdletBinding()]
Param(
[String]
$ResourceName,
[String]
$ExecutionName,
[hashtable]
$Properties
)
$stringBuilder = [System.Text.StringBuilder]::new()
$null = $stringBuilder.AppendLine("Param([hashtable]`$Parameters)")
$null = $stringBuilder.AppendLine(" $ResourceName $ExecutionName { ")
foreach($PropertyName in $Properties.keys) {
$null = $stringBuilder.AppendLine("$PropertyName = `$(`$Parameters['$PropertyName'])")
}
$null = $stringBuilder.AppendLine("}")
Write-Debug ("Generated Resource Block = {0}" -f $stringBuilder.ToString())
[scriptblock]::Create($stringBuilder.ToString()).Invoke($Properties)
}
Set-Alias -Name x -Value Get-DscSplattedResource

Here’s why you may need it.

In DSC, quite often you need to specify a resource with some values like so:

https://gist.github.com/gaelcolas/69e26e1cef3da4a6b711fdc5588400f9

But what if you have an hashtable readily available:

https://gist.github.com/gaelcolas/4481593e2548b50460637700eaa14ddb

Or if you’re iterating through a list of  hashtable, and some don’t contain a value:


#Assuming you already have this hashtable
$MyHashes = @(
@{
Ensure = 'Present'
Name = 'Putty'
Version = 'Latest'
ChocolateyOptions = @{ source = 'https://chocolatey.org/api/v2/' }
},
@{
Ensure = 'Absent'
Name = 'notepadplusplus'
}
)
Configuration MyDscConfig {
$Allnodes.nodename {
#The second Item will error because of missing properties
foreach($MyHash in $MyHashes) {
ChocolateyPackage Putty {
Ensure = $MyHash['Ensure']
Name = $MyHash['Name']
Version = $MyHash['Version']
ChocolateyOptions = $MyHash['ChocolateyOptions']
}
}
}
}

Well, until splatting is supported natively in DSC, you could use the following function as a way to support splatting in your configurations:


function Get-DscSplattedResource {
[CmdletBinding()]
Param(
[String]
$ResourceName,
[String]
$ExecutionName,
[hashtable]
$Properties
)
$stringBuilder = [System.Text.StringBuilder]::new()
$null = $stringBuilder.AppendLine("Param([hashtable]`$Parameters)")
$null = $stringBuilder.AppendLine(" $ResourceName $ExecutionName { ")
foreach($PropertyName in $Properties.keys) {
$null = $stringBuilder.AppendLine("$PropertyName = `$(`$Parameters['$PropertyName'])")
}
$null = $stringBuilder.AppendLine("}")
Write-Debug ("Generated Resource Block = {0}" -f $stringBuilder.ToString())
[scriptblock]::Create($stringBuilder.ToString()).Invoke($Properties)
}
Set-Alias -Name x -Value Get-DscSplattedResource

Be careful in which scope you’re executing this function, because DSC expect the scriptblock invoke in its own scope, not from another module.

But using this trick you can now do something like:


#Assuming you already have this hashtable
$MyHashes = @(
@{
Ensure = 'Present'
Name = 'Putty'
Version = 'Latest'
ChocolateyOptions = @{ source = 'https://chocolatey.org/api/v2/' }
},
@{
Ensure = 'Absent'
Name = 'notepadplusplus'
}
)
. .\Get-DscSplattedResource.ps1
Configuration MyDscConfig {
$Allnodes.nodename {
#The second Item will now work
foreach($MyHash in $MyHashes) {
# 'x' is an alias for my Get-DscSplattedResource function
x ChocolateyPackage $MyHash['name'] $MyHash
}
}
}

3 thoughts on “Pseudo-Splatting DSC Resources

  1. Thank you for this valuable idea! I tried it on a 1300 line DSC config and reduced it to under 200 lines. Much more readable with less duplication. One minor thing I noticed, after the config completed, was that the DependsOn values retrieved from Get-DscConfigurationStatus showed duplicate entries (i.e. the DependsOn value showed up twice). This didn’t affect the outcome as far as I can tell, and it may be my implementation of your suggestion that may have caused it so just wondering if you’ve observed it too. Thanks again well done.

    Like

Leave a comment