Local Configuration Manager

The Local Configuration Manager, or LCM, is the “client agent” for DSC. It runs on each target node, accepts configurations (via either pull or push), and executes those configurations. You can’t schedule when the LCM will run, but you can schedule some parameters related to how often it runs. That’s what this chapter is all about, along with the LCM’s other configuration options.

Checking the Configuration

Run Get-DscLocalConfigurationManager to see the current configuration. Here’s a default Windows 10 computer:

PS C:\> Get-DscLocalConfigurationManager                                                                

ActionAfterReboot              : ContinueConfiguration
AgentId                        : 9BE13016-41FD-11EA-8F88-38F9D3507320
AllowModuleOverWrite           : True
CertificateID                  :
ConfigurationDownloadManagers  : {[ConfigurationRepositoryWeb]AWS}
ConfigurationID                :
ConfigurationMode              : ApplyAndAutoCorrect
ConfigurationModeFrequencyMins : 60
Credential                     :
DebugMode                      : {NONE}
DownloadManagerCustomData      :
DownloadManagerName            :
LCMCompatibleVersions          : {1.0, 2.0}
LCMState                       : PendingConfiguration
LCMStateDetail                 :
LCMVersion                     : 2.0
StatusRetentionTimeInDays      : 10
SignatureValidationPolicy      : NONE
SignatureValidations           : {}
MaximumDownloadSizeMB          : 500
PartialConfigurations          :
RebootNodeIfNeeded             : False
RefreshFrequencyMins           : 240
RefreshMode                    : Pull
ReportManagers                 : {[ReportServerWeb]ComplianceServer}
ResourceModuleManagers         : {}
PSComputerName                 :

Let’s walk through each of those. But, before we do that, we have to point out that this set of configuration properties is from a Windows computer.


This determines what the LCM will do after the computer is rebooted. The default, ContinueConfiguration, will let the LCM pick up where it left off and continue processing the current configuration. You can also choose StopConfiguration, which, as the name implies, stops the configuration from running further. I imagine you’d really only use StopConfiguration in certain troubleshooting or lab situations.


When set to $False - which is the default - the LCM will not download any DSC resource modules that already exist locally. It’s for safety. The presumption is that, once you put a resource onto a node, the node depends on that exact resource in order to run configurations properly. If you change or update a resource, you’re meant to apply a new version to it. Your configurations can then reference that new version, and if properly configured, the LCM will download that new version. This AllowModuleOverwrite setting only applies to downloading new copies of the exact same module. In a test environment, where you’re frequently iterating modules, you’ll probably set this to $True.

Why would you not set this to $True in production? Well… predictability and stability. If an LCM is allowed to overwrite local modules, that can be convenient for you when making ad-hoc changes. But that subverts the entire best practice of code testing, versioning, and so on. Ideally, if Configuration A relies on Module B version 1.2, you don’t want Module B version 1.3 showing up out of the blue. It might not work the way Configuration A expects - for example, Module B version 1.3 might require different properties or property values, which Configuration A doesn’t provide. The correct practice would be to deploy Module B v1.3 as a separate thing, living independently of, and side-by-side with, v1.2. You would then author Configuration C, which specifically references Module B v1.3, and deploy Configuration C to your nodes. That way you always know what each node is using, and troubleshooting becomes a lot easier.


This is the certificate thumbprint (which you can obtain by exploring the CERT: drive) of the encryption certificate that the LCM will use to decrypt any encrypted information from its MOF. Most commonly, this is used to decrypt encrypted logon credentials. We’ll cover certificates pretty thoroughly in an upcoming chapter.


This is a collection of pull servers - that is, servers from which MOF files will be pulled.


