sensu-plugins-windows 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,603 @@
1
+ #
2
+ # check-muilti-template.ps1
3
+ #
4
+ # DESCRIPTION:
5
+ # This is a teplate which should be imported and adapted with the use of a
6
+ # $CheckOptions object.
7
+ #
8
+ # By default, it will check the state of Windows services, just to provide
9
+ # an example. Please also see the example 'check-adapters.ps1' for more
10
+ # info on how to build on this template.
11
+ #
12
+ # Please see the '-Help' parameter, under the 'Sensu check token
13
+ # substitution' header for more info on some extra parsing features.
14
+ #
15
+ # OUTPUT:
16
+ # plain text
17
+ #
18
+ # PLATFORMS:
19
+ # Windows
20
+ #
21
+ # DEPENDENCIES:
22
+ #
23
+ # USAGE:
24
+ # Please run this check with the '-help' parameter for more info.
25
+ #
26
+ # NOTES:
27
+ #
28
+ # LICENSE:
29
+ # Copyright 2016 James Booth <james@absolutejam.co.uk>
30
+ # Released under the same terms as Sensu (the MIT license); see LICENSE for details.
31
+ #
32
+
33
+
34
+ #REGION Configurables
35
+
36
+ [CmdletBinding()]
37
+ Param(
38
+ # Items to check. If any of these items are in a 'failed' state, the check
39
+ # will return a CRITICAL (2) status.
40
+ # Please supply -Help for more information.
41
+ [Parameter(
42
+ Mandatory = $False
43
+ )]
44
+ [array]$CriticalItems,
45
+
46
+ # Items to check. If any of these items are in a 'failed' state, the check
47
+ # will return a WARNING (1) status.
48
+ # Please supply -Help for more information.
49
+ [Parameter(
50
+ Mandatory = $False
51
+ )]
52
+ [array]$ImportantItems,
53
+
54
+ # Display help about this check.
55
+ [switch]$Help = $Help
56
+ # This is so wrapper scripts can pass through '-help'
57
+
58
+ )
59
+
60
+ # Default options. Overridee after importing if required.
61
+ $CheckOptions = @{
62
+ # Example output using below values:
63
+ # CheckName CRITICAL: The following items are in a failed state:
64
+ # - ItemOne
65
+ # - ItemTwo
66
+
67
+ # The name of the check
68
+ 'CheckName' = 'CheckItem'
69
+ # The message to display in event of an OK state
70
+ 'MessageOK' = 'All items are in an OK state.'
71
+ # The message to display in event of a WARNING state
72
+ 'MessageImportant' = 'The following important items are in a failed state:'
73
+ # The message to display in event of a CRITICAL state
74
+ 'MessageCritical' = 'The following critical items are in a failed state:'
75
+ # The message to display in event of missing items
76
+ 'MessageMissing' = 'The following items are missing:'
77
+ # The message to display if no items are specified
78
+ 'MessageNoneSpecified' = 'No items specified.'
79
+ # Change this to $True if you want to check for items that are missing
80
+ # from FailedItems
81
+ 'Inverse' = $False
82
+ # Check if any items are missing
83
+ 'CheckMissing' = $True
84
+ # State of check in the event of missing items
85
+ # (1 OK 2 WARNING 3 CRITICAL)
86
+ 'MissingState' = 2
87
+
88
+ # NOTE: The following scriptblocks must return comparable data
89
+ # eg. an array of strings
90
+ # ScriptBlock to get ALL items
91
+ 'ScriptBlockBaseItems' = {
92
+ Get-Service |
93
+ Select-Object -ExpandProperty Name
94
+ }
95
+ # ScriptBlock to get FAILED items
96
+ 'ScriptBlockMatchItems' = {
97
+ Get-Service |
98
+ Where-Object { $_.Status -ne 'Running' } |
99
+ Select-Object -ExpandProperty Name
100
+ }
101
+ # Help message for this check
102
+ 'CheckHelp' = @'
103
+ Checks whether any specified items are in a failed state.
104
+
105
+ Arguments:
106
+ -CriticalItems A string of comma-separated items
107
+ -ImportantItems A string of comma-separated items
108
+ -Help Show help
109
+
110
+ Example usage:
111
+ powershell.exe -file check-multi-template.ps1 -criticalitems "item1,item2" -warningitems "item3,item4"
112
+
113
+ '@
114
+ }
115
+
116
+ #ENDREGION Configurables
117
+
118
+
119
+ #REGION Functions
120
+
121
+ Function Format-ParamArray {
122
+ <#
123
+ .SYNOPSIS
124
+ Convert an array of strings that contain comma-separated values into
125
+ a single array of all the values. Also removes instances of 'None'.
126
+ .EXAMPLE
127
+ Add-OutputEntry -Status 2 -Items 'alpha','bravo'
128
+ #>
129
+ [CmdletBinding()]
130
+ Param(
131
+ # Array of arrays or strings to be flattened
132
+ [Parameter(
133
+ Mandatory = $False
134
+ )]
135
+ [string[]]$Param = @()
136
+ )
137
+
138
+ # Convert a single string into an array with a single value
139
+ if ($Param -is [string]) {
140
+ $Return = @($Param)
141
+ return ,$Return
142
+ }
143
+
144
+ # Flatten the (potential) array into a string
145
+ $Param = $Param -Join ','
146
+ # Strip any instances of 'None'
147
+ $Param = $Param -Replace 'None[,]?',''
148
+ # Replace multiple consecutive commas with a single comma
149
+ $Param = $Param -Replace '[,]{2,}',','
150
+ # If the last character is a comma, remove it
151
+ if ($Param[-1] -eq ',') {
152
+ $Param = $Param.substring(0, $Param.Length-1)
153
+ }
154
+ # Split into an array
155
+ [array]$Param = $Param -split ','
156
+
157
+ return ,$Param
158
+ }
159
+
160
+ Function Write-ExitState {
161
+ <#
162
+ .SYNOPSIS
163
+ Exit script with supplied exit code
164
+ .PARAMETER ExitState
165
+ The exit code/state of the check (0 OK, 1 WARNING, 2 CRITICAL)
166
+ #>
167
+ [CmdletBinding()]
168
+ Param(
169
+ [Parameter(
170
+ Mandatory = $False
171
+ )]
172
+ [ValidateSet(0, 1, 2)]
173
+ [int]$ExitState = 0
174
+ )
175
+
176
+ Exit $ExitState
177
+ }
178
+
179
+ Function Add-OutputEntry {
180
+ <#
181
+ .SYNOPSIS
182
+ Append check output to 'Output' array.
183
+ .DESCRIPTION
184
+ Allows multiple levels of check results to be included in a check's
185
+ output by adding them all to a single 'Output' array and joining them
186
+ upon submitting check result.
187
+ .PARAMETER State
188
+ The state of the check (0 OK, 1 WARNING, 2 CRITICAL)
189
+ .PARAMETER Items
190
+ Items to format into a bullet list that will be included in the check
191
+ output, eg. a list of failed services that need attention.
192
+ .PARAMETER Message
193
+ Override the default message if required.
194
+ .EXAMPLE
195
+ Add-OutputEntry -Status 2 -Items 'alpha','bravo'
196
+ #>
197
+ [CmdletBinding()]
198
+ Param(
199
+ # The check state (0, 1, 2)
200
+ [Parameter(
201
+ Mandatory = $False
202
+ )]
203
+ [ValidateSet(0, 1, 2)]
204
+ [int]$State = 0,
205
+
206
+ # Items to be enumerated in the check output.
207
+ [Parameter(
208
+ Mandatory = $False
209
+ )]
210
+ [array]$Items,
211
+
212
+ # Supply a custom message.
213
+ [Parameter(
214
+ Mandatory = $False
215
+ )]
216
+ [string]$Message
217
+ )
218
+
219
+ $OutputEntry = New-Object PSObject -Property @{
220
+ 'State' = $State
221
+ 'Items' = $Items
222
+ 'Message' = $Message
223
+ }
224
+ $Output.Add($OutputEntry) | Out-Null
225
+
226
+ }
227
+
228
+ Function Test-NullParameters {
229
+ <#
230
+ .SYNOPSIS
231
+ Exit with OK state if no parameters are passed to script.
232
+
233
+ .PARAMETER Parameters
234
+ Check that each item in the array isn#t an empty string.
235
+ #>
236
+ [CmdletBinding()]
237
+ Param(
238
+ [array]$Parameters
239
+ )
240
+
241
+ # Check if any of the parameters (eg. CriticalItems) is empty
242
+ $ParamCount = 0
243
+ ForEach ($Parameter in $Parameters) {
244
+ $ParamCount += $Parameter |
245
+ Where-Object { $_ -ne '' } |
246
+ Measure-Object |
247
+ Select-Object -ExpandProperty Count
248
+ }
249
+
250
+ if ($ParamCount -eq 0) {
251
+ Add-OutputEntry -State 0 -Message $CheckOptions.MessageNoneSpecified
252
+ Write-CheckResult
253
+ }
254
+
255
+ }
256
+
257
+ Function Compare-CheckItems {
258
+ <#
259
+ .SYNOPSIS
260
+ Compares an 'BaseItems' array against an array of items that
261
+ we want to check the status of.
262
+
263
+ .DESCRIPTION
264
+ Compares a 'CompareItems' array against a 'BaseItems' array,
265
+ returning either those items that are missing from BaseItems
266
+ (-Missing flag), items that are present in both arrays.
267
+
268
+ This lets us compare a list of critical services we want
269
+ to ensure are running against an array of failed services,
270
+ or compare a list of users we want to ensure are absent from
271
+ the system against all users on the system.
272
+
273
+ .PARAMETER BaseItems
274
+ An arrayo of all items in a specific state, such as all services
275
+ available or all network adapters that are disconnected.
276
+
277
+ .PARAMETER CompareItems
278
+ An array of items that we want to explicitly check against the
279
+ BaseItems array.
280
+
281
+ .PARAMETER Missing
282
+ Supply this parameter if you only want to return items that have
283
+ been supplied but are missing from the BaseItems array (Essentially
284
+ reverses the effect of the function).
285
+
286
+ .EXAMPLE
287
+ $CriticalServices = 'dhcp','dnscache'
288
+ $AllServices = Get-Services | Select-Object -ExpandProperty Name
289
+ Compare-CheckItems -BaseItems $AllServices -CompareItems $CriticalServices
290
+
291
+ #>
292
+ [CmdletBinding()]
293
+ Param(
294
+ [array]$BaseItems,
295
+ [array]$CompareItems,
296
+ [switch]$Missing
297
+ )
298
+
299
+ # If an array of arrays was passed, extract all values. Otherwise just
300
+ # use values from array.
301
+ $MergedCompareItems = New-Object -TypeName System.Collections.ArrayList
302
+ ForEach ($Item in $CompareItems |
303
+ Where-Object { $_ -ne '' }) {
304
+ if ($Item -is [array]) {
305
+ ForEach ($ArrayItem in $Item |
306
+ Where-Object { $_ -ne '' }) {
307
+ $MergedCompareItems.Add($ArrayItem) | Out-Null
308
+ }
309
+ } else {
310
+ $MergedCompareItems.Add($Item) | Out-Null
311
+ }
312
+ }
313
+
314
+ if ($Missing) {
315
+ $ReturnItems = Compare-Object -ReferenceObject $MergedCompareItems `
316
+ -DifferenceObject $BaseItems |
317
+ Where-Object { $_.SideIndicator -eq '<=' } |
318
+ Select-Object -ExpandProperty InputObject
319
+
320
+
321
+ } else {
322
+ $ReturnItems = Compare-Object -ReferenceObject $MergedCompareItems `
323
+ -DifferenceObject $BaseItems `
324
+ -ExcludeDifferent `
325
+ -IncludeEqual |
326
+ Where-Object { $_.SideIndicator -eq '==' } |
327
+ Select-Object -ExpandProperty InputObject
328
+ }
329
+
330
+ # This hackery forces Powershell to return an array and stops it mangling
331
+ # it into $Null or a string
332
+ if ($ReturnItems -eq $Null) {
333
+ $ReturnItems = ,@()
334
+ Return $ReturnItems
335
+ } else {
336
+ return ,$ReturnItems
337
+ }
338
+ }
339
+
340
+ Function Get-CheckStatus {
341
+ <#
342
+ .SYNOPSIS
343
+ Returns a string containing the check status based on numerical state/
344
+ #>
345
+ [CmdletBinding()]
346
+ Param(
347
+ [array]$State
348
+ )
349
+
350
+ switch ($State) {
351
+ 0 {
352
+ return New-Object PSObject -Property @{
353
+ 'Status' = 'OK:'
354
+ 'MessageBody' = $CheckOptions.MessageOK
355
+ }
356
+ }
357
+
358
+ 1 {
359
+ return New-Object PSObject -Property @{
360
+ 'Status' = 'WARN:'
361
+ 'MessageBody' = $CheckOptions.MessageImportant
362
+ }
363
+ }
364
+
365
+ 2 {
366
+ return New-Object PSObject -Property @{
367
+ 'Status' = 'CRITICAL:'
368
+ 'MessageBody' = $CheckOptions.MessageCritical
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ Function Write-CheckResult() {
375
+ <#
376
+ .SYNOPSIS
377
+ Return the frmatted check result based on $Output
378
+ #>
379
+
380
+ # Get the highest 'state' value and use that as the total check state
381
+ $FinalState = $Output | Sort-Object -Property state -Descending |
382
+ Select-Object -First 1 |
383
+ Select-Object -ExpandProperty 'State'
384
+
385
+ $FinalStatus = Get-CheckStatus -State $FinalState |
386
+ Select-Object -ExpandProperty 'Status'
387
+
388
+ # Compile the final output
389
+ $CheckMessage = New-Object -TypeName System.Collections.ArrayList
390
+ $CheckMessage.Add(
391
+ ('{0} {1}' -f $CheckOptions.CheckName,$FinalStatus)
392
+ ) | Out-Null
393
+
394
+ ForEach ($State in $Output |
395
+ Group-Object -Property State |
396
+ Sort-Object -Property State -Descending) {
397
+
398
+ ForEach ($Entry in $State.Group) {
399
+ $CheckState = Get-CheckStatus -State $Entry.State
400
+
401
+ if ($Entry.Message) {
402
+ $MessageBody = $Entry.Message
403
+ } else {
404
+ $MessageBody = $CheckState.MessageBody
405
+ }
406
+
407
+ if ($Entry.Items) {
408
+ $Bullet = "`r`n -"
409
+ $ItemsInformation = "$Bullet {1}" -f $Bullet,($Entry.Items -join "$Bullet ")
410
+ } else {
411
+ $ItemsInformation = ''
412
+ }
413
+
414
+ #$Entry | gm
415
+
416
+ # Format message to add
417
+ $Message = " {0}{1}" -f $MessageBody,$ItemsInformation
418
+
419
+ $CheckMessage.Add($Message) | Out-Null
420
+ }
421
+ }
422
+
423
+ Write-Output ($CheckMessage -join "`r`n")
424
+ Write-ExitState -ExitState $FinalState
425
+ }
426
+
427
+ Function Write-Help() {
428
+ <#
429
+ .SYNOPSIS
430
+ Exit, showing help text.
431
+ #>
432
+ Write-Output ("{0}`r`n{1}" -f $CheckOptions.CheckHelp, $CheckMultiHelp)
433
+ Write-ExitState -ExitState 0
434
+ }
435
+
436
+ # This is standard across all checks using this template.
437
+ $CheckMultiHelp = @'
438
+ Sensu check token substitution:
439
+ Because this check is designed to make full use of Sensu's check token
440
+ substitution (https://sensuapp.org/docs/latest/reference/checks.html#check-token-substitution)
441
+ feature, some special considerations have been taken for how the arguments are parsed.
442
+
443
+ The main parameters support a list of of comma-separated strings.
444
+ eg. -CriticalItems 'value1','value2'
445
+ They also accepts accept a single string with comma-separated values.
446
+ eg. -param1 'value1,value2'
447
+ ...or you can mix & match the two and all of the values will be merged.
448
+ eg. -param1 'value1','value2,value3'
449
+ Additionally, any use of the word 'None' will be ignored.
450
+ eg. -param1 'value1','None,value2','None'
451
+
452
+ This is because Sensu's client attribute substitution tokens only work with
453
+ flat strings, but by supporting both of the above methods, it allows the use
454
+ of multiple values within a single check/client attribute AND multiple
455
+ different client/check attributes to be used. Additionally, because 'None'
456
+ is ignored, it allows the user to provide a default value in the check
457
+ token substitution, as not to throw an error if the value is missing.
458
+
459
+ Token substitution example:
460
+ Check attribute 'check_attr' = "alpha,bravo"
461
+ Client attribute 'client_attr' = "charlie,delta"
462
+
463
+ powershell.exe -File check.ps1 -param1 ":::check_attr|None:::",":::missing_attr|None:::",":::client_attr|None:::"
464
+
465
+ Which evaluates to:
466
+
467
+ powershell.exe -File check.ps1 -param "alpha,bravo","None","charlie,delta"
468
+
469
+ The script then strips any instances of 'None' and processes the
470
+ comma-separated string as single flat array.
471
+ '@
472
+
473
+ #
474
+ # MAIN FUNCTION
475
+ #
476
+ Function Invoke-Main {
477
+ <#
478
+ .SYNOPSIS
479
+ The main process. Run automatically when running the script, or when
480
+ called if script is imported.
481
+
482
+ .PARAMETER CriticalItems
483
+ Variable to pass through to CriticalItems
484
+
485
+ .PARAMETER ImportantItems
486
+ Variable to pass through to ImportantItems
487
+ #>
488
+ [CmdletBinding()]
489
+ Param(
490
+ [Parameter(
491
+ Mandatory = $False
492
+ )]
493
+ [array]$CriticalItems = @(),
494
+
495
+ [Parameter(
496
+ Mandatory = $False
497
+ )]
498
+ [array]$ImportantItems = @()
499
+ )
500
+ # If -Help is passed, show help and exit
501
+ if ($Help) {
502
+ Write-Help
503
+ }
504
+
505
+ # Setup
506
+ $Output = New-Object -TypeName System.Collections.ArrayList
507
+
508
+ # Merge the cli parameters into a single string
509
+ $CriticalItemList = Format-ParamArray -Param $CriticalItems
510
+ $ImportantItemList = Format-ParamArray -Param $ImportantItems
511
+
512
+ # Exit if no/null parameters specified
513
+ Test-NullParameters -Parameters $CriticalItemList,$ImportantItemList
514
+
515
+ # Evaluate the scriptblocks so we can compare items passed into the script
516
+ # vs. running state.
517
+ if ($CheckOptions.CheckMissing -ne $False -and
518
+ $CheckOptions.Inverse -ne $True) {
519
+ $BaseItems = & $CheckOptions.ScriptblockBaseItems
520
+ }
521
+ $MatchItems = & $CheckOptions.ScriptBlockMatchItems
522
+ if ($MatchItems.Count -eq 0) { $MatchItems = ,@() }
523
+
524
+ # Check that all of the items specified are present before checking their
525
+ # status
526
+ if ($CheckOptions.CheckMissing -ne $False -and
527
+ $CheckOptions.Inverse -ne $True) {
528
+ $MissingItems = Compare-CheckItems -BaseItems $BaseItems `
529
+ -CompareItems $CriticalItemList,
530
+ $ImportantItemList `
531
+ -Missing
532
+
533
+ if ($MissingItems.Count -gt 0) {
534
+ Add-OutputEntry -State $CheckOptions.MissingState `
535
+ -Message $CheckOptions.MessageMissing `
536
+ -Items $MissingItems
537
+ }
538
+ }
539
+
540
+
541
+ # ImportantItems
542
+ if ($CheckOptions.Inverse) {
543
+ # Only return items that are MISSING from $MatchItems
544
+ $MatchedImportantItems = Compare-CheckItems `
545
+ -BaseItems $MatchItems `
546
+ -CompareItems $ImportantItemList `
547
+ -Missing
548
+
549
+ } else {
550
+ # Return items that match those in $MatchItems
551
+ $MatchedImportantItems = Compare-CheckItems `
552
+ -BaseItems $MatchItems `
553
+ -CompareItems $ImportantItemList
554
+
555
+ }
556
+
557
+ if ($MatchedImportantItems.Count -gt 0) {
558
+ Add-OutputEntry -State 1 -Items $MatchedImportantItems
559
+ }
560
+
561
+
562
+
563
+ # CriticalItems
564
+ if ($CheckOptions.Inverse) {
565
+ # Only return items that are MISSING from $MatchItems
566
+ $MatchedCriticalItems = Compare-CheckItems `
567
+ -BaseItems $MatchItems `
568
+ -CompareItems $CriticalItemList `
569
+ -Missing
570
+ } else {
571
+ # Return items that match those in $MatchItems
572
+ $MatchedCriticalItems = Compare-CheckItems `
573
+ -BaseItems $MatchItems `
574
+ -CompareItems $CriticalItemList
575
+ }
576
+
577
+ if ($MatchedCriticalItems.Count -gt 0) {
578
+ Add-OutputEntry -State 2 -Items $MatchedCriticalItems
579
+ }
580
+
581
+
582
+
583
+ # No issues so far!
584
+ if ($Output.Count -eq 0) {
585
+ Add-OutputEntry -State 0
586
+ }
587
+
588
+ Write-CheckResult
589
+
590
+ }
591
+
592
+ #ENDREGION Functions
593
+
594
+
595
+ #REGION Main
596
+
597
+ # Run 'Invoke-Main' if run directly, but don't if imported.
598
+ # (Python way is best way)
599
+ $Imported = $MyInvocation.InvocationName -eq '.'
600
+ if (!$Imported) {
601
+ Invoke-Main -CriticalItems $CriticalItems `
602
+ -ImportantItems $ImportantItems
603
+ }