Windows PowerShell Desired State Configuration (DSC), just like any other Windows software, records errors and events in logs that can be viewed from the Event Viewer. However, the trick lies in effectively parsing these logs, so we know exactly why a particular operation failed.
In this blog, we explain where the DSC event logs are, and how their content is structured. We also discuss how we can use DSC events for diagnosing failures, and how we can play with the events to gather maximum information from a single DSC operation. We use the term “DSC operation” to identify a single operation that DSC performs from beginning to end. Each DSC cmdlet, when run, represents a single operation. For instance, Start-DscConfiguration is a DSC operation.
Where are DSC event logs?
In Event Viewer, DSC events can be seen inside the tree structure: Applications and Services Logs/Microsoft/Windows/Desired State Configuration.
The corresponding PowerShell cmdlet, Get-WinEvent, can also be run to view the event logs.
PS C:\Users> Get-WinEvent -LogName “Microsoft-Windows-Dsc/Operational”
ProviderName: Microsoft-Windows-DSC
TimeCreated Id LevelDisplayName Message
———– — —————- ——-
11/17/2013 10:27:23 PM 4102 Information Job {02C38626-D95A-47F1-9DA2-C1D44A7128E7} : …
As shown in the example above, DSC’s primary log name is “Microsoft-Windows-DSC”. This is appended to the channel name to create the complete log name. The DSC engine writes mainly into three types of logs : Operational, Analytic, and Debug logs. Because the analytic and debug logs are turned off by default, and because troubleshooting an error is much more efficient if these logs are enabled before running an operation, I recommend turning on the logs first. These logs can be enabled in Event Viewer. The log name for the analytic channel is “Microsoft-Windows-Dsc/Analytic”, and the debug channel is “Microsoft-Windows-Dsc/Debug”.
You could also use the wevtutil utility to enable the logs, as shown in the following example.
PS C:\Users> wevtutil.exe set-log “Microsoft-Windows-Dsc/Analytic” /q:true /e:true
What do DSC logs contain?
DSC logs are split over the three log channels based on the importance of the message. The operational log in DSC contains all error messages, and can be used to identify a problem. The analytic log has a higher volume of events, and can identify where error(s) occurred. This channel also contains verbose messages (if any). The debug log contains logs that can help a developer understand how the errors occurred.
DSC event messages are structured such that every event message begins with a job ID that uniquely represents a DSC operation. For instance, in the example below, we try to obtain the message from the first event logged into the operational DSC log.
PS C:\Users> $AllDscOpEvents=get-winevent -LogName “Microsoft-Windows-Dsc/Operational”
PS C:\Users> $FirstOperationalEvent=$AllDscOpEvents[0]
PS C:\Users> $FirstOperationalEvent.Message
Job {02C38626-D95A-47F1-9DA2-C1D44A7128E7} :
Consistency engine was run successfully.
DSC events are logged in a particular structure that enables the user to aggregate events from one DSC job. The structure is as follows: Job ID : <Guid> <Event Message>
Gathering events from a single DSC operation
DSC event logs contain events generated by various DSC operations. However, the user is usually concerned with the detail about just one particular operation. All DSC logs can be grouped by the job ID property that is unique for every DSC operation. The job ID is displayed as the first property value in all DSC events. The following steps explain how we can accumulate all events in a grouped array structure.
<##########################################################################
Step 1 : Enable analytic and debug DSC channels (Operational channel is enabled by default)
###########################################################################>
wevtutil.exe set-log “Microsoft-Windows-Dsc/Analytic” /q:true /e:true
wevtutil.exe set-log “Microsoft-Windows-Dsc/Debug” /q:True /e:true
<##########################################################################
Step 2 : Perform the required DSC operation (Below is an example, you could run any DSC operation instead)
###########################################################################>
Get-DscLocalConfigurationManager
<##########################################################################
Step 3 : Collect all DSC Logs, from the Analytic, Debug and Operational channels
###########################################################################>
$DscEvents=[System.Array](Get-WinEvent “Microsoft-windows-dsc/operational”) `
+ [System.Array](Get-WinEvent “Microsoft-Windows-Dsc/Analytic” -Oldest) `
+ [System.Array](Get-Winevent “Microsoft-Windows-Dsc/Debug” -Oldest)
<##########################################################################
Step 4 : Group all logs based on the job ID
###########################################################################>
$SeparateDscOperations=$DscEvents | Group {$_.Properties[0].value}
Here, the variable $SeparateDscOperations contains logs grouped by the job IDs. Each array element of this variable represents a group of events logged by a different DSC operation. Hence, we can use this variable to access more information about the logs.
PS C:\> $SeparateDscOperations
Count Name Group
—– —- —–
48 {1A776B6A-5BAC-11E3-BF… {System.Diagnostics.Eventing.Reader.EventLogRecord, System.Diagnostics….
40 {E557E999-5BA8-11E3-BF… {System.Diagnostics.Eventing.Reader.EventLogRecord, System.Diagnostics….
PS C:\> $SeparateDscOperations[0].Group
ProviderName: Microsoft-Windows-DSC
TimeCreated Id LevelDisplayName Message
———– — —————- ——-
12/2/2013 3:47:29 PM 4115 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4198 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4114 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4102 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4098 Warning Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4098 Warning Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4176 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
12/2/2013 3:47:29 PM 4182 Information Job {1A776B6A-5BAC-11E3-BF41-00155D553612} : …
We can mine the data in the variable $SeparateDscOperations using Where-Object. Let me discuss a few reasons why we’d want to do this:
· Requirement 1: Show me all DSC operations on my machine that had some failure.
PS C:\> $SeparateDscOperations | Where-Object {$_.Group.LevelDisplayName -contains “Error”}
Count Name Group
—– —- —–
38 {5BCA8BE7-5BB6-11E3-BF… {System.Diagnostics.Eventing.Reader.EventLogRecord, System.Diagnostics….
Explanation: All events have a level display as per severity levels . This information can be used to identify the error events.
· Requirement 2: Give me details of operations run in the last half hour.
PS C:\> $DateLatest=(Get-date).AddMinutes(-30)
PS C:\> $SeparateDscOperations | Where-Object {$_.Group.TimeCreated -gt $DateLatest}
Count Name Group
—– —- —–
1 {6CEC5B09-5BB0-11E3-BF… {System.Diagnostics.Eventing.Reader.EventLogRecord}
Explanation: TimeCreated, a property of every Windows event, states the time the event was created. Comparing this property with a particular date/time object can be used to filter all events.
· Requirement 3: Display all messages from the latest operation.
PS C:\> $SeparateDscOperations[0].Group.Message
Job {5BCA8BE7-5BB6-11E3-BF41-00155D553612} :
Running consistency engine.
Job {1A776B6A-5BAC-11E3-BF41-00155D553612} :
Configuration is sent from computer NULL by user sid S-1-5-18.
Job {1A776B6A-5BAC-11E3-BF41-00155D553612} :
Displaying messages from built-in DSC resources:
WMI channel 1
ResourceID:
Message : [INCH-VM]: [] Starting consistency engine.
Job {1A776B6A-5BAC-11E3-BF41-00155D553612} :
Displaying messages from built-in DSC resources:
WMI channel 1
ResourceID:
Message : [INCH-VM]: [] Consistency check completed.
Explanation: The latest operation is stored in the first index of the array group $SeparateDscOperations. Hence, querying the group’s messages for index 0 returns all messages for the latest operation.
· Requirement 4: My most recent operation failed. What is the error message logged?
PS C:\> $myFailedEvent=($SeparateDscOperations[0].Group | Where-Object {$_.LevelDisplayName -eq “Error”})
PS C:\> $myFailedEvent.Message
Job {5BCA8BE7-5BB6-11E3-BF41-00155D553612} :
DSC Engine Error :
Error Message Current configuration does not exist. Execute Start-DscConfiguration command with -Path pa
rameter to specify a configuration file and create a current configuration first.
Error Code : 1
Explanation: $SeparateDscOperations[0].Group contains a set of events for the latest operation. Run the Where-Object cmdlet to filter the events based on their level display name. Results are stored in the $myFailedEvent variable, which can be further dissected to get the event message.
· Requirement 5: I know the required operation’s job ID = $jobX ; give me all events generated for this job ID.
PS C:\> ($SeparateDscOperations | Where-Object {$_.Name -eq $jobX} ).Group
ProviderName: Microsoft-Windows-DSC
TimeCreated Id LevelDisplayName Message
———– — —————- ——-
12/2/2013 4:33:24 PM 4102 Information Job {847A5619-5BB2-11E3-BF41-00155D553612} : …
12/2/2013 4:33:24 PM 4168 Information Job {847A5619-5BB2-11E3-BF41-00155D553612} : …
12/2/2013 4:33:24 PM 4146 Information Job {847A5619-5BB2-11E3-BF41-00155D553612} : …
12/2/2013 4:33:24 PM 4120 Information Job {847A5619-5BB2-11E3-BF41-00155D553612} : …
Explanation: $SeparateDscOperations is an array of groups, each of which has the name as the unique job ID. By running the Where-Object cmdlet, we can extract those groups of events that have a particular job ID.
The usage can be extended based on your requirements, to diagnose errors, or just to read events. These are just a few examples to get you started with DSC eventing information. They can make troubleshooting or reporting errors much quicker.
Inchara Shivalingaiah
Windows PowerShell Development
I understand it’s an old blog, but still this saved me so many hours looking everywhere to solve why my DSC script provisionning Azure Virtual Machine Scale Sets wasn’t working.
Thanks so much.