Chapter 6. Pulling DSC Configurations

In Chapter 5, Pushing DSC Configurations, we covered how to push a DSC configuration to a target node using Start-DscConfiguration. This method required a lot of steps to be performed each time you provisioned a new target node, as well as a few repetitive steps each time you pushed a new DSC configuration to it. Some of it could be scripted away, but it required extra work to accomplish the automation. A DSC Pull Server provides features that remove the responsibility for automating these steps from you and performs them itself, saving you both time and effort. Throughout the course of this chapter, we will cover the ways DSC Pull Servers will help you in managing the configuration of your target nodes as well as reducing the amount of work you have to perform.

In this chapter, we will cover:

  • Creating DSC Pull Servers
  • Validating a DSC Pull Server install
  • Registering target nodes with a DSC Pull Server
  • Pulling DSC configurations with a DSC Pull Server
  • DSC Pull Server and target node status

Creating DSC Pull Servers

We covered installing DSC Pull Servers in Chapter 2, DSC Architecture, by showing an example DSC configuration script and listing several steps to configure the server afterwards. If we covered it there, why do we need to devote a chapter to it here? Well, for one, we skipped a lot of detail about how to actually use that DSC configuration. We dived right into an example DSC configuration script, but you couldn't actually use it then because we hadn't yet gotten to Chapter 5, Pushing DSC Configurations, where you learned how to push DSC configurations. Installing the first DSC Pull Server with DSC is like the chicken-and-egg problem; you want to use DSC Pull Server to deploy DSC configurations and handle all the deployment processes for you, but you need to first push a DSC configuration to install the DSC Pull Server. It will require some one-time setup work, but the initial effort will pay dividends as time goes on and you continue to use the DSC Pull Server.

If there are extra steps or other problems with installing DSC servers automatically using DSC, why bother? You could in theory install a DSC Pull Server yourself by hand if you wanted to, but it is clearly not an option Microsoft or anyone who uses DSC expects you to take. There are no instructions out there to tell you the steps to do so by hand, and the configuration of the components used by the DSC Pull Server are not documented for you to reproduce. It would take a lot of time and effort for you to accomplish this, with no substantial benefit to you. There are many complex parts to a DSC pull server that aren't Microsoft DSC software-specific, so there isn't an MSI or package to distribute to you. Like we covered earlier, some components are already present on the target server (IIS, the DSC feature, and so on) and others need copying and configuration (IIS website files and OData endpoint configurations).

It is a complex set of software that acts together to present one whole or system.

Another reason for devoting a whole chapter to DSC pull servers is that we did not cover the differences between a WMF 4 Pull Server and the new features of a WMF 5 Pull Server and how they affect your deployment choices. In WMF 5, the PowerShell team added new target node registration methods as well as a new feature for DSC configurations called partial configurations. We'll address these new features and changes throughout the course of this chapter.

DSC Pull Server setup considerations

There are some considerations to decide on before you start installing DSC Pull Servers. Making these decisions now will not only allow you to install the DSC Pull Server successfully the first time, but also ensure that the Pull Server continues to operate correctly in your environment as time goes on.

DSC Pull Server types

A DSC Pull Server can either be installed as an HTTP Pull Server or an SMB Pull Server. You must choose which type to use before installing your DSC Pull Server as it determines how the target nodes communicate with the DSC Pull Server and how it functions internally.

An SMB pull sever is very easy to get running as it requires just a properly set up file share to function. In simple network topology environments or those with existing file shares, it may be easier to use an SMB DSC Pull Server. In more complicated network topology environments, accessing file shares with complicated permission rules, across firewalls or multi-domain AD forests, is difficult to get right. SMB Pull Servers also introduce two points of contact for a target node to work: the DSC Pull Server itself and the server where the file share is hosted. All target nodes must be able to reach the file share server, something that may be harder to accomplish for a file server than a single-purpose DSC Pull Server.

An HTTP Pull Server, in comparison, requires more initial effort to get working but may be easier to use long-term. In the short term, it requires setting up an HTTP endpoint, which means that IIS and dependent services need to be installed and configured correctly. If you set up a website, you're going to want to use HTTPS and SSL certificates. Depending on the location from which you get your SSL certificate, this might add extra work for you to procure and deploy (we will cover these steps in a moment). While it may require more initial effort, an HTTPS endpoint is easier to access. There's no dependency on permission rules or AD forests. In complicated network environments, getting one port allowed on multiple firewalls is much easier than allowing the SMB traffic through.