This is a Globally Unique Identifier (GUID) that you assign to the LCM. In WMF v4, this was the only way to tell the LCM which MOF to pull from a pull server. In WMF v5, you can also use configuration names. However, when using ConfigurationID, the node will essentially look on the pull server for a MOF file whose filename is the same GUID. Note that a GUID isn’t just a random string of hexadecimal characters; it’s a specific thing that must be generated. In PowerShell, you can use [guid]::newGuid() to generate one. This is really important: If you specify a ConfigurationID, you can run against a v4 or v5 pull server, and the v5 pull server will follow v4 behaviors. If you omit the ConfigurationID, whether you include Configuration Names or not, the pull server must be v5 or later, will behave as v5 or later, and requires a registration key to be specified in a Repository section.


This controls the LCM’s actions. The following values are allowed:

  • Disabled. The LCM does not run. This is perhaps most often used in cases where a third-party management technology, like Chef, is actually running the show. Chef can use DSC resource modules under the hood, but it doesn’t want the actual LCM stepping in and interfering.
  • ApplyOnly. The LCM applies the current configuration, and then stops running until manually run.
  • ApplyAndMonitor. The LCM applies the current configuration, and re-checks it on the ConfigurationModeFrequencyMinutes value. It does not attempt to fix the configuration, but will report a status to a Reporting Server if so configured.
  • ApplyAndAutoCorrect. The LCM applies the current configuration, and re-checks it on the ConfigurationModeFrequencyMinutes value. It will attempt to fix out-of-compliance configuration settings and, if configured, will report status to a Reporting Server.


This controls how often the LCM will re-evaluate its current configuration. It defaults to, and has a minimum value of, 15 minutes. This is important, conceptually, because it means the LCM cannot guarantee continuous compliance with your desired configuration. If someone changes something, that change can “last” for 15+ minutes until the next consistency check. So in cases where the “desired configuration” could mean the difference between literal life or death, or someone going to jail or not, DSC might not be the right technology. In many cases, you could extend this to 24 hours or more (calculated in minutes) for cases when you simply need a once-a-day check on configuration compliance.


This appears to be obsolete, since the individual resource blocks (which we’ll get into in a bit) can define this on a per-instance basis.


Whether or not the LCM’s debug mode is on or off ($True or $False).


This appears to be obsolete in v5.


This appears to be obsolete in v5.


The LCM versions that this LCM is compatible with. For example, LCM 2.0, which ships in WMF v5, is compatible with LCM 1.0, meaning it can accept the same configuration documents that the older LCM accepted, in addition to newer, 2.0-only ones.


This tells you what the LCM is currently up to:

  • Idle
  • Busy
  • PendingReboot
  • PendingConfiguration


This is usually a more descriptive version of what the LCM is doing right then, like “LCM is applying a new configuration.”


The version of the LCM.


This controls how long the LCM will retain current status information. The default is 10 days.


This doesn’t presently do anything.


When set to $True, the LCM will automatically restart the target node if a DSC resource indicates that a restart is required to finalize the configuration. This is set to $False by default, on the very reasonable grounds that most people want a little more control over when their servers restart.


This controls how often the LCM will check the pull server for new MOFs. It defaults to 30 minutes, and in WMF v4 must be set to an even multiple of the ConfigurationModeFrequencyMinutes value (15 * 2 = 30, hence the default of 30). This value should always be larger than the ConfigurationModeFrequencyMinutes.


Push or Pull. As easy as that. This defaults to Push, meaning that the LCM just sits and waits for you to hit it up with a configuration.


This is a collection of configured reporting servers.


This is a collection of pull servers from which modules (DSC resources) can be downloaded.

Changing the Configuration

To change the configuration of an LCM, even the local one, you need a meta-MOF. This is a special MOF that you can create by writing a special PowerShell configuration script. Meta-MOFs are pushed to their nodes, using the Set-DscLocalConfigurationManager cmdlet (which uses CIM sessions for connectivity). A meta-MOF configuration script might look something like the following:

configuration LCMConfig
    Node Node1
            RefreshMode = 'Push'

In this case, the [DSCLocalConfigurationManager()] bit tells PowerShell that this is to be a meta-MOF, which is generated somewhat differently than a normal configuration MOF. The name of the configuration, LCMConfig, is arbitrary. You simply need to specify that name - usually at the very bottom of the script file - to run the config and generate the MOF (it’s basically like running a function). Within the Settings{} block is where you can put whatever settings you like from the list above.

