diff --git a/source/DSCResources/DSC_xServiceResource/DSC_xServiceResource.psm1 b/source/DSCResources/DSC_xServiceResource/DSC_xServiceResource.psm1 index 000fa333b..a4beb4c9b 100644 --- a/source/DSCResources/DSC_xServiceResource/DSC_xServiceResource.psm1 +++ b/source/DSCResources/DSC_xServiceResource/DSC_xServiceResource.psm1 @@ -2145,57 +2145,58 @@ function Get-ServiceFailureActions { $Service ) process { - $registryData = Get-Item -Path HKLM:\SYSTEM\CurrentControlSet\Services\$service - - $failureActions = [PSCustomObject]@{ - resetPeriodSeconds = $null - hasRebootMessage = $null - hasFailureCommand = $null - failureActionCount = $null - failureCommand = $null - rebootMessage = $null - actionsCollection = $null - $FailureActionsOnNonCrashFailures = $false - } + if($registryData = Get-Item -Path HKLM:\SYSTEM\CurrentControlSet\Services\$service -ErrorAction SilentlyContinue) + { + $failureActions = [PSCustomObject]@{ + resetPeriodSeconds = $null + hasRebootMessage = $null + hasFailureCommand = $null + failureActionCount = $null + failureCommand = $null + rebootMessage = $null + actionsCollection = $null + FailureActionsOnNonCrashFailures = $false + } - if($registryData.GetvalueNames() -match 'FailureCommand') { - $failureActions.failureCommand = $registryData.GetValue('FailureCommand') - } + if($registryData.GetvalueNames() -match 'FailureCommand') { + $failureActions.failureCommand = $registryData.GetValue('FailureCommand') + } - if($registryData.GetValueNames() -match 'RebootMessage') { - $failureActions.rebootMessage = $registryData.GetValue('RebootMessage') - } + if($registryData.GetValueNames() -match 'RebootMessage') { + $failureActions.rebootMessage = $registryData.GetValue('RebootMessage') + } - if($registryData.GetvalueNames() -match 'FailureActionsOnNonCrashFailures') { - $failureActions.FailureActionsOnNonCrashFailures = [System.Boolean]$registryData.GetValue('FailureActionsOnNonCrashFailures') - } + if($registryData.GetvalueNames() -match 'FailureActionsOnNonCrashFailures') { + $failureActions.FailureActionsOnNonCrashFailures = [System.Boolean]$registryData.GetValue('FailureActionsOnNonCrashFailures') + } - if($registryData.GetValueNames() -match 'FailureActions') - { - $failureActionsBinaryData = $registryData.GetValue('FailureActions') + if($registryData.GetValueNames() -match 'FailureActions') + { + $failureActionsBinaryData = $registryData.GetValue('FailureActions') - # The first four bytes represent the Reset Period. - $failureActions.resetPeriodSeconds = Get-FailureActionsProperty -PropertyName ResetPeriodSeconds -Bytes $failureActionsBinaryData + # The first four bytes represent the Reset Period. + $failureActions.resetPeriodSeconds = Get-FailureActionsProperty -PropertyName ResetPeriodSeconds -Bytes $failureActionsBinaryData - # Next four bytes indicate the presence of a reboot message in case one of the chosen failure actions is - # SC_ACTION_REBOOT. The actual value of the message is stored in the 'RebootMessage' property - $failureActions.hasRebootMessage = Get-FailureActionsProperty -PropertyName HasRebootMsg -Bytes $failureActionsBinaryData + # Next four bytes indicate the presence of a reboot message in case one of the chosen failure actions is + # SC_ACTION_REBOOT. The actual value of the message is stored in the 'RebootMessage' property + $failureActions.hasRebootMessage = Get-FailureActionsProperty -PropertyName HasRebootMsg -Bytes $failureActionsBinaryData - # The next four bytes indicate whether a failure action run command exists. This command - # would be run in the case one of the failure actions chosen is SC_ACTION_RUN_COMMAND - # If this value is true then the actual command string is stored in the 'FailureCommand' property. - $failureActions.hasFailureCommand = Get-FailureActionsProperty -PropertyName HasFailureCommand -Bytes $failureActionsBinaryData + # The next four bytes indicate whether a failure action run command exists. This command + # would be run in the case one of the failure actions chosen is SC_ACTION_RUN_COMMAND + # If this value is true then the actual command string is stored in the 'FailureCommand' property. + $failureActions.hasFailureCommand = Get-FailureActionsProperty -PropertyName HasFailureCommand -Bytes $failureActionsBinaryData - # These four bytes give the count of how many reboot failure actions have been defined. - $failureActions.failureActionCount = Get-FailureActionsProperty -PropertyName FailureActionCount -Bytes $failureActionsBinaryData + # These four bytes give the count of how many reboot failure actions have been defined. + $failureActions.failureActionCount = Get-FailureActionsProperty -PropertyName FailureActionCount -Bytes $failureActionsBinaryData - if($failureActions.failureActionCount -gt 0) - { - $failureActions.ActionsCollection = Get-FailureActionCollection -Bytes $failureActionsBinaryData -ActionsCount $failureActions.failureActionCount + if($failureActions.failureActionCount -gt 0) + { + $failureActions.ActionsCollection = Get-FailureActionCollection -Bytes $failureActionsBinaryData -ActionsCount $failureActions.failureActionCount + } } - } - $failureActions + $failureActions + } } } diff --git a/tests/Unit/DSC_xServiceResource.Tests.ps1 b/tests/Unit/DSC_xServiceResource.Tests.ps1 index da6a5642d..1569a6d56 100644 --- a/tests/Unit/DSC_xServiceResource.Tests.ps1 +++ b/tests/Unit/DSC_xServiceResource.Tests.ps1 @@ -217,6 +217,44 @@ try $getTargetResourceResult.Dependencies | Should -Be $ExpectedValues.Dependencies } } + + if ($ExpectedValues.ContainsKey('ResetPeriodSeconds')) + { + it 'Should return the reset period in seconds' { + $getTargetResourceResult.resetPeriodSeconds | Should -Be $ExpectedValues.resetPeriodSeconds + } + } + + if ($ExpectedValues.ContainsKey('FailureCommand')) + { + it 'Should return the failure command' { + $getTargetResourceResult.failureCommand | Should -Be $ExpectedValues.FailureCommand + } + } + + if ($ExpectedValues.ContainsKey('RebootMessage')) + { + it 'Should return the reboot message' { + $getTargetResourceResult.rebootMessage | Should -Be $ExpectedValues.RebootMessage + } + } + + if ($ExpectedValues.ContainsKey('FailureActionsCollection')) + { + foreach ($index in 0..($ExpectedValues.failureActionsCollection.count - 1)) { + it "Should return the correct failure action for index $index" { + $getTargetResourceResult.failureActionsCollection[$index].type | Should -Be $ExpectedValues.FailureActionsCollection[$index].type + $getTargetResourceResult.failureActionsCollection[$index].delaySeconds | Should -Be $ExpectedValues.FailureActionsCollection[$index].delaySeconds + } + } + } + + if ($ExpectedValues.ContainsKey('FailureActionsOnNonCrashFailures')) + { + it 'Should return the failure actions on non crash failures flag' { + $getTargetResourceResult.failureActionsOnNonCrashFailures | Should -Be $ExpectedValues.failureActionsOnNonCrashFailures + } + } } Mock -CommandName 'Get-Service' -MockWith { } @@ -265,23 +303,43 @@ try DesktopInteract = $true } + $testServiceFailureActions = @{ + resetPeriodSeconds = 86400 + hasRebootMessage = 0 + hasFailureCommand = 0 + failureActionCount = 1 + failureCommand = $null + rebootMessage = $null + actionsCollection = @([PSCustomObject]@{ + type = 'RESTART' + delaySeconds = 30000 + }) + failureActionsOnNonCrashFailures = $true + } + Mock -CommandName 'Get-Service' -MockWith { return $testService } Mock -CommandName 'Get-ServiceCimInstance' -MockWith { return $testServiceCimInstance } Mock -CommandName 'ConvertTo-StartupTypeString' -MockWith { return $convertToStartupTypeStringResult } + Mock -CommandName 'Get-ServiceFailureActions' -MockWith { return $testServiceFailureActions } Test-GetTargetResourceDoesntThrow -GetTargetResourceParameters $getTargetResourceParameters -TestServiceCimInstance $testServiceCimInstance $expectedValues = @{ - Name = $getTargetResourceParameters.Name - Ensure = 'Present' - Path = $testServiceCimInstance.PathName - StartupType = $convertToStartupTypeStringResult - BuiltInAccount = $testServiceCimInstance.StartName - State = $testService.Status - DisplayName = $testService.DisplayName - Description = $testServiceCimInstance.Description - DesktopInteract = $testServiceCimInstance.DesktopInteract - Dependencies = [System.Object[]] $testService.ServicesDependedOn.Name + Name = $getTargetResourceParameters.Name + Ensure = 'Present' + Path = $testServiceCimInstance.PathName + StartupType = $convertToStartupTypeStringResult + BuiltInAccount = $testServiceCimInstance.StartName + State = $testService.Status + DisplayName = $testService.DisplayName + Description = $testServiceCimInstance.Description + DesktopInteract = $testServiceCimInstance.DesktopInteract + Dependencies = [System.Object[]] $testService.ServicesDependedOn.Name + ResetPeriodSeconds = $testServiceFailureActions.resetPeriodSeconds + FailureCommand = $testServiceFailureActions.failureCommand + RebootMessage = $testServiceFailureActions.rebootMessage + FailureActionsCollection = $testServiceFailureActions.actionsCollection + failureActionsOnNonCrashFailures = $testServiceFailureActions.failureActionsOnNonCrashFailures } Test-GetTargetResourceResult -GetTargetResourceParameters $getTargetResourceParameters -ExpectedValues $expectedValues @@ -307,23 +365,43 @@ try DesktopInteract = $false } + $testServiceFailureActions = @{ + resetPeriodSeconds = 86400 + hasRebootMessage = 0 + hasFailureCommand = 0 + failureActionCount = 1 + failureCommand = $null + rebootMessage = $null + actionsCollection = @([PSCustomObject]@{ + type = 'RESTART' + delaySeconds = 30000 + }) + failureActionsOnNonCrashFailures = $true + } + Mock -CommandName 'Get-Service' -MockWith { return $testService } Mock -CommandName 'Get-ServiceCimInstance' -MockWith { return $testServiceCimInstance } Mock -CommandName 'ConvertTo-StartupTypeString' -MockWith { return $convertToStartupTypeStringResult } + Mock -CommandName 'Get-ServiceFailureActions' -MockWith { return $testServiceFailureActions } Test-GetTargetResourceDoesntThrow -GetTargetResourceParameters $getTargetResourceParameters -TestServiceCimInstance $testServiceCimInstance $expectedValues = @{ - Name = $getTargetResourceParameters.Name - Ensure = 'Present' - Path = $testServiceCimInstance.PathName - StartupType = $convertToStartupTypeStringResult - BuiltInAccount = $expectedBuiltInAccountValue - State = $testService.Status - DisplayName = $testService.DisplayName - Description = $testServiceCimInstance.Description - DesktopInteract = $testServiceCimInstance.DesktopInteract - Dependencies = $null + Name = $getTargetResourceParameters.Name + Ensure = 'Present' + Path = $testServiceCimInstance.PathName + StartupType = $convertToStartupTypeStringResult + BuiltInAccount = $expectedBuiltInAccountValue + State = $testService.Status + DisplayName = $testService.DisplayName + Description = $testServiceCimInstance.Description + DesktopInteract = $testServiceCimInstance.DesktopInteract + Dependencies = $null + ResetPeriodSeconds = $testServiceFailureActions.resetPeriodSeconds + FailureCommand = $testServiceFailureActions.failureCommand + RebootMessage = $testServiceFailureActions.rebootMessage + FailureActionsCollection = $testServiceFailureActions.actionsCollection + failureActionsOnNonCrashFailures = $testServiceFailureActions.failureActionsOnNonCrashFailures } Test-GetTargetResourceResult -GetTargetResourceParameters $getTargetResourceParameters -ExpectedValues $expectedValues @@ -356,23 +434,43 @@ try DesktopInteract = $false } + $testServiceFailureActions = @{ + resetPeriodSeconds = 86400 + hasRebootMessage = 0 + hasFailureCommand = 0 + failureActionCount = 1 + failureCommand = $null + rebootMessage = $null + actionsCollection = @([PSCustomObject]@{ + type = 'RESTART' + delaySeconds = 30000 + }) + failureActionsOnNonCrashFailures = $true + } + Mock -CommandName 'Get-Service' -MockWith { return $testService } Mock -CommandName 'Get-ServiceCimInstance' -MockWith { return $testServiceCimInstance } Mock -CommandName 'ConvertTo-StartupTypeString' -MockWith { return $convertToStartupTypeStringResult } + Mock -CommandName 'Get-ServiceFailureActions' -MockWith { return $testServiceFailureActions } Test-GetTargetResourceDoesntThrow -GetTargetResourceParameters $getTargetResourceParameters -TestServiceCimInstance $testServiceCimInstance $expectedValues = @{ - Name = $getTargetResourceParameters.Name - Ensure = 'Present' - Path = $testServiceCimInstance.PathName - StartupType = $convertToStartupTypeStringResult - BuiltInAccount = $expectedBuiltInAccountValue - State = $testService.Status - DisplayName = $null - Description = $null - DesktopInteract = $testServiceCimInstance.DesktopInteract - Dependencies = [System.Object[]] $testService.ServicesDependedOn.Name + Name = $getTargetResourceParameters.Name + Ensure = 'Present' + Path = $testServiceCimInstance.PathName + StartupType = $convertToStartupTypeStringResult + BuiltInAccount = $expectedBuiltInAccountValue + State = $testService.Status + DisplayName = $null + Description = $null + DesktopInteract = $testServiceCimInstance.DesktopInteract + Dependencies = [System.Object[]] $testService.ServicesDependedOn.Name + ResetPeriodSeconds = $testServiceFailureActions.resetPeriodSeconds + FailureCommand = $testServiceFailureActions.failureCommand + RebootMessage = $testServiceFailureActions.rebootMessage + FailureActionsCollection = $testServiceFailureActions.actionsCollection + failureActionsOnNonCrashFailures = $testServiceFailureActions.failureActionsOnNonCrashFailures } Test-GetTargetResourceResult -GetTargetResourceParameters $getTargetResourceParameters -ExpectedValues $expectedValues @@ -442,10 +540,25 @@ try DesktopInteract = $false } + $testServiceFailureActions = @{ + resetPeriodSeconds = 86400 + hasRebootMessage = 0 + hasFailureCommand = 0 + failureActionCount = 1 + failureCommand = $null + rebootMessage = $null + actionsCollection = @([PSCustomObject]@{ + type = 'RESTART' + delaySeconds = 30000 + }) + failureActionsOnNonCrashFailures = $true + } + Mock -CommandName 'Get-Service' -MockWith { return $testService } Mock -CommandName 'Get-ServiceCimInstance' -MockWith { return $testServiceCimInstance } Mock -CommandName 'ConvertTo-StartupTypeString' -MockWith { return $convertToStartupTypeStringResult } Mock -CommandName 'Write-Warning' + Mock -CommandName 'Get-ServiceFailureActions' -MockWith { return $testServiceFailureActions } Test-GetTargetResourceDoesntThrow -GetTargetResourceParameters $getTargetResourceParameters -TestServiceCimInstance $testServiceCimInstance @@ -454,16 +567,21 @@ try } $expectedValues = @{ - Name = $getTargetResourceParameters.Name - Ensure = 'Present' - Path = $testServiceCimInstance.PathName - StartupType = $convertToStartupTypeStringResult - BuiltInAccount = $testServiceCimInstance.StartName - State = $testService.Status - DisplayName = $testService.DisplayName - Description = $testServiceCimInstance.Description - DesktopInteract = $testServiceCimInstance.DesktopInteract - Dependencies = [System.Object[]] ($testService.ServicesDependedOn | Where-Object -FilterScript {![System.String]::IsNullOrEmpty($_.Name)}).Name + Name = $getTargetResourceParameters.Name + Ensure = 'Present' + Path = $testServiceCimInstance.PathName + StartupType = $convertToStartupTypeStringResult + BuiltInAccount = $testServiceCimInstance.StartName + State = $testService.Status + DisplayName = $testService.DisplayName + Description = $testServiceCimInstance.Description + DesktopInteract = $testServiceCimInstance.DesktopInteract + Dependencies = [System.Object[]] ($testService.ServicesDependedOn | Where-Object -FilterScript {![System.String]::IsNullOrEmpty($_.Name)}).Name + ResetPeriodSeconds = $testServiceFailureActions.resetPeriodSeconds + FailureCommand = $testServiceFailureActions.failureCommand + RebootMessage = $testServiceFailureActions.rebootMessage + FailureActionsCollection = $testServiceFailureActions.actionsCollection + failureActionsOnNonCrashFailures = $testServiceFailureActions.failureActionsOnNonCrashFailures } Test-GetTargetResourceResult -GetTargetResourceParameters $getTargetResourceParameters -ExpectedValues $expectedValues