One of the first ways that you can have a single Configuration script produce multiple unique MOFs is to supply the script with configuration data. This is something that lives apart from the script itself, and is assigned to the Configuration when the Configuration is compiled. See the following basic example:
configuration MyMasterConfig {
# configurations go here
}
$configData = @{}
MyMasterConfig -ConfigurationData $configData
We’ve created a Configuration named MyMasterConfig. Separately - and this could have been in a totally different file that we dot-sourced, for example - we created a $configData hash table. Then, we run the config, and pass in the hash table using a built-in parameter. Now, the configuration data is available “inside” MyMasterConfig.
Defining Configuration Data
The top level Configuration data hash table needs to contain two elements, AllNodes and NonNodeData. AllNodes is an array, and it’ll contain all of the unique node information that you need to provide. Each element within the array is a new hash table, which must at least contain a NodeName element. See the following example:
$MyData =
@{
AllNodes =
@(
@{
NodeName = 'DEMOWWW0001'
Role = 'WebServer'
},
@{
NodeName = 'DEMOWWW0002'
Role = 'WordPress'
},
@{
NodeName = 'DEMOWWW0003'
Role = 'WebServer'
}
);
NonNodeData = ''
}
Here, we’ve defined three nodes, named DEMOWWW0001, DEMOWWW0002, and DEMOWWW0003. For each, we’ve defined a “Role” property. In order to create that connection, we need to run the Configuration, and use its built-in -ConfigurationData parameter to pass in $MyData.
Referencing and Using Configuration Data
Inside the Configuration we’ll use three built-in variables:
- $AllNodes automatically gets you the AllNodes@() portion of your ConfigurationData block.
- Once you’ve filtered the $AllNodes collection, you can use $Node to refer to just the current node.
- $ConfigurationData represents the entire block of data.
Pretend that the above three-node data block has been defined in the same script as this example:
configuration AllMyServers {
Node $AllNodes.Where({$_.Role -eq "WebServer"}).NodeName {
}
}
AllMyServers -ConfigurationData $MyData
The Node{} construct wants you to provide a list of node names. That’s it - just computer names, and no other data. So we’re taking $AllNodes, which contains everything. We’re using its special Where method to grab only those nodes whose Role property is set to WebServer.
Now let’s add a bit more:
configuration AllMyServers {
import-DSCResource xWebAdministration
Node $AllNodes.Where({$_.Role -eq "WebServer"}).NodeName {
xWebSite TheWeb {
Name = $Node.NodeName
PhysicalPath = 'c:\inetpub\wwwroot'
Ensure = 'Present'
}
}
}
AllMyServers -ConfigurationData $MyData
Within the Node{} construct, PowerShell will automatically run the contents once for each node you’ve given it. You can see that this is going to produce two MOF files, one named DEMOWWW0001.mof and another named DEMOWWW0003.mof, both (by default) in a folder named /AllMyServers. Each MOF will define a website, which will have the same name as the server itself. Let´´ add some more settings to the configuration.
$MyData =
@{
AllNodes =
@(
@{
NodeName = 'DEMOWWW0001'
Role = 'WebServer'
Site = 'CustomApp'
SitePath = 'c:\inetpub\approot'
},
@{
NodeName = 'DEMOWWW0002'
Role = 'WordPress'
},
@{
NodeName = 'DEMOWWW0003'
Role = 'WebServer'
Site = 'App2'
SitePath = 'c:\inetpub\app2root'
}
);
NonNodeData = ''
}
Notice that we’ve added Site and SitePath properties only to the nodes that have a WebServer value for Role. So now we can use those two new properties:
configuration AllMyServers {
Node $AllNodes.Where({$_.Role -eq "WebServer"}).NodeName {
xWebSite TheWeb {
Name = $Node.Site
PhysicalPath = $Node.SitePath
Ensure = 'Present'
}
}
}
AllMyServers -ConfigurationData $MyData
You can see how the data block allows us to use a single Configuration script to produce multiple, unique MOFs for multiple nodes.
All-Nodes Data
You can also specify properties to apply to all nodes:
$MyData =
@{
AllNodes =
@(
@{ NodeName = '*'
SystemRoot = 'c:\windows\system32'
},
@{
NodeName = 'DEMOWWW0001'
Role = 'WebServer'
Site = 'CustomApp'
SitePath = 'c:\inetpub\approot'
},
@{
NodeName = 'DEMOWWW0002'
Role = 'WordPress'
},
@{
NodeName = 'DEMOWWW0003'
Role = 'WebServer'
Site = 'App2'
SitePath = 'c:\inetpub\app2root'
}
);
NonNodeData = ''
}
Now, all three nodes also have a SystemRoot property.
Using the $AllNodes Variable
The $AllNodes variable becomes a key for making those MOFs unique. It has two special functions: Where and ForEach:
$AllNodes.Where({ $_.Site -eq 'CustomApp' }) # returns 1 node
$AllNodes.Where({ $_.NodeName -like 'NODE*' }) # returns 1 node
$AllNodes.Where({ $_.SystemRoot -eq 'c:\windows\system32' }) # returns 3 nodes
Imagine this Configuration data block:
{
AllNodes = @(
@{
NodeName = '*'
FilesToCopy = @(
@{
SourcePath = 'C:\SampleConfig.xml'
TargetPath = 'C:\SampleCode\SampleConfig.xml'
},
@{
SourcePath = 'C:\SampleConfig2.xml'
TargetPath = 'C:\SampleCode\SampleConfig2.xml'
}
}
Now you might use a ForEach loop:
configuration CopyStuff {
Node $AllNodes.NodeName {
$filenumber = 1
ForEach ($file in $Node.FilesToCopy) {
File "File$filenumber" {
Ensure = 'Present'
Type = 'File'
SourcePath = $file.SourcePath
DestinationPath = $file.TargetPath
}
$filenumber++
}
}
}
Using NonNodeData
There’s a couple of important things to know about this section. First, you do not have to call the section “NonNodeData”, and second, you can have multiple NonNodeData sections, which makes a NonNodeData section a good option for role-specific settings that do not pertain to all nodes.
The snippet below shows two NonNodeData sections, one for domain controller settings (DCData) and the other for DHCP server settings (DHCPData).
$MyData = @{
AllNodes = @( ... )
DCData = @{
DomainName = "Test.Pri"
DomainDN = "DC=Test,DC=Pri"
DCDatabasePath = "C:\NTDS"
DCLogPath = "C:\NTDS"
SysvolPath = "C:\Sysvol"
}
DHCPData = @{
DHCPName = 'DHCP1'
DHCPIPStartRange = '192.168.3.200'
DHCPIPEndRange = '192.168.3.250'
DHCPSubnetMask = '255.255.255.0'
DHCPState = 'Active'
DHCPAddressFamily = 'IPv4'
DHCPLeaseDuration = '00:08:00'
DHCPScopeID = '192.168.3.0'
DHCPDnsServerIPAddress = '192.168.3.10'
DHCPRouter = '192.168.3.1'
}
}
Keep in mind that you have the special $ConfigurationData variable, and $ConfigurationData.