Deploying the LCM Configuration

The file Node1.meta.mof will be created in a subfolder named LCMConfig. Once you’ve run that and generated a Node1.meta.mof, you can use Set-DscLocalConfigurationManager to “push” the meta-MOF to Node1.

Set-DscLocalConfigurationManager -Path ./LCMConfig -ComputerName Node1 -verbose

It’s also possible to “inject” the meta-MOF into a node by copying it into the place where the LCM looks for it (C:/Windows/System32/Configuration/metaconfig.mof). For example, this is a great way to help configure the LCM as part of an automated VM build, since you can use things like the Hyper-V integration cmdlets to copy files into the VM.

NOTE: I should point out that there can be a bunch of caveats around “injecting” a MOF by simply copying a file. I’ve found it’s nearly always better to push the meta-MOF to the LCM as part of an automated build process, or just to copy the meta-MOF to an arbitrary local file on the node and have the VM “push” that to itself. And keep in mind that you can also “sort of push” a meta-MOF into a VM node, even if WS-MAN isn’t enabled on the node, by using integration components like those provided by Hyper-V. If you want to read more on injection, though, have a look at http://dille.name/blog/2014/12/07/injecting-powershell-dsc-meta-and-node-configurations/ and https://blogs.msdn.microsoft.com/powershell/2014/02/28/want-to-automatically-configure-your-machines-using-dsc-at-initial-boot-up/, although those articles refer to WMF v4, so the actual examples are slightly outdated.

Specifying Configuration Pull Servers

The basic settings I covered above are only the beginning of what you’ll need to configure. One thing you’re probably going to want to do is configure one or more pull servers, from which the LCM will pull its configuration MOF (or MOFs, if you’re using partial configurations). So in addition to the Settings{} block in the meta-MOF, you can have one or more pull server sections.