Considerations like these largely depend on your environment, so evaluate your options carefully before proceeding.

The Windows Management Framework version

It was very hard to decide how to lay out this chapter due to the new features that have been introduced as DSC has matured. We could have simply listed steps performed in WMF 4, then WMF 5, and then summarized your tasks. This approach is hard to read because the information is separated but sometimes repeated, but it is easy to refer back to. We have chosen instead to list the steps performed to install a DSC Pull Server no matter the WMF version, flagging special cases or notes for each version. This approach was chosen because as time moves on, you will refer back to this book by feature or wondering "how do I do this again?" instead of looking for a specific version number.

For that reason, we will go through all the considerations regarding the WMF versions inside each section in this chapter instead of trying to list them here. There are too many that require extra explanation or context-specific information to make the choice of separating them here.

Initial setup tasks

Before we can actually install the DSC Pull Server, there are some setup tasks you have to perform. These tasks only have to be performed by you (whether manually or through a script) for the first DSC Pull Server you deploy, and they can be added to your DSC deployments as time goes on. Again, we reference the chicken-and-egg problem; naturally, some of this requires us to do a little work until we have something set up to do the work for us.

Installing required DSC Resources

Whether you are compiling your DSC configuration to an MOF file on your desktop or on the DSC Pull Server itself, you need to have the xPSDesiredStateConfiguration module that contains the xDscWebService DSC Resource in PSModulePath. How you get this module onto your system depends largely on your WMF version.

If you are using WMF 4, you have to download xPSDesiredStateConfiguration from GitHub. Remember that the TechNet Script Center contains out-of-date versions of all the Resource Kit DSC Resources. You can either clone xPSDesiredStateConfiguration directly from GitHub using git or download it in a ZIP file from the GitHub website, as shown:

Installing required DSC Resources

Tip

For more information on the sources of DSC Resources, see Chapter 4, DSC Resources.

If you are using WMF 5, you can use the built-in PackageManagement Cmdlets to download and install the DSC Resource to the correct place automatically:

Install-Package -Name 'xPSDesiredStateConfiguration' -RequiredVersion 3.4.0.0 -Force -ForceBootStrap

We specified ForceBootStrap to instruct Install-Package to install the underlying nuget.exe binaries if they are not present. Notice also that we specified the version in the code example. We did this to show what version we were working with when the book was written so that you know which version to use when running examples. You may use a newer version in production than the one specified here, as it is bound to change as time moves on.

In our downloadable example code, we also download and install the xWebAdministration DSC Resource as we use this in our example DSC configuration that we will be pushing to the target nodes:

Install-Package -Name 'xWebAdministration' -RequiredVersion 1.7.0.0 -Force -ForceBootStrap

Even though we downloaded xWebAdministration using PackageManagement, we also manually download it to our working directory so that we can package it up for the DSC Pull Server to distribute it to our target nodes. We do this because the folder structure downloaded by Install-Module supports the side-by-side installation mechanics in WMF 5, which means it contains a subfolder named with the version number:

[PS]> ls $env:ProgramFilesWindowsPowerShellModulesxWebAdministration

    Directory: C:Program FilesWindowsPowerShellModulesxWebAdministration

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        9/17/2015   1:49 PM                1.7.0.0

[PS]> ls $env:ProgramFilesWindowsPowerShellModulesxWebAdministration1.7.0.0

    Directory: C:Program FilesWindowsPowerShellModulesxWebAdministration1.7.0.0

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        9/17/2015   1:49 PM                DSCResources
-a----        9/17/2015   1:49 PM           1473 xWebAdministration.psd1

We can't use that in the Preparing DSC Resources for Pull Server distribution section, so we use the original folder structure.

[PS]> ls c:vagrantxWebAdministration

    Directory: c:vagrantxWebAdministration

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        9/17/2015   1:49 PM                DSCResources
-a----        9/17/2015   1:49 PM           1473 xWebAdministration.psd1

SSL certificates

When installing an HTTPS DSC Pull Server, you will need to have an SSL certificate. You can use any valid non-expired SSL certificate that is trusted by the server you are installing the DSC Pull Server on and any target nodes that will communicate with it. It can be a self-signed certificate, an AD domain certificate, or an online registrar certificate. The only limitation is that it must be trusted on each target node and Pull Server you deploy.

Tip

If you chose to use an SMB Pull Server, then you might think you can skip this step. However, you can only skip using SSL certificates if you do not use SSL to encrypt any credentials you might have used inside your DSC configuration blocks.

