@@ -89,25 +89,20 @@ function Get-TargetResource
89
89
$serviceFailureActions = Get-ServiceFailureActions - Service $service.Name
90
90
91
91
$serviceResource = @ {
92
- Name = $Name
93
- Ensure = ' Present'
94
- Path = $serviceCimInstance.PathName
95
- StartupType = $startupType
96
- BuiltInAccount = $builtInAccount
97
- State = $service.Status.ToString ()
98
- DisplayName = $service.DisplayName
99
- Description = $serviceCimInstance.Description
100
- DesktopInteract = $serviceCimInstance.DesktopInteract
101
- Dependencies = $dependencies
102
- ResetPeriodSeconds = $serviceFailureActions.resetPeriodSeconds
103
- FailureCommand = $serviceFailureActions.failureCommand
104
- RebootMessage = $serviceFailureActions.rebootMessage
105
- failure1Action = $serviceFailureActions.failureAction1.actionType
106
- failure1Delay = $serviceFailureActions.failureAction1.delay
107
- failure2Action = $serviceFailureActions.failureAction2.actionType
108
- failure2Delay = $serviceFailureActions.failureAction2.delay
109
- failure3Action = $serviceFailureActions.failureAction3.actionType
110
- failure3Delay = $serviceFailureActions.failureAction3.delay
92
+ Name = $Name
93
+ Ensure = ' Present'
94
+ Path = $serviceCimInstance.PathName
95
+ StartupType = $startupType
96
+ BuiltInAccount = $builtInAccount
97
+ State = $service.Status.ToString ()
98
+ DisplayName = $service.DisplayName
99
+ Description = $serviceCimInstance.Description
100
+ DesktopInteract = $serviceCimInstance.DesktopInteract
101
+ Dependencies = $dependencies
102
+ ResetPeriodSeconds = $serviceFailureActions.resetPeriodSeconds
103
+ FailureCommand = $serviceFailureActions.failureCommand
104
+ RebootMessage = $serviceFailureActions.rebootMessage
105
+ FailureActionsCollection = $serviceFailureActions.ActionsCollection
111
106
}
112
107
}
113
108
else
@@ -529,28 +524,8 @@ function Test-TargetResource
529
524
$FailureCommand ,
530
525
531
526
[Parameter ()]
532
- [ACTION _TYPE ]
533
- $Failure1Action ,
534
-
535
- [Parameter ()]
536
- [System.UInt32 ]
537
- $Failure1Delay ,
538
-
539
- [Parameter ()]
540
- [ACTION _TYPE ]
541
- $Failure2Action ,
542
-
543
- [Parameter ()]
544
- [System.UInt32 ]
545
- $Failure2Delay ,
546
-
547
- [Parameter ()]
548
- [ACTION _TYPE ]
549
- $Failure3Action ,
550
-
551
- [Parameter ()]
552
- [System.UInt32 ]
553
- $Failure3Delay ,
527
+ [System.Object []]
528
+ $FailureActionsCollection ,
554
529
555
530
[Parameter ()]
556
531
[ValidateNotNull ()]
@@ -723,47 +698,34 @@ function Test-TargetResource
723
698
return $false
724
699
}
725
700
726
- # Check the failure 1 action
727
- if ($PSBoundParameters.ContainsKey (' Failure1Action' ) -and $Failure1Action -ine $serviceResource.failure1Action )
728
- {
729
- Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' Failure1Action' , $Name , $Failure1Action , $serviceResource.failure1Action )
730
- return $false
731
- }
701
+ # Check the failure actions collection
702
+ if ($PSBoundParameters.ContainsKey (' FailureActionsCollection' )) {
703
+ $inSync = $true
704
+ if ($FailureActionsCollection.count -ne $serviceResource.FailureActionsCollection.count ) {
705
+ Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' FailureActionsCollection.count' , $Name , $FailureActionsCollection.count , $serviceResource.FailureActionsCollection.count )
706
+ return $false
707
+ }
732
708
733
- # Check failure 1 delay
734
- if ($PSBoundParameters.ContainsKey (' Failure1Delay' ) -and $Failure1Delay -ine $serviceResource.failure1Delay )
735
- {
736
- Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' Failure1Delay' , $Name , $Failure1Delay , $serviceResource.failure1Delay )
737
- return $false
738
- }
709
+ foreach ($actionIndex in (0 .. ($FailureActionsCollection.count - 1 ))) {
710
+ $parameterAction = $FailureActionsCollection [$actionIndex ]
711
+ $serviceResourceAction = $serviceResource.FailureActionsCollection [$actionIndex ]
739
712
740
- # Check the failure 2 action
741
- if ($PSBoundParameters.ContainsKey (' Failure2Action' ) -and $Failure2Action -ine $serviceResource.failure2Action )
742
- {
743
- Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' Failure2Action' , $Name , $Failure2Action , $serviceResource.failure2Action )
744
- return $false
745
- }
713
+ if ($parameterAction.type -ne $serviceResourceAction.type ) {
714
+ Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f " FailureActionsCollection Action $actionIndex type" , $Name , $parameterAction.type , $serviceResourceAction.type )
715
+ $inSync = $false
716
+ }
746
717
747
- # Check failure 2 delay
748
- if ($PSBoundParameters.ContainsKey (' Failure2Delay' ) -and $Failure2Delay -ine $serviceResource.failure2Delay )
749
- {
750
- Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' Failure2Delay' , $Name , $Failure2Delay , $serviceResource.failure2Delay )
751
- return $false
752
- }
718
+ if ($parameterAction.delaySeconds -ne $serviceResourceAction.delaySeconds ) {
719
+ Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f " FailureActionsCollection Action $actionIndex delaySeconds" , $Name , $parameterAction.delaySeconds , $serviceResourceAction.delaySeconds )
720
+ $inSync = $false
721
+ }
722
+ }
753
723
754
- # Check the failure 3 action
755
- if ($PSBoundParameters.ContainsKey (' Failure3Action' ) -and $Failure3Action -ine $serviceResource.failure3Action )
756
- {
757
- Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' Failure3Action' , $Name , $Failure3Action , $serviceResource.failure3Action )
758
- return $false
724
+ if (-not $inSync ) {
725
+ return $inSync
726
+ }
759
727
}
760
728
761
- # Check failure 3 delay
762
- if ($PSBoundParameters.ContainsKey (' Failure3Delay' ) -and $Failure3Delay -ine $serviceResource.failure3Delay )
763
- {
764
- Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f ' Failure3Delay' , $Name , $Failure3Delay , $serviceResource.failure3Delay )
765
- return $false
766
- }
767
729
}
768
730
769
731
return $true
@@ -2029,9 +1991,7 @@ function Get-ServiceFailureActions {
2029
1991
failureActionCount = $null
2030
1992
failureCommand = $null
2031
1993
rebootMessage = $null
2032
- failureAction1 = @ {actionType = $null ; delay = $null }
2033
- failureAction2 = @ {actionType = $null ; delay = $null }
2034
- failureAction3 = @ {actionType = $null ; delay = $null }
1994
+ ActionsCollection = $null
2035
1995
}
2036
1996
2037
1997
if ($registryData.GetvalueNames () -match ' FailureCommand' ) {
@@ -2048,62 +2008,87 @@ function Get-ServiceFailureActions {
2048
2008
2049
2009
# The first four bytes represent the Reset Period. The bytes are little endian
2050
2010
# so they are reversed, converted to hex, and then cast to an integer.
2051
- $failureActions.resetPeriodSeconds = Convert-RegistryBinaryValueToInt - Bytes $failureActionsBinaryData - Offset 0
2011
+ $failureActions.resetPeriodSeconds = Get-FailureActionsProperty - PropertyName ResetPeriodSeconds - Bytes $failureActionsBinaryData
2052
2012
2053
2013
# Next found bytes indicate the presence of a reboot message in case one of the chosen failure actions is
2054
2014
# SC_ACTION_REBOOT. The actual value of the message is stored in the 'RebootMessage' property
2055
- $failureActions.hasRebootMessage = Convert-RegistryBinaryValueToInt - Bytes $failureActionsBinaryData - Offset 1
2015
+ $failureActions.hasRebootMessage = Get-FailureActionsProperty - PropertyName HasRebootMsg - Bytes $failureActionsBinaryData
2056
2016
2057
2017
# The next four bytes indicate whether a failure action run command exists. This command
2058
2018
# would be run in the case one of the failure actions chosen is SC_ACTION_RUN_COMMAND
2059
2019
# If this value is true then the actual command string is stored in a different value.
2060
- $failureActions.hasFailureCommand = Convert-RegistryBinaryValueToInt - Bytes $failureActionsBinaryData - Offset 2
2020
+ $failureActions.hasFailureCommand = Get-FailureActionsProperty - PropertyName HasFailureCommand - Bytes $failureActionsBinaryData
2061
2021
2062
2022
# These four bytes give the count of how many reboot failure actions have been defined.
2063
2023
# Up to three actions may be defined.
2064
- $failureActions.failureActionCount = Convert-RegistryBinaryValueToInt - Bytes $failureActionsBinaryData - Offset 3
2024
+ $failureActions.failureActionCount = Get-FailureActionsProperty - PropertyName FailureActionCount - Bytes $failureActionsBinaryData
2065
2025
2066
2026
if ($failureActions.failureActionCount -gt 0 ) {
2067
- foreach ($item in 1 .. $failureActions.failureActionCount ) {
2068
-
2069
- # Manually counting the array offset is easier than implementing some weird array arithmetic.
2070
- $offset = switch ($item ) {
2071
- 1 { 5 }
2072
- 2 { 7 }
2073
- 3 { 9 }
2074
- Default {-1 }
2075
- }
2076
- # Occasionaly a service will store an array acount greater than 3. As far as I can tell
2077
- # A count greater than 3 has no meaning, so we only support 3.
2078
- if ($offset -lt 0 ) { break }
2079
- $failureActions ." failureAction$item " .actionType = [ACTION _TYPE ](Convert-RegistryBinaryValueToInt - Bytes $failureActionsBinaryData - offset $offset )
2080
- $failureActions ." failureAction$item " .delay = Convert-RegistryBinaryValueToInt - Bytes $failureActionsBinaryData - offset ($offset + 1 )
2081
- }
2027
+ $failureActions.ActionsCollection = Get-FailureActionCollection - Bytes $failureActionsBinaryData - ActionsCount $failureActions.failureActionCount
2082
2028
}
2083
2029
}
2084
2030
2085
2031
$failureActions
2086
2032
}
2087
2033
}
2088
2034
2089
- function Convert-RegistryBinaryValueToInt
2035
+ function Get-FailureActionsProperty
2036
+ {
2037
+ [CmdletBinding ()]
2038
+ param (
2039
+ [Parameter (Mandatory )]
2040
+ [ValidateSet (' ResetPeriodSeconds' , ' HasRebootMsg' , ' HasFailureCommand' , ' FailureActionCount' )]
2041
+ [System.String ]
2042
+ $PropertyName ,
2043
+ [Parameter (Mandatory )]
2044
+ [System.Byte []]
2045
+ $Bytes
2046
+ )
2047
+
2048
+ process {
2049
+ $byteRange = switch ($PropertyName ) {
2050
+ ResetPeriodSeconds { 0 .. 3 }
2051
+ HasRebootMsg { 4 .. 7 }
2052
+ HasFailureCommand { 8 .. 11 }
2053
+ FailureActionCount { 12 .. 15 }
2054
+ Default {}
2055
+ }
2056
+
2057
+ [System.BitConverter ]::ToInt32($Bytes [$byteRange ], 0 )
2058
+ }
2059
+ }
2060
+
2061
+ function Get-FailureActionCollection
2090
2062
{
2091
2063
[CmdletBinding ()]
2092
2064
param (
2093
2065
[Parameter (Mandatory )]
2094
- [byte []]
2066
+ [System.Byte []]
2095
2067
$Bytes ,
2096
2068
[Parameter (Mandatory )]
2097
- [int ]
2098
- $Offset ,
2099
- [int ]
2100
- $Size = 4
2069
+ [System.UInt32 ]
2070
+ $ActionsCount
2101
2071
)
2102
2072
2103
2073
process {
2104
- $lastByte = (($offset + 1 ) * 4 ) - 1
2105
- $firstByte = $lastbyte - ($size - 1 )
2106
- # Bytes in the registry are little endian, so we reverse them before conversion.
2107
- [int ]" 0x$ ( ($bytes [$lastByte .. $firstByte ] | % {" {0:x}" -f $_ }) -join ' ' | out-string ) "
2074
+ $actionsCollection = New-Object System.Collections.Generic.List[PSObject ]
2075
+
2076
+ foreach ($action in 0 .. ($ActionsCount - 1 )) {
2077
+
2078
+ # The structure of the _SERVICE_FAILURE_ACTIONS struct encoded in this registry key
2079
+ # dictates that the array of _SC_ACTION structs will always start at byte 20.
2080
+ # The 8 is because each _SC_ACTION is a 8 byte struct.
2081
+ $actionTypeByteRange = (20 + (8 * $action )).. (20 + (8 * $action ) + 3 )
2082
+ $actionDelayByteRange = (20 + (8 * $action ) + 4 ).. (20 + (8 * $action ) + 7 )
2083
+
2084
+ $currentAction = [PSCustomObject ]@ {
2085
+ type = [ACTION _TYPE ]([System.BitConverter ]::ToInt32($Bytes [$actionTypeByteRange ], 0 ))
2086
+ delaySeconds = [System.BitConverter ]::ToInt32($Bytes [$actionDelayByteRange ], 0 )
2087
+ }
2088
+
2089
+ $actionsCollection.Add ($currentAction ) | Out-Null
2090
+ }
2091
+
2092
+ $actionsCollection
2108
2093
}
2109
2094
}
0 commit comments