configuration LCMConfig
    Node localhost
		Settings {
			RefreshMode = 'Pull'

		ConfigurationRepositoryWeb MainPull {
			AllowUnsecureConnection = $false
			ConfigurationNames = @('Server2Configuration')
			RegistrationKey = '140a952b-b9d6-406b-b416-e0f759c9c0e4'
			ServerURL = 'https://mypullserver.company.pri/PSDSCPullServer.svc'

		ConfigurationRepositoryShare FilePull {
			SourcePath = '\\organization\path\folder\'

The above example shows both a Web and a file share-based pull server configuration. You can mix and match; note that the file share-based version also allows a Credential property, where you can specify a credential to use to access the share (if you don’t, then the share must allow anonymous, un-authenticated access). Frankly, file share-based pull servers are rare in my experience, and they offer less functionality. I’ll assume you’re using a Web-based pull server, which means the pull server is running IIS, and you’ve installed the DSC Pull Server feature on the server (we’ll cover pull server setup in an upcoming chapter).

Also notice that each block has a name. This is arbitrary, and meaningful to me; DSC doesn’t care what you name them. I’ve used “MainPull” and “FilePull.”

Web pull servers support these properties:

  • AllowUnsecureConnection. This should always be $False, and is by default. This is a lot less about ensuring the connection is encrypted (although it also means that), and more about ensuring that the node is connecting to a known, trusted pull server. With this set to $True, it becomes very easy to use man-in-the-middle attacks to inject malicious configurations into your environment. When you wind up on CNN because you got p0wned by means of DSC, just remember that I Told You So, and stop using unsecure connections.
  • CertificateID. This is the GUID (thumbprint) of a local certificate, which the node will send to the pull server to authenticate the node to the server. This is a great way to prevent unknown nodes from even trying to contact your pull server. This is nothing fancier than good old IIS certificate-based authentication.
  • ConfigurationNames. When set, this means you should remove the ConfigurationID GUID from the Settings{} block, switching the node over to requesting one or more MOFs by filename. Notice this is specified as an array. When you use this, you must also specify the RegistrationKey. You must also use a pull server that has WMF v5. Finally, note that while ConfigurationNames accepts an array, it is illegal to specify more than one, unless you are specifying partial configurations (covered in a bit).
  • RegistrationKey. This is a GUID (use [guid]::newGuid() to generate it) that is configured in advance on the pull server. It acts as a kind of password for the node to “log in” and retrieve MOFs. The theory is that, when you just use a ConfigurationID (GUID), it’s really hard for a bad actor to guess at your MOF filenames. But when you start using ConfigurationNames, which are likely to be meaningful words and phrases, guessing filenames becomes easier. The RegistrationKey makes it harder for a bad guy to download your MOFs and inspect them (which would teach them a lot about your environment and facilitate an attack). Note that I’ve seen some documentation which suggests that you can remove RegistrationKey once the node is registered; in analyzing the code for the Linux LCM, and in speaking with some of the team, that’s not true. The RegistrationKey is used every time the node runs a consistency check and hits the Pull Server.
  • ServerURL. The URL of the pull server, which should start with https:// unless you’re okay being hacked. And yes, that means the IIS web site that the pull server is running under must have an SSL certificate that is issued by a root Certificate Authority that the node trusts. The URL must end in ‘PSDSCPullServer.svc’ if you’re using the Microsoft-supplied pull server service.
  • SignedItemType. New in WMF 5.1, this lets you tell the LCM to expect digital signatures from files delivered from the pull server or pushed to the LCM. This can be “Configuration”, “Module”, or both (e.g., “Configuration”,“Module”). See the chapter, “Security and DSC,” for information on digital signing for these items.
  • TrustedStorePath. New in WMF 5.1, this goes along with SignedItemType. This is optional; if you don’t include it, the LCM will use its normal certificate trust procedures to verify signed items. However, if you provide this (e.g., CERT:/LocalMachine/DSCStore), then the LCM will use that path to retrieve trusted publishers. This is an excellent idea, because you can restrict the CAs that are trusted to only those you control.

Notice that only SMB (file share) pull servers support a credential; Web pull servers do not. But Web pull servers support configuration names, certificate authentication, encryption, and lots more. They are Better In Every Way.

Specifying DSC Resource Pull Servers

Even when configured in Push mode, a node can be configured to download DSC resource modules from a pull server. This relieves you of the burden of manually deploying resource modules. You do not need to set up a unique pull server for this purpose; whatever pull server you’ve already got will do fine.

configuration LCMConfig
    Node localhost
		Settings {
			RefreshMode = 'Pull'

		ConfigurationRepositoryWeb MainPull {
			AllowUnsecureConnection = $false
			ConfigurationNames = @('Server2Configuration')
			RegistrationKey = '140a952b-b9d6-406b-b416-e0f759c9c0e4'
			ServerURL = 'https://mypullserver.company.pri/PSDSCPullServer.svc'

		ResourceRepositoryWeb ModuleSource {
			AllowUnsecureConnection	= $false
			RegistrationKey = '140a952b-b9d6-406b-b416-e0f759c9c0e4'
			ServerURL = 'https://mypullserver.company.pri/PSDSCPullServer.svc'			

Notice that the RegistrationKey and ServerURL are the same in both the ConfigurationRepositoryWeb and ResourceRepositoryWeb blocks? I’m using the exact same pull server. I can also specify a CertificateID setting, if the pull server requires client certificate authentication. You can also define a ResourceRepositoryShare{} block, which would be for a file share-based pull server, and it accepts Credential and SourcePath properties.

Again: it’s totally legal in WMF v5 to specify a ResourceRepositoryWeb{} block, completely omit any other configurations, and leave the LCM in Push mode. When you Push a configuration to the node, it’ll scan to see what resources are needed. If it’s missing any of those resources, the node will connect to the defined server and attempt to download the ZIPped resource module. It’ll then unzip it and proceed with the configuration. StatusData (a text field containing JSON data)