We will be using a self-signed certificate in the following examples, so we need to create an SSL certificate and install it on both the DSC Pull Server and the target nodes. The following code uses the built-in PowerShell Cmdlets on Windows 2012 R2 to create a self-signed SSL certificate and install it into both the Root and my trusted LocalMachine cert stores. It also exports the certificate to a file so it can be copied to and installed on the target nodes:

$CertPath = 'C:vagrantservercert.cer'
$cert = Get-ChildItem -Path Cert:LocalMachineMy | ? { $_.Subject -eq 'CN=dsc-box1' }
if($cert.Count -eq 0){
  $cert = New-SelfSignedCertificate -DnsName 'dsc-box1' -CertStoreLocation cert:LocalMachineMy
}
Export-Certificate -Cert "Cert:LocalMachineMy$($cert.ThumbPrint)" -FilePath $CertPath
Import-Certificate -FilePath $CertPath -CertStoreLocation Cert:LocalMachineRoot

It is advisable to provide a resolvable name for the DnsName parameter to create the self-signed certificate. The next step is to install the self-signed certificate on our target node. In our downloadable code examples, we use a common shared folder and PowerShell Remoting to install the certificate, but feel free to use whichever method suits your environment.

Import-Certificate -FilePath "C:vagrantservercert.cer" -CertStoreLocation Cert:LocalMachineRoot

Tip

We are only using self-signed certificates here because we are using local test machines not joined to an AD domain. Self-signed certificates are harder to use than AD domain certificates; they are somewhat less secure and require you to install them on all machines in order for them to work. In your production environment, you will most likely use an AD domain certificate or other SSL certificate from a trusted vendor that all of your target nodes trust. Setting up an AD domain certificate infrastructure is outside the scope of this book, but you use the certificates generated from those methods in exactly the same way as a self-signed certificate.

If you are having trouble creating the certificate using the previous code, or can't use the built-in PowerShell Cmdlets, a good place to start for more information is https://msdn.microsoft.com/en-us/library/bfsktky3(v=vs.110).aspx.

SMB share creation

You can create SMB shares for use with DSC Pull Servers either inside the DSC configuration script using the xSMBShare DSC Resource, ahead of time using native Windows tooling or PowerShell Cmdlets, or with existing SMB shares that you already have.

Tip

If you choose to use an HTTPS DSC Pull Server, you can skip this step.

Documentation for the SMB share permissions is patchy, and there doesn't seem to be an official Microsoft documentation page for them. We have successfully run configurations by setting the share permissions to allow the "Domain Computers" group read access to the share in Active Directory domain environments.

Preparing DSC Resources for Pull Server distribution

We covered preparing DSC Resources for DSC Pull Server deployment briefly in Chapter 2, DSC Architecture. To review what we have learned, here are the steps:

  1. Compress the DSC Resource module to a single archive file.
  2. Version the name of the archive file.
  3. Copy the archive file to the DSC Pull Server.
  4. Create a checksum file for the archive file.

By compressing the DSC Resource module folders into archive files, we save space on the DSC Pull Server and save time and bandwidth in transmitting them to the target nodes. We version the file names so that DSC can determine which DSC Resource to use for a given target node. This allows many different versions of the same DSC Resource to exist on the DSC Pull Server and handle the potentially many versions that are deployed in different DSC configuration scripts.

The manual actions we covered to accomplish the above steps in Chapter 2, DSC Architecture are fine if we do this infrequently, but since this is something we will be performing every time there is a new version of a DSC Resource or we use a new DSC Resource altogether, these actions should be automated to reduce errors and increase our deployment speed.

As we mentioned in Chapter 2, DSC Architecture, there are no built-in compression Cmdlets in PowerShell v4 and we can't make the archive files using the .NET compression classes because they do not set the byte header that DSC expects. An example bug report that is currently open can be found here: https://connect.microsoft.com/PowerShell/feedback/details/804230/lcm-fails-to-extract-module-zipped-with-system-io-compression-zipfile, but we know this has been solved in PowerShell v5. To work around this, we could write our own code to use the Shell.Application COM object interface in PowerShell v4. In PowerShell v5, we can use the built-in compression Cmdlet Compress-Archive to accomplish the same task.

Tip

