Separating configuration and environment data
Applies To: Windows PowerShell 4.0, Windows PowerShell 5.0
It can be useful to separate the data used in a DSC configuration from the configuration itself by using configuration data. By doing this, you can use a single configuration for multiple environments.
For example, if you are developing an application, you can use one configuration for both development and production environments, and use configuration data to specify data for each environment.
What is configuration data?
Configuration data is data that is defined in a hashtable and passed to a DSC configuration when you compile that configuration.
For a detailed description of the ConfigurationData hashtable, see Using configuration data.
A simple example
Let's look at a very simple example to see how this works. We'll create a single configuration that ensures that IIS is present on some nodes, and that Hyper-V is present on others:
Configuration MyDscConfiguration {
Node $AllNodes.Where{$_.Role -eq "WebServer"}.NodeName
{
WindowsFeature IISInstall {
Ensure = 'Present'
Name = 'Web-Server'
}
}
Node $AllNodes.Where{$_.Role -eq "VMHost"}.NodeName
{
WindowsFeature HyperVInstall {
Ensure = 'Present'
Name = 'Hyper-V'
}
}
}
$MyData =
@{
AllNodes =
@(
@{
NodeName = 'VM-1'
Role = 'WebServer'
},
@{
NodeName = 'VM-2'
Role = 'VMHost'
}
)
}
MyDscConfiguration -ConfigurationData $MyData
The last line in this script compiles the configuration, passing $MyData
as the value
ConfigurationData parameter.
The result is that two MOF files are created:
Directory: C:\DscTests\MyDscConfiguration
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/31/2017 5:09 PM 1968 VM-1.mof
-a---- 3/31/2017 5:09 PM 1970 VM-2.mof
$MyData
specifies two different nodes, each with its own NodeName
and Role
. The configuration
dynamically creates Node blocks by taking the collection of nodes it gets from $MyData
(specifically, $AllNodes
) and filters that collection against the Role
property..
Using configuration data to define development and production environments
Let's look at a complete example that uses a single configuration to set up both development and production environments of a website. In the development environment, both IIS and SQL Server are installed on a single nodes. In the production environment, IIS and SQL Server are installed on separate nodes. We'll use a configuration data .psd1 file to specify the data for the two different environments.
Configuration data file
We'll define the development and production environment data in a file named DevProdEnvData.psd1
as follows:
@{
AllNodes = @(
@{
NodeName = "*"
SQLServerName = "MySQLServer"
SqlSource = "C:\Software\Sql"
DotNetSrc = "C:\Software\sxs"
WebSiteName = "New website"
},
@{
NodeName = "Prod-SQL"
Role = "MSSQL"
},
@{
NodeName = "Prod-IIS"
Role = "Web"
SiteContents = "C:\Website\Prod\SiteContents\"
SitePath = "\\Prod-IIS\Website\"
},
@{
NodeName = "Dev"
Role = "MSSQL", "Web"
SiteContents = "C:\Website\Dev\SiteContents\"
SitePath = "\\Dev\Website\"
}
)
}
Configuration script file
Now, in the configuration, which is defined in a .ps1
file, we filter the nodes we defined in
DevProdEnvData.psd1
by their role (MSSQL
, Dev
, or both), and configure them accordingly. The
development environment has both the SQL Server and IIS on one node, while the production
environment has them on two different nodes. The site contents is also different, as specified by
the SiteContents
properties.
At the end of the configuration script, we call the configuration (compile it into a MOF document),
passing DevProdEnvData.psd1
as the $ConfigurationData
parameter.
Note: This configuration requires the modules
xSqlPs
andxWebAdministration
to be installed on the target node.
Let's define the configuration in a file named MyWebApp.ps1
:
Configuration MyWebApp
{
Import-DSCResource -ModuleName PSDesiredStateConfiguration
Import-DSCResource -ModuleName xSqlPs
Import-DSCResource -ModuleName xWebAdministration
Node $AllNodes.Where{$_.Role -contains "MSSQL"}.NodeName
{
# Install prerequisites
WindowsFeature installdotNet35
{
Ensure = "Present"
Name = "Net-Framework-Core"
Source = "c:\software\sxs"
}
# Install SQL Server
xSqlServerInstall InstallSqlServer
{
InstanceName = $Node.SQLServerName
SourcePath = $Node.SqlSource
Features = "SQLEngine,SSMS"
DependsOn = "[WindowsFeature]installdotNet35"
}
}
Node $AllNodes.Where{$_.Role -contains "Web"}.NodeName
{
# Install the IIS role
WindowsFeature IIS
{
Ensure = 'Present'
Name = 'Web-Server'
}
# Install the ASP .NET 4.5 role
WindowsFeature AspNet45
{
Ensure = 'Present'
Name = 'Web-Asp-Net45'
}
# Stop the default website
xWebsite DefaultSite
{
Ensure = 'Present'
Name = 'Default Web Site'
State = 'Stopped'
PhysicalPath = 'C:\inetpub\wwwroot'
DependsOn = '[WindowsFeature]IIS'
}
# Copy the website content
File WebContent
{
Ensure = 'Present'
SourcePath = $Node.SiteContents
DestinationPath = $Node.SitePath
Recurse = $true
Type = 'Directory'
DependsOn = '[WindowsFeature]AspNet45'
}
# Create the new Website
xWebsite NewWebsite
{
Ensure = 'Present'
Name = $Node.WebSiteName
State = 'Started'
PhysicalPath = $Node.SitePath
DependsOn = '[File]WebContent'
}
}
}
MyWebApp -ConfigurationData DevProdEnvData.psd1
When you run this configuration, three MOF files are created (one for each named entry in the AllNodes array):
Directory: C:\DscTests\MyWebApp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/31/2017 5:47 PM 2944 Prod-SQL.mof
-a---- 3/31/2017 5:47 PM 6994 Dev.mof
-a---- 3/31/2017 5:47 PM 5338 Prod-IIS.mof
Using non-node data
You can add additional keys to the ConfigurationData hashtable for data that is not specific to
a node. The following configuration ensures the presence of two websites. Data for each website are
defined in the AllNodes array. The file Config.xml
is used for both websites, so we define it
in an additional key with the name NonNodeData
. Note that you can have as many additional keys as
you want, and you can name them anything you want. NonNodeData
is not a reserved word, it is just
what we decided to name the additional key.
You access additional keys by using the special variable $ConfigurationData. In this example,
ConfigFileContents
is accessed with the line:
Contents = $ConfigurationData.NonNodeData.ConfigFileContents
in the File
resource block.
$MyData =
@{
AllNodes =
@(
@{
NodeName = "*"
LogPath = "C:\Logs"
},
@{
NodeName = "VM-1"
SiteContents = "C:\Site1"
SiteName = "Website1"
},
@{
NodeName = "VM-2"
SiteContents = "C:\Site2"
SiteName = "Website2"
}
);
NonNodeData =
@{
ConfigFileContents = (Get-Content C:\Template\Config.xml)
}
}
configuration WebsiteConfig
{
Import-DscResource -ModuleName xWebAdministration -Name MSFT_xWebsite
node $AllNodes.NodeName
{
xWebsite Site
{
Name = $Node.SiteName
PhysicalPath = $Node.SiteContents
Ensure = "Present"
}
File ConfigFile
{
DestinationPath = $Node.SiteContents + "\\config.xml"
Contents = $ConfigurationData.NonNodeData.ConfigFileContents
}
}
}