When working with PowerShell DSC your scripts often get big and difficult to follow. If you are not careful you will end up copy and pasting configuration. I don’t like Copy/Paste coding so I was looking for a mechanism to allow me to reuse my DSC scripts. I came across Composite Resources.
Composite resources look very similar to you main DSC configuration but along with parameters they allow you to write reusable configuration. The following blog post has a good introduction to composite resources:
http://blogs.msdn.com/b/powershell/archive/2014/02/25/reusing-existing-configuration-scripts-in-powershell-desired-state-configuration.aspx
I followed this post but I had a few issues trying to get my composite resource to be recognised by my DSC configuration. The main issues is that the composite resource requires a very specific structure within which the files need to be put in order for it to be recognised. It then needs copying to somewhere on the DSC module path. On my computer this was C:\Program Files\WindowsPowerShell\Modules. The structure is as follows:
MyModule.psd1 & MyCompositeResource.psd1 are manifest files created using New-ModuleManifest. This effectively creates a GUID for the module and the resource. Once these files are created open up MyCompositeResource.psd1 and edit the following line :
RootModule = ‘MyCompositeResource.schema.psm1'
To check to see if the module is configured and structured correctly, go to PowerShell and type:
Get-DscResource -Name MyCompositeResource
If it is configured correctly then PowerShell will return details of the module
ImplementedAs Name Module Properties
------------- ---- ------ ----------
Composite MyCompositeResource MyModule {ServiceName, exeFullPath, sourcePath, destinat...
If you want to use the composite resource on a pull server then the whole MyModules folder needs zipping and a checksum file creating, then copy it to the modules folder on your pull server where all the other modules reside.
This now works well until I added a Script resource to my composite resource. I was creating a composite resource to install a set of windows services and the process I was following required me to uninstall and then reinstall the service using a script. The script block worked fine until I had multiple services using the same composite resource. I then started getting errors when creating the MOF file complaining that I had duplicate keys for my script blocks.
“Add-NodeKeys : The key properties combination 'some script' is duplicated for keys 'GetScript,SetScript,TestScript' of resource 'Script' in node 'nodename'. Please make sure key properties are unique for each resource in a node”
After a bit of searching I found this post: https://www.briantist.com/how-to/use-duplicate-dsc-script-resources-in-loop/ which explains how to resolve the problem. I copied the Replace-Using script to the top of my composite resource file and then piped the GetScript, TestScript and SetScripts to Replace-Using
e.g.
Script Service.UrlAcl
{
GetScript = {$using:ServiceName + "UrlAclGet"} |Replace-Using
TestScript =
{
if([String]::IsNullOrEmpty($using:UrlAcl))
{
Write-Verbose -Message "urlacl not configured in parameters"
return $true
}
else
{
[String] $resp = (netsh http show urlacl url=$using:UrlAcl | findstr -i $using:UrlAcl)
Write-Verbose -Message "netsh returned $resp for url $using:UrlAcl"
if( [string]::IsNullOrEmpty($resp) -OR ($resp.IndexOf($using:UrlAcl) -eq -1) )
{
# The url is not registered
Write-Verbose -Message "urlacl=$using:UrlAcl not registered"
return $false
}
else
{
Write-Verbose -Message "urlacl=$using:UrlAcl IS registered"
return $true
}
}
} |Replace-Using
SetScript =
{
$fullun= $using:un
$domainpos = $fullun.IndexOf("\")
if ($domainpos -ne -1 )
{
$fullun=$fullun.Substring($domainpos+1)
}
Write-Verbose -Message "Setting urlacl= $using:UrlAcl for $fullun"
netsh http add urlacl url=$using:UrlAcl user=$fullun
} |Replace-Using
DependsOn = "[Script]Service.Install"
}
I now have a working composite resource that I can add to my pull server to configure up Windows Services