Note that while we use Shell.Application here to automate the creating of the archive file, there is some danger in using this API. Shell.Application is an asynchronous API, which means it does not block our session from continuing while it works. We work around this by using the Start-Sleep Cmdlet to wait for Shell.Applicaiton to finish. However, if we do not wait long enough, we could continue working when Shell.Application has not finished yet and corrupt the archive file. There is a relatively small chance of this happening as we are dealing with small folder sizes, but the chance is still there. If you are concerned enough, you can replace the custom Shell.Applicaiton code with an archive library of your choice, like 7zip.

Included here and in the downloadable code is a function called New-DscResourceArchive that correctly creates DSC Resource archive files on either PowerShell v4 or PowerShell v5. It determines the version of the DSC Resource, correctly formats the file name, and compresses the directory. It then creates a checksum file in the same directory as the archive file:

function New-DscResourceArchive
{
  [CmdletBinding()]
  param(
    [string]$ModulePath,
    [string]$DestinationPath,
    [Switch]$Force
  )

  $Version     = Get-DscResourceModuleVersion -ModulePath $ModulePath
  $folderName  = $DestinationPath + "_" + $Version
  $archiveName = $executionContext.SessionState
                    .Path
                    .GetUnresolvedProviderPathFromPSPath("$folderName.zip")

  if(Test-Path $archiveName){
    if($Force){
      Remove-Item $archiveName -Force
    }
    else{
      throw "Item with specified name $archiveName already exists."
    }
  }

  if($PSVersionTable.PSVersion.Major -eq 4){
    New-ZipFile -Path $ModulePath -DestinationPath $archiveName
    New-DSCCheckSum -Path $archiveName -OutPath (Split-Path -Path $DestinationPath -Parent)
  }else{
    Compress-Archive -Path $ModulePath -DestinationPath $archiveName
  }
}

function Get-DscResourceModuleVersion
{
  [CmdletBinding()]
  param($ModulePath)

  $moduleName = Split-Path -Path $modulePath -Leaf
  Write-Verbose $ModulePath
  Write-Verbose $moduleName
  $manifest   = Get-ChildItem -Path $modulePath -Filter "$moduleName.psd1" -Recurse | Select-Object -First 1
  Write-Verbose $manifest.FullName
  if(-not (Test-Path $manifest.FullName)){
    throw "Could not find manifest.FullName in $modulePath"
  }

  $text    = Get-Content -Path $manifest.FullName -Raw
  $version = (Invoke-Expression -Command $text)['ModuleVersion']
  return $version
}

function New-ZipFile
{
  [CmdletBinding()]
  param($Path, $DestinationPath)

  [byte[]]$zipHeader = 0x50,0x4B,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  try{
    $stream = New-Object System.IO.FileStream $DestinationPath, "Create"
    $com    = New-Object -ComObject "Shell.Application"
    $zip    = $com.namespace($DestinationPath)

    $stream.Write($zipheader, 0, 22)
    $stream.Close();
    Start-Sleep -Seconds 1

    $zip.CopyHere($Path)
    Start-Sleep -Seconds 5
  }
  finally{
    $com = $null
    $zip = $null
  }

  Write-Verbose "Created $DestinationPath"
}

It uses a function called New-ZipFile that uses standard COM objects to write data to a ZIP file for PowerShell 4 that you can find in any search online; the only thing special about it is that it writes the correct byte header to the ZIP file that DSC expects. Since this is fixed in PowerShell v5, don't get too hung up about having to have special archive creation functions; you can remove it as you upgrade:

[PS]> New-DscResourceArchive -Path "$env:ProgramFilesWindowsPowerShellModulesxPSDesiredStateConfiguration" -DestinationPath "$HomedesktopxPSDesiredStateConfiguration" -Force
[PS]> ls $homedesktop

    Directory: C:Usersjamesdesktop

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         9/7/2015   1:17 PM         122003 xPSDesiredStateConfiguration_3.4.0.0.zip
-a----         9/7/2015   1:17 PM             64 xPSDesiredStateConfiguration_3.4.0.0.zip.checksum

Tip

When running the New-DscResourceArchive function, be sure to provide a DestinationPath that exists for you. Here we use $homedesktop, which is most likely not available in some AD domain environments.

In our downloadable code, we use this function to package all the DSC Resource modules we want to include in our distribution, like so:

. c:vagrantookch06dsctooling.ps1
if(-not(Test-Path 'c:modules')){ mkdir 'c:modules' }
$modules = @('xWebAdministration','xPSDesiredStateConfiguration')
$modules | % {
  New-DscResourceArchive -ModulePath (Join-Path 'C:vagrant' $_) -Destinationpath (Join-Path 'c:modules' $_) -Force
}
New-DscChecksum -Path 'c:modules'

