Gnarly Innards: How to live debug PowerShell DSC configurations without using Enable-DSCDebug

17_ctraltdelThe Problem

Have you ever needed to debug a PowerShell Desired State Configuration that appeared to be hanging when it was applying? At that point it's a little too late to run Enable-DscDebug. Here's how to debug it anyway…

The Solution

On the box applying the active configuration you can see the LCM is busy. Notice the LCMState and LCMStateDetail properties.

PS C:\> Get-DscLocalConfigurationManager

ActionAfterReboot              : ContinueConfiguration
AgentId                        : 7DF72A3A-9AEF-11E6-80BB-00155D67460E
AllowModuleOverWrite           : False
CertificateID                  :
ConfigurationDownloadManagers  : {}
ConfigurationID                :
ConfigurationMode              : ApplyOnly
ConfigurationModeFrequencyMins : 15
Credential                     :
DebugMode                      : {NONE}
DownloadManagerCustomData      :
DownloadManagerName            :
LCMCompatibleVersions          : {1.0, 2.0}
LCMState                       : Busy
LCMStateDetail                 : LCM is a applying an existing configuration.
LCMVersion                     : 2.0
StatusRetentionTimeInDays      : 10
PartialConfigurations          :
RebootNodeIfNeeded             : True
RefreshFrequencyMins           : 30
RefreshMode                    : PUSH
ReportManagers                 : {}
ResourceModuleManagers         : {}
PSComputerName                 :

To debug it we need to find out which process is applying the configuration. DSC configurations run in the WmiPrvSE process, but there are usually multiple instances of this process at any given time. We want the one with the DSC AppDomainName.

PS C:\> (Get-Process WmiPrvSE).Id | ForEach-Object {Get-PSHostProcessInfo -Id $_ | Where-Object AppDomainName -eq 'DscPsPluginWkr_AppDomain'}

ProcessName ProcessId AppDomainName
----------- --------- -------------
WmiPrvSE         3536 DscPsPluginWkr_AppDomain

Then we enter that process for debugging. After listing the runspaces you will usually debug #1.

PS C:\> Enter-PSHostProcess -Id 3536 -AppDomainName DscPsPluginWkr_AppDomain
[Process:3536]: PS C:\Windows\system32> Get-Runspace

 Id Name            ComputerName    Type          State         Availability
 -- ----            ------------    ----          -----         ------------
  1 Runspace1       localhost       Local         Opened        Busy
  2 Runspace2       localhost       Local         Opened        Available
 89 RemoteHost      localhost       Local         Opened        Busy

[Process:3536]: PS C:\Windows\system32> Debug-Runspace -Id 1

Now use the traditional PowerShell command line debugging techniques (? for menu). In my case I was debugging the xWaitForADDomain resource which has a sleep timer in it. At this point I had to wait for the timer to expire on the current iteration before the debug prompt would appear. As the hackers say in the movies: “I’m in!”

[DBG]: [Process:3536]: [Runspace1]: PS C:\Windows\system32>> ?

 s, stepInto         Single step (step into functions, scripts, etc.)
 v, stepOver         Step to next statement (step over functions, scripts, etc.)
 o, stepOut          Step out of the current function, script, etc.

 c, continue         Continue operation
 q, quit             Stop operation and exit the debugger
 d, detach           Continue operation and detach the debugger.

 k, Get-PSCallStack  Display call stack

 l, list             List source code for the current script.
                     Use "list" to start from the current line, "list "
                     to start from line , and "list  " to list 
                     lines starting from line 

              Repeat last command if it was stepInto, stepOver or list

 ?, h                displays this help message.

For instructions about how to customize your debugger prompt, type "help about_prompt".

You can use Get-Variable to see a list of all the variable in scope as the code is executing. Use ‘l’ to list the code and see where you are in the current execution. Use ‘s’, ‘v’, ‘o’ to step through and find your problem. Once you have analyzed your code, you can either use 'd' to detach and let it keep running or 'q' to stop the configuration completely and exit the debugger.

[DBG]: [Process:3536]: [Runspace1]: PS C:\Windows\system32>> d
[Process:3536]: PS C:\Windows\system32> Exit-PSHostProcess

There you go. You have now seen the gnarly innards of a live DSC configuration running on your box. I hope you do not need this trick very often, but now you know.

More Information

Read more about debugging PowerShell DSC configurations and resources:

Debugging PowerShell DSC Class Resources – Great article that teaches everything we did above.

PowerShell Runspace Debugging: Part 1 – More good background information.

Get-Help about_Debuggers – Learn more about PowerShell command line debugging.

What's New in PowerShell v5 – Watch the module 4 video of PowerShell MVP Kirk Munro explaining debugging

Skip to main content