Automatically create a checksum and publish DSC MOF configuration files to an SMB pull server
You've configured one or more DSC (Desired State Configuration) SMB pull servers in your environment. You've also configured the target nodes appropriately. One problem that seems to be a constant problem in your environment when authoring and updating DSC configuration files (MOF files) is keeping track of what GUID belongs to which machine and it's also a common problem to forget to update the corresponding checksum when a configuration file is updated. Last week, you spent an entire day troubleshooting an issue where a machine wasn't pulling the updated configuration only to learn that the checksum hadn't been updated. Sound familiar?
To alleviate this problem, you've decided to write a PowerShell function that will be used to automatically determine the appropriate SMB share to copy the MOF configuration files to, determine the correct ConfigurationID (GUID), and generate the necessary checksum. The function to accomplish that task is shown in the following code example:
1#Requires -Version 4.0
2function Publish-MrMOFToSMB {
3
4<#
5.SYNOPSIS
6 Publishes a DSC MOF configuration file to the pull server that's configured on a target node(s).
7
8.DESCRIPTION
9 Publish-MrMOFToSMB is an advanced PowerShell function that publishes one or more MOF configuration files
10 to the an SMB DSC server by determining the ConfigurationID (GUID) that's configured on the target node along
11 with the UNC path of the SMB pull server and creates the necessary checksum along with copying the MOF and
12 checksum to the pull server.
13
14.PARAMETER ConfigurationPath
15 The folder path on the local computer that contains the mof configuration files.
16
17.PARAMETER ComputerName
18 The computer name of the target node that the DSC configuration is created for.
19
20.EXAMPLE
21 Publish-MrMOFToSMB -ConfigurationPath 'C:\MyMofFiles'
22
23.EXAMPLE
24 Publish-MrMOFToSMB -ConfigurationPath 'C:\MyMofFiles' -ComputerName 'Server01', 'Server02'
25
26.EXAMPLE
27 'Server01', 'Server02' | Publish-MrMOFToSMB -ConfigurationPath 'C:\MyMofFiles'
28
29.EXAMPLE
30 MyDscConfiguration -Param1 Value1 -Parm2 Value2 | Publish-MrMOFToSMB
31
32.INPUTS
33 String
34
35.OUTPUTS
36 None
37
38.NOTES
39 Author: Mike F Robbins
40 Website: http://mikefrobbins.com
41 Twitter: @mikefrobbins
42#>
43
44 [CmdletBinding()]
45 param (
46 [Parameter(Mandatory,
47 ValueFromPipelineByPropertyName)]
48 [ValidateScript({Test-Path -Path $_ -PathType Container})]
49 [Alias('Directory')]
50 [string]$ConfigurationPath,
51
52 [Parameter(ValueFromPipeline,
53 ValueFromPipelineByPropertyName)]
54 [Alias('BaseName')]
55 [string[]]$ComputerName
56 )
57
58 BEGIN {
59 if (-not($PSBoundParameters['ComputerName'])) {
60 $ComputerName = (Get-ChildItem -Path $ConfigurationPath\*.mof).basename
61 }
62 }
63
64 PROCESS {
65 foreach ($Computer in $ComputerName) {
66
67 try {
68 Write-Verbose -Message "Retrieving LCM information from $Computer"
69 $LCMConfig = Get-DscLocalConfigurationManager -CimSession $Computer -ErrorAction Stop
70 }
71 catch {
72 Write-Error -Message "An error has occurred. Error details: $_.Exception.Message"
73 continue
74 }
75
76 $servermof = "$ConfigurationPath\$Computer.mof"
77
78 if (-not(Get-ChildItem -Path $servermof -ErrorAction SilentlyContinue)) {
79 Write-Error -Message "Unable to find MOF file for $Computer in location: $ConfigurationPath"
80 }
81 elseif ($LCMConfig.RefreshMode -ne 'Pull') {
82 Write-Error -Message "The LCM on $Computer is not configured for DSC pull mode."
83 }
84 elseif ($LCMConfig.DownloadManagerName -ne 'DscFileDownloadManager' -and $LCMConfig.ConfigurationDownloadManagers.ResourceId -notlike '`[ConfigurationRepositoryShare`]*') {
85 Write-Error -Message "LCM on $Computer not configured to receive configuration from DSC SMB pull server"
86 }
87 elseif (-not($LCMConfig.ConfigurationID)) {
88 Write-Error -Message "A ConfigurationID (GUID) has not been set in the LCM on $Computer"
89 }
90 else {
91 if ($LCMConfig.ConfigurationDownloadManagers.SourcePath) {
92 $SMBPath = "$($LCMConfig.ConfigurationDownloadManagers.SourcePath)"
93 }
94 elseif ($LCMConfig.DownloadManagerCustomData.Value) {
95 $SMBPath = "$($LCMConfig.DownloadManagerCustomData.Value)"
96 }
97
98 Write-Verbose -Message "Creating DSCChecksum for $servermof"
99 New-DSCCheckSum -ConfigurationPath $servermof -Force
100
101 if (Test-Path -Path $SMBPath) {
102
103 $guidmof = Join-Path -Path $SMBPath -ChildPath "$($LCMConfig.ConfigurationID).mof"
104
105 try {
106 Write-Verbose -Message "Copying $servermof.checksum to $guidmof.checksum"
107 Copy-Item -Path "$servermof.checksum" -Destination "$guidmof.checksum" -ErrorAction Stop
108
109 Write-Verbose -Message "Copying $servermof to $guidmof"
110 Copy-Item -Path $servermof -Destination $guidmof -ErrorAction Stop
111 }
112 catch {
113 Write-Error -Message "An error has occurred. Error details: $_.Exception.Message"
114 }
115
116 }
117 else {
118 Write-Error -Message "Unable to connect to $SMBPath as specified in the LCM on $Computer for it's DSC pull server"
119 }
120 }
121 }
122 }
123}
A very basic configuration will be used to test the function shown in the previous example.
1configuration TelnetClient {
2 param (
3 [Parameter(Mandatory)]
4 [string[]]$ComputerName
5 )
6 node $ComputerName {
7 WindowsFeature TelnetClient {
8 Name = 'Telnet-Client'
9 Ensure = 'Present'
10 }
11 }
12}
After the configuration is loaded into memory, it's called as it normally would be to generate the
MOF configuration files and then it can simply be piped to the Publish-MrMOFToSMB
function which
will query the target node for the necessary information to automatically generate the required
checksum and copy both the MOF configuration and checksum files to the SMB pull server, renaming the
files to the GUID name on the destination end:
1TelnetClient -ComputerName 'Server01', 'Server02' | Publish-MrMOFToSMB -Verbose
If the MOF files have already been generated and you want to publish all of the ones in the
.\TelnetClient folder to the appropriate SMB pull server, just specify that path via the
ConfigurationPath
parameter:
1Publish-MrMOFToSMB -ConfigurationPath .\TelnetClient -Verbose
If you only want to publish some of the existing MOF files in that folder, specify one or more
computer names via the ComputerName
parameter:
1Publish-MrMOFToSMB -ComputerName server01 -ConfigurationPath .\TelnetClient -Verbose
For preexisting MOF files, the computer names can also be specified via parameter input which allows you to programmatically determine the computer names you want to publish the existing MOF files for by piping the results of some other cmdlet into this one:
1'server02' | Publish-MrMOFToSMB -ConfigurationPath .\TelnetClient -Verbose
Parameter validation is performed on the ConfigurationPath
parameter which means if the path
specified for the MOF files doesn't exist, the function will stop at that point and not attempt to
continue any further:
1Publish-MrMOFToSMB -ComputerName server01 -ConfigurationPath .\DoesNotExist -Verbose
There are various other checks in place as well. Errors will be generated if the target node is offline, if the MOF file doesn't already exist, if the LCM on the target node is not configured for pull mode or for SMB, if the ConfigurationID hasn't been set to a GUID, and if the SMB share that's specified in the target node's LCM cannot be contacted:
1Publish-MrMOFToSMB -ComputerName server01, server05, sql01, dc01, server03, server04, dc02, server02 -ConfigurationPath .\TelnetClient -Verbose
Any of the ones that are specified which are valid will complete successfully as shown in the previous set of results where server01 and server02 (the first and last one) completed successfully even though all of the others failed for the specified reasons.
µ