Miscellaneous tasks

You may be required to perform additional tasks in order for your DSC Pull Server to function. In your production environment, you will most likely add firewall port accept rules for the ports you choose to run the DSC Pull Server on and have DNS set up in your environment. Please read through our instructions below to decide if there are more steps for your particular environment.

In our downloadable code example, we disable the firewall to allow network communication on the HTTP ports we use and add IP addresses to the hosts file to allow name resolution between the two hosts. This is entirely because we are using a non-domain joined workgroup test machine, so name resolution is not available and we don't need to worry about blocking ports.

Creating a WMF 4 DSC Pull Server

We said in the beginning of this chapter that for a large part of the install, you will be doing most of the work to install a DSC Pull Server yourself. While this is true, it doesn't mean you can't script most of the tasks. We are going to use the approach of putting all the steps in individual scripts and then wrapping them all in a "root" invocation script. We do this since this is a test environment and we will be generating SSL certs and DSC Pull Server endpoint URLs on demand, in comparison to a production environment where you will have a known SSL certificate and endpoint URL to deal with. We will start by addressing each step in the process and then showing the completed "root" script. This will make more sense as we move on, so bear with us.

We are going to follow the same DSC configuration script we used in Chapter 2, DSC Architecture, to set up our WMF 4 DSC Pull Server, with the addition of ensuring that HTTPS and SSL are set up and configured. Note that we have to place the certificate thumbprint in the appropriate property for the PullServer endpoint. This will set up the IIS websites with the correct SSL cert. Another decision in WMF 4 that we have to make is where to keep the DSC Resources and where to store the DSC service configuration. For the most part, you will follow the standard locations (as we do next), unless you have customized drive and partition setups. The final choice you have to make is what port to host these endpoints on. We have used the default suggested ports here, but you can choose which ones to use in your environment. This is especially helpful if there are other services running on the server you decide to install the DSC Pull Server on.

The result of these decisions is the following DSC configuration script:

Configuration WMF4PullServer
{
  Import-DSCResource -ModuleName xPSDesiredStateConfiguration

  Node $AllNodes.Where({ $_.Roles -contains 'PullServer'}).NodeName
  {
    WindowsFeature DSCServiceFeature
    {
      Ensure = 'Present'
      Name   = 'DSC-Service'
    }

    xDscWebService PSDSCPullServer
    {
      Ensure                       = "Present"
      EndpointName                 = $Node.PullServerEndpointName
      Port                         = $Node.PullServerPort
      PhysicalPath                 = $Node.PullServerPhysicalPath
      CertificateThumbPrint        = $Node.CertificateThumbPrint
      ModulePath                   = $Node.ModulePath
      ConfigurationPath            = $Node.ConfigurationPath
      AcceptSelfSignedCertificates = $true
      State                        = "Started"
      DependsOn                    = @("[WindowsFeature]DSCServiceFeature")
    }

    xDscWebService PSDSCComplianceServer
    {
      Ensure                = "Present"
      EndpointName          = $Node.ComplianceServerEndpointName
      Port                  = $Node.ComplianceServerPort
      PhysicalPath          = $Node.CompliancePhysicalPath
      CertificateThumbPrint = "AllowUnencryptedTraffic"
      IsComplianceServer    = $true
      State                 = "Started"
      DependsOn             = @("[WindowsFeature]DSCServiceFeature")
    }

    File CopyPackagedModules
    {
      Ensure          = "Present"
      Type            = "Directory"
      SourcePath      = $Node.PackagedModulePath
      DestinationPath = $Node.ModulePath
      Recurse         = $true
      DependsOn       = "[xDscWebService]PSDSCPullServer"
    }
  }
}

All of this looks remarkably similar to any DSC configuration script we have done so far. As we keep seeing with DSC, this is explicitly on purpose. These standard ways of expressing the state of a target node allow you to apply the knowledge you gained from deploying one piece of software or system to any piece of software or system. One thing to note is that we copy the archived DSC Resources as we did in the initial steps at the beginning of this chapter from a deployment directory to the DSC Pull Server module directory. You can include this step to keep your DSC Pull Server distribution up-to-date with new module versions.

