I've been playing around a little with this issue, trying to keep track of both what configurations are tied to what GUIDs, and then which machines are configured to pull those GUIDs. I opted for a SQL database approach, and came up with a couple of scripts:
Function Publish-DSCConfiguration{ Param ( [Parameter(Mandatory=$True)] [ValidateScript({test-path $_ })] [System.IO.FileInfo]$Path, [String]$Description, [Parameter(Mandatory=$True)] [Guid]$Guid ) Write-Verbose "Validating parameters" If (!($Path.name -like "*.mof")){ Write-Verbose "Specified path not a MOF file. Searching directory" $path = Get-ChildItem $path -filter *.mof if ($path.count -eq 0){ Write-error "MOF file not found in specified Path" -ErrorAction Stop } Elseif ($path.count -gt 1){ Write-error "Multiple MOF files found in specified Path. Please specify correct file" -ErrorAction Stop } else { Write-Verbose "MOF file found at $path" } } $dest = "\\PULLSERVER\c`$\Program Files\WindowsPowerShell\DscService\Configuration\$guid.mof" if(!(Test-Path -path (split-path -Path $dest -Parent))){ Write-Error "Cannot access destination directory $(split-path -path $dest.fullname -parent)" -erroraction Stop } Write-Verbose "Attempt database connection before updating files" Try{ $SQLReadConn = New-Object System.Data.SqlClient.SqlConnection $SQLReadConn.ConnectionString = "server=.\SQLExpress;database=DSCData;trusted_connection=true;" $SQLReadConn.Open() $SQLWriteConn = New-Object System.Data.SqlClient.SqlConnection $SQLWriteConn.ConnectionString = "server=.\SQLExpress;database=DSCData;trusted_connection=true;" $SQLWriteConn.Open() } Catch{ Write-Error "Unable to connect to database, halting script." -ErrorAction Stop } If (test-path $dest -ea SilentlyContinue){ Write-Verbose "File exists, creating backup" Copy $dest "$(split-path $dest -parent)\Backup\$(Split-path $dest -Leaf)-$(get-date -UFormat "%m.%d.%y-%H.%M")" -Force -ErrorAction Stop } copy $Path $dest -Force -ErrorAction Stop New-DscCheckSum $dest -force -ErrorAction Stop #Once publishing is complete, write data to tracking database #If new config, write Configname ($path.name), GUID, creation date #If updated config, update/write configname ($Path.name), GUID, modify date $ConfigName = $((split-path $path -parent).split('\')[-1]) $SQLReadCmd = New-Object System.Data.SqlClient.SqlCommand $SQLReadCmd.Connection = $SQLReadConn $SQLReadCmd.CommandText = "SELECT * FROM ConfigList WHERE Guid='$guid'" $result = $SQLReadCmd.ExecuteReader() If ($result.length -eq $Null){ Write-Verbose "GUID not found in database, writing entry as new configuration" $SQLString = "INSERT INTO ConfigList (Guid,ConfigName,CreationDate,Description) VALUES('{0}','{1}','{2}','{3}')" -f $Guid,$ConfigName,$(get-date),$Description } Else { Write-Verbose "Entry found in database for GUID, updating record" $SQLString = "UPDATE ConfigList SET ConfigName = '$ConfigName', UpdateTime = '$(Get-date)', Description = '$Description' WHERE Guid = '$guid'" } $SQLWriteCmd = New-Object System.Data.SqlClient.SqlCommand $SQLWriteCmd.Connection = $SQLWriteConn $SQLWriteCMD.CommandText = $SQLString $SQLWriteCmd.executenonquery() | Out-Null $SQLReadConn.Close() $SQLWriteConn.Close() }
I'll generate my mof like normal, then use this script to move it and rename it with a guid, then write the info into a sql database, recording GUID, creation date/time, last updated date/time, and the name of the configuration before it was moved. So for a new config the command might be this:
Publish-DSCConfiguration -Path C:\dsc\BaselineServer\localhost.mof -Guid $([GUID]::NewGuid()) -Verbose
Then once it is out on the pull server, I'll use this code to tell a server to pull that file:
Configuration SetPullMode{ Param( [parameter(Mandatory=$True)] [string]$guid ) LocalConfigurationManager{ ConfigurationMode = "ApplyAndAutoCorrect" ConfigurationID=$guid RefreshMode='Pull' DownloadManagerName='WebDownloadManager' DownloadManagerCustomData=@{ ServerUrl = 'https://PSDSCPullServerCert:8080/PSDSCPullServer.svc'; } } } Function Set-DSCPullConfig{ Param( [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [Alias('Computername','Computer')] [String[]]$NodeName, [Parameter(Mandatory=$True)] [Guid]$Guid ) Begin{ write-verbose "Generating MOF" $MofPath = SPlit-path -path $(SetPullMode -guid $guid -OutputPath C:\DSC\SetPullMode) -Parent Write-Verbose "Testing database access" Try{ $SQLReadConn = New-Object System.Data.SqlClient.SqlConnection $SQLReadConn.ConnectionString = "server=.\SQLExpress;database=DSCData;trusted_connection=true;" $SQLReadConn.Open() $SQLReadConn.Close() $SQLWriteConn = New-Object System.Data.SqlClient.SqlConnection $SQLWriteConn.ConnectionString = "server=.\SQLExpress;database=DSCData;trusted_connection=true;" $SQLWriteConn.Open() $SQLWriteConn.Close() } Catch{ Write-Error "Unable to connect to database, halting script." -ErrorAction Stop } } Process{ Foreach ($Computer in $NodeName){ Write-Verbose "Pushing LCM config to $computer" Copy-Item "$mofpath\localhost.meta.mof" "$mofpath\$computer.meta.mof" Set-DscLocalConfigurationManager -ComputerName $Computer -path $MofPath -ErrorAction Stop Write-Verbose "Updating configuration database" $SQLReadConn = New-Object System.Data.SqlClient.SqlConnection $SQLReadConn.ConnectionString = "server=.\SQLExpress;database=DSCData;trusted_connection=true;" $SQLReadConn.Open() $SQLWriteConn = New-Object System.Data.SqlClient.SqlConnection $SQLWriteConn.ConnectionString = "server=.\SQLExpress;database=DSCData;trusted_connection=true;" $SQLWriteConn.Open() $SQLReadCmd = New-Object System.Data.SqlClient.SqlCommand $SQLReadCmd.Connection = $SQLReadConn $SQLReadCmd.CommandText = "SELECT * FROM AssignList WHERE ComputerName='$Computer'" $result = $SQLReadCmd.ExecuteReader() If ($result.length -eq $Null){ Write-Verbose "Computer $computer not found in database, writing entry as new configuration" $SQLString = "INSERT INTO AssignList (Guid,ComputerName,AssignDate) VALUES('{0}','{1}','{2}')" -f $Guid,$Computer,$(get-date) } Else { Write-Verbose "Entry found in database for $computer, updating record" $SQLString = "UPDATE AssignList SET Guid = '$guid', AssignDate = '$(Get-date)' WHERE ComputerName = '$Computer'" } $SQLWriteCmd = New-Object System.Data.SqlClient.SqlCommand $SQLWriteCmd.Connection = $SQLWriteConn $SQLWriteCMD.CommandText = $SQLString $SQLWriteCmd.executenonquery() | Out-Null Write-Verbose "Closing database connections" $SQLReadConn.Close() $SQLWriteConn.Close() } #After setting the configuration update a database table #include computername, assigned guid, date the config was pushed } End{ } }
I just parameterized the GUID portion of the LCM configuration so I can pass it whatever, then I generate the MOF, push it out to the server (a push to tell it to pull, still mixes me up a bit) then I write an entry in a second table that lists the server name, the assigned guid and the date it was set.
Not super elegant or anthing, and I still need to clean up the code a bit, document, etc. but so far it seems to work.