@@ -89,25 +89,20 @@ function Get-TargetResource
8989 $serviceFailureActions = Get-ServiceFailureActions - Service $service.Name
9090
9191 $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
111106 }
112107 }
113108 else
@@ -529,28 +524,8 @@ function Test-TargetResource
529524 $FailureCommand ,
530525
531526 [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 ,
554529
555530 [Parameter ()]
556531 [ValidateNotNull ()]
@@ -723,47 +698,34 @@ function Test-TargetResource
723698 return $false
724699 }
725700
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+ }
732708
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 ]
739712
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+ }
746717
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.delay -ne $serviceResourceAction.delay ) {
719+ Write-Verbose - Message ($script :localizedData.ServicePropertyDoesNotMatch -f " FailureActionsCollection Action $actionIndex delay" , $Name , $parameterAction.delay , $serviceResourceAction.delay )
720+ $inSync = $false
721+ }
722+ }
753723
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+ }
759727 }
760728
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- }
767729 }
768730
769731 return $true
@@ -2029,9 +1991,7 @@ function Get-ServiceFailureActions {
20291991 failureActionCount = $null
20301992 failureCommand = $null
20311993 rebootMessage = $null
2032- failureAction1 = @ {actionType = $null ; delay = $null }
2033- failureAction2 = @ {actionType = $null ; delay = $null }
2034- failureAction3 = @ {actionType = $null ; delay = $null }
1994+ ActionsCollection = $null
20351995 }
20361996
20371997 if ($registryData.GetvalueNames () -match ' FailureCommand' ) {
@@ -2048,62 +2008,87 @@ function Get-ServiceFailureActions {
20482008
20492009 # The first four bytes represent the Reset Period. The bytes are little endian
20502010 # 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
20522012
20532013 # Next found bytes indicate the presence of a reboot message in case one of the chosen failure actions is
20542014 # 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
20562016
20572017 # The next four bytes indicate whether a failure action run command exists. This command
20582018 # would be run in the case one of the failure actions chosen is SC_ACTION_RUN_COMMAND
20592019 # 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
20612021
20622022 # These four bytes give the count of how many reboot failure actions have been defined.
20632023 # 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
20652025
20662026 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
20822028 }
20832029 }
20842030
20852031 $failureActions
20862032 }
20872033}
20882034
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
20902062{
20912063 [CmdletBinding ()]
20922064 param (
20932065 [Parameter (Mandatory )]
2094- [byte []]
2066+ [System.Byte []]
20952067 $Bytes ,
20962068 [Parameter (Mandatory )]
2097- [int ]
2098- $Offset ,
2099- [int ]
2100- $Size = 4
2069+ [System.UInt32 ]
2070+ $ActionsCount
21012071 )
21022072
21032073 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+ delay = [System.BitConverter ]::ToInt32($Bytes [$actionDelayByteRange ], 0 )
2087+ }
2088+
2089+ $actionsCollection.Add ($currentAction ) | Out-Null
2090+ }
2091+
2092+ $actionsCollection
21082093 }
21092094}
0 commit comments