Keeping with the theme of separating our configuration data from our execution script, we have saved the configuration data in a separate file, but we haven't made it a .psd1 file. We used this approach because we did not know the certificate thumbprint that would be generated using the scripts we are about to show. These compile the DSC configuration previous script up, so we make it a .ps1 file in order that we can execute some code to get the certificate thumbprint:

 $cert = Get-ChildItem -Path Cert:LocalMachineRoot | ? { $_.Subject -eq 'CN=dsc-box1' }
$configData = @{
  AllNodes = @(
    @{
      NodeName               = "*"
      PackagedModulePath     = 'c:Modules'
      ConfigurationServerURL = "https://dsc-box1:8080/PSDSCPullServer.svc"
      ComplianceServerURL    = "http://dsc-box1:9080/PSDSCComplianceServer.svc"
      CertificateID          = "$($cert.ThumbPrint)"
      RefreshMode            = "PULL"
      ConfigurationMode      = "ApplyAndAutocorrect"
      AllowModuleOverwrite   = $true
      RebootNodeIfNeeded     = $true
    },
    @{
      NodeName                     = 'dsc-box1'
      Roles                        = @('PullServer')
      AcceptSelfSignedCertificates = $true
      CertificateThumbPrint        = "$($cert.ThumbPrint)"
      ModulePath                   = "$env:PROGRAMFILESWindowsPowerShellDscServiceModules"
      ConfigurationPath            = "$env:PROGRAMFILESWindowsPowerShellDscServiceConfiguration"
      PullServerEndpointName       = 'PSDSCPullServer'
      PullServerPhysicalPath       = "$env:SystemDriveinetpubPSDSCPullServer"
      PullServerPort               = 8080
      ComplianceServerEndpointName = 'PSDSCComplianceServer'
      CompliancePhysicalPath       = "$env:SystemDriveinetpubPSDSCComplianceServer"
      ComplianceServerPort         = 9080
    },
    @{
      NodeName        = 'dsc-box2'
      Roles           = @('Target')
      ConfigurationId = 'c19fbe22-b664-4a8a-a2a1-477f16ce9659'
      WebSiteFolder   = 'C:	estsite'
      IndexFile       = 'C:	estsiteindex.html'
      WebSiteName     = 'TestSite'
      WebContentText  = '<h1>Hello World</h1>'
      WebProtocol     = 'HTTP'
      Port            = '80'
    }
  );
}
return $configData

You might not use this approach in your production environment as the certificate thumbprint and other details will be determined beforehand and not generated at runtime like this. You could choose to use this approach in production for a fully automated script if you have to make several decisions on what data to generate for each of your DSC Pull Servers.

Since we are setting up the DSC Pull Server, we can't expect to have it pull the DSC configuration, so we will push it using the knowledge we gained from Chapter 5, Pushing DSC Configurations. We are running it locally on the DSC Pull Server, but as we saw in the last chapter, you can push DSC configurations remotely, so this will work as well remotely as it does here locally:

$dataScript = ([IO.Path]::Combine($PSScriptRoot, 'wmf4_config_data.ps1'))
$configData = &$dataScript

c:vagrantookch06wmf4_pull_server.ps1 -OutputPath ([IO.Path]::Combine($PSScriptRoot, 'WMF4PullServer')) -ConfigData $configData

Start-DscConfiguration -Path ([IO.Path]::Combine($PSScriptRoot, 'WMF4PullServer')) -Wait -Verbose -Force

We used this approach so that we invoke code to find the thumbprint at runtime to compile the MOF file and install the DSC Pull Server. The preceding code finds the configuration data script and executes it to return the configuration data hash we need to compile the MOF in the wmf4_pull_server.ps1 script. It then installs the DSC Pull Server using Start-DscConfiguration:

