This repository was archived by the owner on May 15, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 107
Expand file tree
/
Copy pathcDscDiagnostics.psm1
More file actions
795 lines (656 loc) · 28 KB
/
cDscDiagnostics.psm1
File metadata and controls
795 lines (656 loc) · 28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
<#
# This script enables a user to diagnose errors caused by a DSC operation. In short, the following commands would help you diagnose errors
# To get the last 10 operations in DSC that show their Result status (failure,success) : Get-cDscOperation
# To get a list of last n (say, 13) DSC operations : Get-cDscOperation -Newest 13
# To see details of the last operation : Trace-cDscOperation
# TO view trace details of the third last operation run : Trace-cDscOperation 3
# To view trace details of an operation with Job ID $jID : Trace-cDscOperation -JobID $jID
# To View trace details of multiple computers : Trace-cDscOperation -ComputerName @("PN25113D0891","PN25113D0890")
#
#>
#region Global variables
$Script:DscVerboseEventIdsAndPropertyIndex=@{4100=3;4117=2;4098=3};
$Script:DscLogName="Microsoft-windows-dsc"
$Script:RedirectOutput=$false
$Script:TemporaryHtmLocation="$env:TEMP/dscreport"
$Script:SuccessResult="Success"
$Script:FailureResult="Failure"
$Script:ThisCredential=""
$Script:ThisComputerName=$env:COMPUTERNAME
$Script:UsingComputerName=$false
$Script:FormattingFile="cDscDiagnosticsFormat.ps1xml"
$Script:RunFirstTime = $true
#endregion
#region Cache for events
$Script:LatestGroupedEvents=@{} #Hashtable of "Computername", "GroupedEvents"
$Script:MostRecentJobId=@{} #Hashtale of "ComputerName", "GroupedEvents"
#endregion
#region Exported Functions
<#
.SYNOPSIS
Traces through any DSC operation selected from among all operations using its unique sequence ID (obtained from Get-cDscOperation), or from its unique Job ID
.DESCRIPTION
This function, when called, will look through all the event logs for DSC, and output the results in the form of an object, that contains the event type, event message, time created, computer name, job id, sequence number, and the event information.
.PARAMETER SequenceId
Each operation in DSC has a certain Sequence ID, ordered by time of creation of these DSC operations. The sequence IDs can be obtained by running Get-cDscOperation
By mentioning a sequence ID, the trace of the corresponding DSC operation is output.
.PARAMETER JobId
The event viewer shows each DSC event start with a unique job ID for each operation. If this job id is specified with this parameter, then all diagnostic messages displayed are taken from the dsc operation pertaining to this job id.
.PARAMETER ComputerName
The names of computers in which you would like to trace the past DSC operations
.PARAMETER Credential
The credential needed to access the computers specified inside ComputerName parameters
.EXAMPLE
To Obtain the diagnostic information for the latest operation :
Trace-cDscOperation
.EXAMPLE
To obtain the diagnostic information for the third latest operation :
Trace-cDscOperation -sequenceId 3
.EXAMPLE
To diagnose an operation with job Id 11112222-1111-1122-1122-111122221111 :
Trace-cDscOperation -JobId 11112222-1111-1122-1122-111122221111
.EXAMPLE
To Get Logs from a remote computer :
Trace-cDscOperation -ComputerName XYZ -sequenceID 2
To Get logs from a remote computer with credentials :
Trace-cDscOperation -Computername XYZ -Credential $mycredential -sequenceID 2
To get logs from multiple remote computers :
Trace-cDscOperation -ComputerName @("PN25113D0891","PN25113D0890")
Please note that to perform actions on the remote computer, have the firewall for remote configuration enabled. This can be done with the following command:
C:> netsh firewall set service remoteadmin enable
#>
function Trace-cDscOperation
{
[cmdletBinding()]
param(
[UInt32]$SequenceID=1, #latest is by default
[Guid]$JobId,
[String[]]$ComputerName,
[pscredential]$Credential)
Add-ClassTypes
if($ComputerName)
{
$Script:UsingComputerName=$true
$args=$PSBoundParameters
$null=$args.Remove("ComputerName")
$null=$args.Remove("Credential")
foreach($thisComputerName in $ComputerName)
{
Log -Verbose "Gathering logs for Computer $thisComputerName ..."
$Script:ThisComputerName=$thisComputerName
$Script:ThisCredential=$Credential
Trace-DscOperationInternal @PSBoundParameters
}
}
else
{
$Script:ThisComputerName=$env:COMPUTERNAME
Trace-DscOperationInternal @PSBoundParameters
$Script:UsingComputerName=$false
}
}
<#
.SYNOPSIS
Gives a list of all DSC operations that were executed . Each DSC operation has sequence Id information , and job id information
It returns a list of objects, each of which contain information on a distinct DSC operation . Here a DSC operation is referred to any single DSC execution, such as start-dscconfiguration, test-dscconfiguration etc. These will log events with a unique jobID (guid) identifying the DSC operation.
When you run Get-cDscOperation, you will see a list of past DSC operations , and you could use the following details from the output to trace any of them individually.
- Job ID : By using this GUID, you can search for the events in Event viewer, or run Trace-cDscOperation -jobID <required Jobid> to obtain all event details of that operation
- Sequence Id : By using this identifier, you could run Trace-cDscOperation <sequenceId> to get all event details of that particular dsc operation.
.DESCRIPTION
This will list all the DSC operations that were run in the past in the computer. By Default, it will list last 10 operations.
.PARAMETER Newest
By default 10 last DSC operations are pulled out from the event logs. To have more, you could use enter another number with this parameter.a PS Object with all the information output to the screen can be navigated by the user as required.
.EXAMPLE
PS C:\> Get-cDscOperation 20 #Lists last 20 operations
PS C:\> Get-cDscOperation -ComputerName @("XYZ","ABC") -Credential $cred #Lists operations for the array of computernames passed in.
#>
function Get-cDscOperation
{
[cmdletBinding()]
param(
[UInt32]$Newest=10,
[String[]]$ComputerName,
[pscredential]$Credential)
Add-ClassTypes
if($ComputerName)
{
$Script:UsingComputerName=$true
$args=$PSBoundParameters
$null=$args.Remove("ComputerName")
$null=$args.Remove("Credential")
foreach($thisComputerName in $ComputerName)
{
Log -Verbose "Gathering logs for Computer $thisComputerName"
$Script:ThisComputerName=$thisComputerName
$Script:ThisCredential=$Credential
Get-DscOperationInternal @PSBoundParameters
}
}
else
{
$Script:ThisComputerName=$env:COMPUTERNAME
Get-DscOperationInternal @PSBoundParameters
$Script:UsingComputerName=$false
}
}
#endregion
#region FunctionTools
function Log
{
param($text,[Switch]$Error,[Switch]$Verbose)
if($Error)
{
Write-Error $text
}
elseif($Verbose)
{
Write-Verbose $text
}
}
function Add-ClassTypes
{
#We don't want to add the same types again and again.
if($Script:RunFirstTime)
{
$pathToFormattingFile=(join-path $PSScriptRoot $Script:FormattingFile)
$ClassdefinitionGroupedEvents=@"
using System;
using System.Globalization;
using System.Collections;
namespace Microsoft.PowerShell.cDscDiagnostics
{
public class GroupedEvents {
public int SequenceId;
public System.DateTime TimeCreated;
public string ComputerName;
public string Result;
public Guid? JobID=null;
public System.Array AllEvents;
public int NumberOfEvents;
public System.Array AnalyticEvents;
public System.Array DebugEvents;
public System.Array NonVerboseEvents;
public System.Array VerboseEvents;
public System.Array OperationalEvents;
public System.Array ErrorEvents;
public System.Array WarningEvents;
}
}
"@
$ClassdefinitionTraceOutput=@"
using System;
using System.Globalization;
namespace Microsoft.PowerShell.cDscDiagnostics
{
public enum EventType {
DEBUG,
ANALYTIC,
OPERATIONAL,
ERROR,
VERBOSE
}
public class TraceOutput {
public EventType EventType;
public System.DateTime TimeCreated;
public string Message;
public string ComputerName;
public Guid? JobID=null;
public int SequenceID;
public System.Diagnostics.Eventing.Reader.EventRecord Event;
}
}
"@
Add-Type -Language CSharp -TypeDefinition $ClassdefinitionGroupedEvents
Add-Type -Language CSharp -TypeDefinition $ClassdefinitionTraceOutput
#Update-TypeData -TypeName TraceOutput -DefaultDisplayPropertySet EventType, TimeCreated, Message
Update-FormatData -PrependPath $pathToFormattingFile
$Script:RunFirstTime = $false; #So it doesnt do it the second time.
}
}
function Get-AllGroupedDscEvents
{
$groupedEvents=$null
$latestJobId=Get-DscLatestJobId
Log -Verbose "Collecting all events from the DSC logs"
if(($Script:MostRecentJobId[$Script:ThisComputerName] -eq $latestJobId ) -and $Script:LatestGroupedEvents[$Script:ThisComputerName])
{
# this means no new events were generated and you can use the event cache.
$groupedEvents=$Script:LatestGroupedEvents[$Script:ThisComputerName]
}
else
{
#Save it to cache
$allEvents=Get-AllDscEvents
if(!$allEvents)
{
Log -Error "Error : Could not find any events. Either a DSC operation has not been run, or the event logs are turned off . Please ensure the event logs are turned on in DSC. To set an event log, run the command wevtutil Set-Log <channelName> /e:true, example: wevtutil set-log 'Microsoft-Windows-Dsc/Operational' /e:true /q:true"
return
}
$groupedEvents= $allEvents | Group {$_.Properties[0].Value}
$Script:MostRecentJobId[$Script:ThisComputerName]=$latestJobId
$Script:LatestGroupedEvents[$Script:ThisComputerName] =$groupedEvents
}
#group based on their Job Ids
return $groupedEvents
}
#Wrapper over get-winevent, that will call into a computer if required.
function get-winevent
{
$resultArray=""
try
{
if($Script:UsingComputerName)
{
if($Script:ThisCredential)
{
$resultArray=Microsoft.PowerShell.Diagnostics\Get-WinEvent @args -ComputerName $Script:ThisComputerName -Credential $Script:ThisCredential
}
else
{
$resultArray= Microsoft.PowerShell.Diagnostics\Get-WinEvent @args -ComputerName $Script:ThisComputerName
}
}
else
{
$resultArray= Microsoft.PowerShell.Diagnostics\Get-WinEvent @args
}
}
catch
{
Log -Error "Get-Winevent failed with error : $_ "
throw "Cannot read events from computer $Script:ThisComputerName. Please check if the firewall is enabled. Run this command in the remote machine to enable firewall for remote administration : netsh firewall set service remoteadmin enable "
}
return $resultArray
}
#Gets the JOB ID of the most recently executed script.
function Get-DscLatestJobId
{
#Collect operational events , they're ordered from newest to oldest.
$allevents=get-winevent -LogName "$Script:DscLogName/operational" -MaxEvents 2 -ea Ignore
if($allevents -eq $null)
{
return "NOJOBID"
}
$latestEvent=$allevents[0] #Since it extracts it in a sorted order.
#Extract just the jobId from the string like : Job : {<jobid>}
#$jobInfo=(((($latestEvent.Message -split (":",2))[0] -split "job {")[1]) -split "}")[0]
$jobInfo=$latestEvent.Properties[0].value
return $jobInfo.ToString()
}
#Function to get all dsc events in the event log - not exposed by the module
function Get-AllDscEvents
{
#If you want a specific channel events, run it as Get-AllDscEvents
param
(
[string[]]$ChannelType=@("Debug","Analytic","Operational") ,
$OtherParams=@{}
)
if($ChannelType.ToLower().Contains("operational"))
{
$operationalEvents=get-winevent -LogName "$Script:DscLogName/operational" @OtherParams -ea Ignore
$allevents=$operationalEvents
}
if($ChannelType.ToLower().Contains("analytic"))
{
$analyticEvents=get-winevent -LogName "$Script:DscLogName/analytic" -Oldest -ea Ignore @OtherParams
if($analyticEvents -ne $null)
{
#Convert to an array type before adding another type - to avoid the error "Method invocation failed with no op_addition operator"
$allevents = [System.Array]$allEvents + $analyticEvents
}
}
if($ChannelType.ToLower().Contains("debug"))
{
$debugEvents=get-winevent -LogName "$Script:DscLogName/debug" -Oldest -ea Ignore @OtherParams
if($debugEvents -ne $null)
{
$allevents = [System.Array]$allEvents +$debugEvents
}
}
return $allevents
}
# Function to prompt the user to set an event log, for the channel passed in as parameter
#
function Test-DscEventLogStatus
{
param($Channel="Analytic")
$LogDetails=Get-WinEvent -ListLog "$Script:DscLogName/$Channel"
if($($LogDetails.IsEnabled))
{
return $true
}
$numberOfTries=0;
while($numberOfTries -lt 3)
{
$enableLog=Read-Host "The $Channel log is not enabled. Would you like to enable it?(y/n)"
if($enableLog.ToLower() -eq "y")
{
Enable-DscEventLog -Channel $Channel
Write-Host "Execute the operation again to record the events. Events were not recorded in the $Channel channel since it was disabled"
break
}
elseif($enableLog.ToLower() -eq "n")
{
Log -Error "The $Channel events cannot be read until it has been enabled"
break
}
else
{
Log -Error "Could not understand the option, please try again"
}
$numberOfTries++
}
return $false
}
#This function gets all the DSC runs that are recorded into the event log.
function Get-SingleDscOperation
{
#If you specify a sequence ID, then the diagnosis will be for that sequence ID.
param(
[Uint32]$indexInArray=0,
[Guid]$JobId
)
#Get all events
$groupedEvents=Get-AllGroupedDscEvents
if(!$groupedEvents)
{
return
}
#If there is a job ID present, ignore the IndexInArray, search based on jobID
if($JobId)
{
Log -Verbose "Looking at Event Trace for the given Job ID $JobId"
$indexInArray=0;
foreach($eventGroup in $groupedEvents)
{
#Check if the Job ID is present in any
if($($eventGroup.Name) -match $JobId)
{
break;
}
$indexInArray ++
}
if($indexInArray -ge $groupedEvents.Count)
{
#This means the job id doesn't exist
Log -Error "The Job ID Entered $JobId, does not exist among the dsc operations. To get a list of previously run DSC operations, run this command : Get-cDscOperation"
return
}
}
$requiredRecord=$groupedEvents[$indexInArray]
if($requiredRecord -eq $null)
{
Log -Error "Could not obtain the required record! "
return
}
$errorText="[None]"
$thisRunsOutputEvents=Split-SingleDscGroupedRecord -singleRecordInGroupedEvents $requiredRecord -index $indexInArray
$thisRunsOutputEvents
}
function Split-SingleDscGroupedRecord
{
param(
$singleRecordInGroupedEvents,
$index)
#$singleOutputRecord=New-Object psobject
$status=$Script:SuccessResult
$errorEvents=@()
$col_AllEvents=@()
$col_verboseEvents=@()
$col_analyticEvents=@()
$col_debugEvents=@()
$col_operationalEvents=@()
$col_warningEvents=@()
$col_nonVerboseEvents=@()
#We want to now add a column for each event that says "staus as success or failure"
$oneGroup= $singleRecordInGroupedEvents.Group
$column_Time=$oneGroup[0].TimeCreated
$oneGroup| %{
$thisEvent=$_
$thisType=""
$timeCreatedOfEvent=$_.TimeCreated
if($_.level -eq 2) #which means there's an error
{
$status="$Script:FailureResult"
$errorEvents += $_
$thisType= [Microsoft.PowerShell.cDscDiagnostics.EventType]::ERROR
}
elseif($_.LevelDisplayName -like "warning") { $col_warningEvents +=$_ }
if($_.ContainerLog.endsWith("operational"))
{
$col_operationalEvents+=$_ ;
$col_nonVerboseEvents += $_
#Only if its not an error message, mark it as OPerational tag
if(!$thisType)
{$thisType=[Microsoft.PowerShell.cDscDiagnostics.EventType]::OPERATIONAL}
}
elseif($_.ContainerLog.endsWith("debug")) { $col_debugEvents+=$_ ; $thisType = [Microsoft.PowerShell.cDscDiagnostics.EventType]::DEBUG }
elseif($_.ContainerLog.endsWith("analytic"))
{
$col_analyticEvents+=$_
if($_.Id -in $Script:DscVerboseEventIdsAndPropertyIndex.Keys)
{
$col_verboseEvents +=$_
$thisType=[Microsoft.PowerShell.cDscDiagnostics.EventType]::VERBOSE
}
else
{
$col_nonVerboseEvents += $_
$thisType=[Microsoft.PowerShell.cDscDiagnostics.EventType]::ANALYTIC
}
}
$eventMessageFromEvent=Get-MessageFromEvent $thisEvent -verboseType
#Add event with its tag
$thisObject= New-Object PSobject -Property @{TimeCreated=$timeCreatedOfEvent; Type=$thisType; Event=$thisEvent; Message = $eventMessageFromEvent}
$col_AllEvents += $thisObject
}
$jobIdWithoutParenthesis=($($singleRecordInGroupedEvents.Name).split('{}'))[1] #Remove paranthesis that comes in the job id
if(!$jobIdWithoutParenthesis) {$jobIdWithoutParenthesis=$null}
$singleOutputRecord = new-object Microsoft.PowerShell.cDscDiagnostics.GroupedEvents -property @{
SequenceID=$index;
ComputerName=$Script:ThisComputerName;
JobId=$jobIdWithoutParenthesis;
TimeCreated=$column_Time;
AllEvents=$col_AllEvents | Sort-Object TimeCreated;
AnalyticEvents=$col_analyticEvents ;
WarningEvents=$col_warningEvents | Sort-Object TimeCreated ;
OperationalEvents=$col_operationalEvents;
DebugEvents=$col_debugEvents ;
VerboseEvents=$col_verboseEvents ;
NonVerboseEvents=$col_nonVerboseEvents | Sort-Object TimeCreated;
ErrorEvents=$errorEvents;
Result=$status;
NumberOfEvents=$singleRecordInGroupedEvents.Count;}
return $singleOutputRecord
}
function Get-MessageFromEvent($EventRecord,[switch]$verboseType)
{
#You need to remove the job ID and send back the message
if($EventRecord.Id -in $Script:DscVerboseEventIdsAndPropertyIndex.Keys -and $verboseType)
{
$requiredIndex=$Script:DscVerboseEventIdsAndPropertyIndex[$($EventRecord.Id)]
return $EventRecord.Properties[$requiredIndex].Value
}
$NonJobIdText=($EventRecord.Message -split([Environment]::NewLine,2))[1]
return $NonJobIdText
}
function Get-DscErrorMessage
{
param(<#[System.Diagnostics.Eventing.Reader.EventRecord[]]#>$ErrorRecords)
$cimErrorId=4131
$errorText=""
foreach($Record in $ErrorRecords)
{
#go through each record, and get the single error message required for that record.
$outputErrorMessage=Get-SingleRelevantErrorMessage -errorEvent $Record
if($Record.Id -eq $cimErrorId)
{
$errorText = "$outputErrorMessage $errorText"
}
else
{
$errorText = "$errorText $outputErrorMessage"
}
}
return $errorText
}
function Enable-DscEventLog
{
<#
.SYNOPSIS
Sets any DSC Event log (Operational, analytic, debug )
.DESCRIPTION
This cmdlet will set a DSC log when run with Enable-DscEventLog <channel Name>.
.PARAMETER Channel
Name of the channel of the event log to be set.
.EXAMPLE
C:\PS> Enable-DscEventLog "Analytic"
C:\PS> Enable-DscEventLog -Channel "Debug"
#>
[CmdletBinding()]
param
(
[ValidateSet("Debug", "Analytic", "Operational")]
[string] $Channel = "Analytic",
[string] $ComputerName = $env:ComputerName,
$Credential
)
$LogName = "Microsoft-Windows-Dsc"
$eventLogFullName = "$LogName/$Channel"
try
{
Write-Verbose "Enabling the log $eventLogFullName"
if($ComputerName -eq $env:COMPUTERNAME)
{
wevtutil set-log $eventLogFullName /e:true /q:true
}
else
{
# For any other computer, invoke command.
$scriptTosetChannel = [Scriptblock]::Create(" wevtutil set-log $eventLogFullName /e:true /q:true")
if($Credential)
{
Invoke-Command -ScriptBlock $scriptTosetChannel -ComputerName $ComputerName -Credential $Credential
}
else
{
Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptTosetChannel
}
}
Write-Verbose "The $Channel event log has been Enabled. "
}
catch
{
Write-Error "Error : $_ "
}
}
function Get-SingleRelevantErrorMessage(<#[System.Diagnostics.Eventing.Reader.EventRecord]#>$errorEvent)
{
$requiredPropertyIndex=@{4116=2;
4131=1;
4183 =-1;#means full message
4129=-1;
4192=-1;
4193=-1;
4194=-1;
4185=-1;
4097=6;
4103=5;
4104=4}
$cimErrorId=4131
$errorText=""
$outputErrorMessage=""
$eventId=$errorEvent.Id
$propertyIndex=$requiredPropertyIndex[$eventId]
if($propertyIndex -ne -1)
{
#This means You need just the property from the indices hash
$outputErrorMessage=$errorEvent.Properties[$propertyIndex].Value
}
else
{
$outputErrorMessage=Get-MessageFromEvent -EventRecord $errorEvent
}
return $outputErrorMessage
}
function Trace-DscOperationInternal
{
[cmdletBinding()]
param(
[UInt32]$SequenceID=1, #latest is by default
[Guid]$JobId
)
#region VariableChecks
$indexInArray= ($SequenceId-1); #Since it is indexed from 0
if($indexInArray -lt 0)
{
Log -Error "Please enter a valid Sequence ID . All sequence IDs can be seen after running command Get-cDscOperation . " -ForegroundColor Red
return
}
$null=Test-DscEventLogStatus -Channel "Analytic"
$null=Test-DscEventLogStatus -Channel "Debug"
#endregion
#First get the whole object set of that operation
$thisRUnsOutputEvents=""
if(!$JobId)
{
$thisRunsOutputEvents=Get-SingleDscOperation -IndexInArray $indexInArray
}
else
{
$thisRunsOutputEvents=Get-SingleDscOperation -IndexInArray $indexInArray -JobId $JobId
}
if(!$thisRunsOutputEvents)
{
return;
}
#Now we play with it.
$result=$thisRunsOutputEvents.Result
#Parse the error events and store them in error text.
$errorEvents= $thisRunsOutputEvents.ErrorEvents
$errorText = Get-DscErrorMessage -ErrorRecords $errorEvents
#Now Get all logs which are non verbose
$nonVerboseMessages=@()
$AllEventMessageObject=@()
$thisRunsOutputEvents.AllEvents | %{
$ThisEvent= $_.Event
$ThisMessage= $_.Message
$ThisType= $_.Type
$ThisTimeCreated= $_.TimeCreated
#Save a hashtable as a message value
if(!$thisRunsOutputEvents.JobId) {$thisJobId=$null}
else {$thisJobId=$thisRunsOutputEvents.JobId}
$AllEventMessageObject += new-object Microsoft.PowerShell.cDscDiagnostics.TraceOutput -Property @{EventType=$ThisType;TimeCreated=$ThisTimeCreated;Message=$ThisMessage;ComputerName=$Script:ThisComputerName;JobID=$thisJobId;SequenceID=$SequenceID;Event=$ThisEvent}
}
return $AllEventMessageObject
}
#Internal function called by Get-cDscOperation
function Get-DscOperationInternal()
{
param
([UInt32]$Newest = 10)
#Groupo all events
$groupedEvents=Get-AllGroupedDscEvents
$DiagnosedGroup =$groupedEvents
#Define the type that you want the output in
$index=1
foreach($singleRecordInGroupedEvents in $DiagnosedGroup)
{
$singleOutputRecord=Split-SingleDscGroupedRecord -singleRecordInGroupedEvents $singleRecordInGroupedEvents -index $index
$singleOutputRecord
if($index -ge $Newest)
{
break;
}
$index++
}
}
#endregion
function Clear-DscDiagnosticsCache
{
Log -Verbose "Clearing Diagnostics Cache"
$Script:LatestGroupedEvents=@{}
$Script:MostRecentJobId=@{}
}
Export-ModuleMember -Function Trace-cDscOperation, Get-cDscOperation, Enable-DscEventLog