[PS]> C:vagrantookch06wmf4_02_install_pull_server.ps1

    Directory: C:vagrantookch06WMF4PullServer

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-----         9/19/2015   9:24 AM       4918 dsc-box1.mof
VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' =
SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' =
root/Microsoft/Windows/DesiredStateConfiguration'.
VERBOSE: An LCM method call arrived from computer DSC-BOX1 with user sid
S-1-5-21-2584411961-1507261911-1533134791-1001.
VERBOSE: [DSC-BOX1]: LCM:  [ Start  Set      ]
VERBOSE: [DSC-BOX1]: LCM:  [ Start  Resource ]  [[WindowsFeature]DSCServiceFeature]
VERBOSE: [DSC-BOX1]: LCM:  [ Start  Test     ]  [[WindowsFeature]DSCServiceFeature]
VERBOSE: [DSC-BOX1]:                            [[WindowsFeature]
<# ... #>
VERBOSE: [DSC-BOX1]:                            [[File]CopyPackagedModules] Copying file
c:ModulesxWebAdministration_1.7.0.0.zip to C:Program
FilesWindowsPowerShellDscServiceModulesxWebAdministration_1.7.0.0.zip.
VERBOSE: [DSC-BOX1]:                            [[File]CopyPackagedModules] Copying file
c:ModulesxWebAdministration_1.7.0.0.zip.checksum to C:Program
FilesWindowsPowerShellDscServiceModulesxWebAdministration_1.7.0.0.zip.checksum.
VERBOSE: [DSC-BOX1]: LCM:  [ End    Set      ]  [[File]CopyPackagedModules]  in 0.0160 seconds.
VERBOSE: [DSC-BOX1]: LCM:  [ End    Resource ]  [[File]CopyPackagedModules]
VERBOSE: [DSC-BOX1]: LCM:  [ End    Set      ]    in  1.2105 seconds.
VERBOSE: Operation 'Invoke CimMethod' complete.
VERBOSE: Time taken for configuration job to complete is 1.208 seconds

Creating a WMF 5 DSC Pull Server

Installing and configuring a WMF 5 DSC Pull Server is much the same as a WMF 4 DSC Pull Server, with one major exception: the registration key feature. In WMF 5, the PowerShell team has added the ability to register a target node using pre-shared unique keys called RegistrationKeys that are easier to track than the ConfigurationId GUID concept in WMF 4. We will go into further detail about registration keys in the DSC configuration example section next.

Tip

We will review what RegistrationKeys refers to and how it's used in the Registering a node with a WMF 5 DSC Pull Server section later on.

You can choose to continue using ConfigurationIds for registering your target nodes in WMF 5. If you choose to do so, you can reuse the WMF 4 DSC configuration script without modification in WMF 5. If you choose to use the RegistrationKeys feature, you will modify your DSC configuration script as follows:

Configuration WMF5PullServer
{
  Import-DSCResource -ModuleName xPSDesiredStateConfiguration

  Node $AllNodes.Where({ $_.Roles -contains 'PullServer'}).NodeName
  {
    WindowsFeature DSCServiceFeature
    {
      Ensure = 'Present'
      Name   = 'DSC-Service'
    }

    File RegistrationKeyFile
    {
      Ensure          = 'Present'
      DestinationPath = (Join-Path $Node.RegistrationKeyPath $Node.RegistrationKeyFile)
      Contents        = $Node.RegistrationKey
      DependsOn       = @("[WindowsFeature]DSCServiceFeature")
    }

    xDscWebService PSDSCPullServer
    {
      Ensure                       = "Present"
      EndpointName                 = $Node.PullServerEndpointName
      Port                         = $Node.PullServerPort
      PhysicalPath                 = $Node.PullServerPhysicalPath
      CertificateThumbPrint        = $Node.CertificateThumbPrint
      ModulePath                   = $Node.ModulePath
      ConfigurationPath            = $Node.ConfigurationPath
      RegistrationKeyPath          = $Node.RegistrationKeyPath
      AcceptSelfSignedCertificates = $true
      State                        = "Started"
      DependsOn                    = @("[WindowsFeature]DSCServiceFeature","[File]RegistrationKeyFile")
    }

    xDscWebService PSDSCComplianceServer
    {
      Ensure                = "Present"
      EndpointName          = $Node.ComplianceServerEndpointName
      Port                  = $Node.ComplianceServerPort
      PhysicalPath          = $Node.CompliancePhysicalPath
      CertificateThumbPrint = "AllowUnencryptedTraffic"
      IsComplianceServer    = $true
      State                 = "Started"
      DependsOn             = @("[WindowsFeature]DSCServiceFeature")
    }

    File CopyPackagedModules
    {
      Ensure          = "Present"
      Type            = "Directory"
      SourcePath      = $Node.PackagedModulePath
      DestinationPath = $Node.ModulePath
      Recurse         = $true
      DependsOn       = "[xDscWebService]PSDSCPullServer"
    }
  }
}

We have added a file DSC Resource statement for creating the RegistrationKey file and populating it with RegistrationKey we have chosen, and we've also added RegistrationKeyPath to the Pull Server xDscWebService DSC Resource statement.

We update our DSC configuration data script with the following data. Again, we are using this approach to get the current certificate thumbprint in our test environment:

$cert = Get-ChildItem -Path Cert:LocalMachineRoot | ? { $_.Subject -eq 'CN=dsc-box1' }
$configData = @{
  AllNodes = @(
    @{
      NodeName               = "*"
      RegistrationKey        = 'c4729623-1eb7-408a-b3f4-fbddcc63e703'
      PackagedModulePath     = 'c:Modules'
      ConfigurationServerURL = "https://dsc-box1:8080/PSDSCPullServer.svc"
      ComplianceServerURL    = "http://dsc-box1:9080/PSDSCComplianceServer.svc"
      CertificateID          = "$($cert.ThumbPrint)"
      RefreshMode            = "PULL"
      ConfigurationMode      = "ApplyAndAutocorrect"
      AllowModuleOverwrite   = $true
      RebootNodeIfNeeded     = $true
    },
    @{
      NodeName                     = 'dsc-box1'
      Roles                        = @('PullServer')
      AcceptSelfSignedCertificates = $true
      CertificateThumbPrint        = "$($cert.ThumbPrint)"
      RegistrationKeyFile          = 'RegistrationKeys.txt'
      RegistrationKeyPath          = "$env:PROGRAMFILESWindowsPowerShellDscService"
      ModulePath                   = "$env:PROGRAMFILESWindowsPowerShellDscServiceModules"
      ConfigurationPath            = "$env:PROGRAMFILESWindowsPowerShellDscServiceConfiguration"
      PullServerEndpointName       = 'PSDSCPullServer'
      PullServerPhysicalPath       = "$env:SystemDriveinetpubPSDSCPullServer"
      PullServerPort               = 8080
      ComplianceServerEndpointName = 'PSDSCComplianceServer'
      CompliancePhysicalPath       = "$env:SystemDriveinetpubPSDSCComplianceServer"
      ComplianceServerPort         = 9080
    },
    @{
      NodeName        = 'dsc-box2'
      Roles           = @('Target')
      ConfigurationId = 'c19fbe22-b664-4a8a-a2a1-477f16ce9659'
      WebSiteFolder   = 'C:	estsite'
      IndexFile       = 'C:	estsiteindex.html'
      WebSiteName     = 'TestSite'
      WebContentText  = '<h1>Hello World</h1>'
      WebProtocol     = 'HTTP'
      Port            = '80'
    }
  );
}
return $configData

We use the same approach as used in the WMF 4 example to install the WMF 5 DSC Pull Server. All you have to do is change the file names, and you are good to go. The script has some hardcoded values, looks a little clunky, and is very repetitious, but remember that this is only needed to get the first DSC Pull Server installed. Once the DSC Pull Server is up and running, installing other DSC Pull Servers or maintaining the configuration of the existing one is easy using DSC:

$dataScript = ([IO.Path]::Combine($PSScriptRoot, 'wmf5_config_data.ps1'))
$configData = &$dataScript

c:vagrantookch06wmf5_pull_server.ps1 -OutputPath ([IO.Path]::Combine($PSScriptRoot, 'WMF5PullServer')) -ConfigData $configData

Start-DscConfiguration -Path ([IO.Path]::Combine($PSScriptRoot, 'WMF5PullServer')) -Wait -Verbose -Force

Executing it shows similar output to the WMF 4 install:

[PS]> C:vagrantookch06wmf5_02_install_pull_server.ps1

    Directory: C:vagrantookch06WMF5PullServer

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
------        9/19/2015   7:57 AM           7276 dsc-box1.mof
VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' =
SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' =
root/Microsoft/Windows/DesiredStateConfiguration'.
VERBOSE: An LCM method call arrived from computer DSC-BOX1 with user sid
S-1-5-21-2584411961-1507261911-1533134791-1001.
VERBOSE: [DSC-BOX1]: LCM:  [ Start  Set      ]
<#  ... #>
VERBOSE: [DSC-BOX1]: LCM:  [ End    Set      ]  [[File]CopyPackagedModules]  in 0.0000 seconds.
VERBOSE: [DSC-BOX1]: LCM:  [ End    Resource ]  [[File]CopyPackagedModules]
VERBOSE: [DSC-BOX1]: LCM:  [ End    Set      ]
VERBOSE: [DSC-BOX1]: LCM:  [ End    Set      ]    in  50.6250 seconds.
VERBOSE: Operation 'Invoke CimMethod' complete.
VERBOSE: Time taken for configuration job to complete is 51.139 seconds
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset