Skip to content

Commit 30d3e31

Browse files
committed
[ServiceManager] Add Failure Actions
1 parent 95f5649 commit 30d3e31

4 files changed

Lines changed: 258 additions & 184 deletions

File tree

Elements/ServiceManagement/WindowsService.vb

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,44 @@
2626
Critical = 3
2727
End Enum
2828

29+
Class ServiceFailureActions
30+
Public Property FirstFailure As ServiceFailureAction
31+
Public Property FirstDelayInMillis As Long
32+
Public Property SecondFailure As ServiceFailureAction
33+
Public Property SecondDelayInMillis As Long
34+
Public Property SubsequentFailure As ServiceFailureAction
35+
Public Property SubsequentDelaysInMillis As Long
36+
Public Property ResetDelayInSeconds As Integer
37+
38+
Public Sub New()
39+
FirstFailure = ServiceFailureAction.NoAction
40+
FirstDelayInMillis = 0
41+
SecondFailure = ServiceFailureAction.NoAction
42+
SecondDelayInMillis = 0
43+
SubsequentFailure = ServiceFailureAction.NoAction
44+
SubsequentDelaysInMillis = 0
45+
ResetDelayInSeconds = 0
46+
End Sub
47+
48+
Public Sub New(firstFail As ServiceFailureAction, firstDelay As Long, secondFail As ServiceFailureAction, secondDelay As Long, subsequentFail As ServiceFailureAction, subsequentDelays As Long, resetDelays As Long)
49+
FirstFailure = firstFail
50+
FirstDelayInMillis = If(firstDelay >= 0, firstDelay, 0)
51+
SecondFailure = secondFail
52+
SecondDelayInMillis = If(secondDelay >= 0, secondDelay, 0)
53+
SubsequentFailure = subsequentFail
54+
SubsequentDelaysInMillis = If(subsequentDelays >= 0, subsequentDelays, 0)
55+
ResetDelayInSeconds = If(resetDelays >= 0, resetDelays, 0)
56+
End Sub
57+
End Class
58+
59+
Enum ServiceFailureAction As Integer
60+
Unknown = -1
61+
NoAction = 0
62+
RestartService = 1
63+
RestartComputer = 2
64+
RunProgram = 3
65+
End Enum
66+
2967
Public Property Name As String
3068
Public Property DisplayName As String
3169
Public Property Description As String
@@ -37,8 +75,9 @@
3775
Public Property ErrorControl As ServiceErrorControl
3876
Public Property RequiredPrivileges As New List(Of NTSecurityPrivilegeConstant)
3977
Public Property Dependencies As String()
78+
Public Property FailureActions As ServiceFailureActions
4079

41-
Public Sub New(name As String, displayName As String, description As String, objectName As String, imagePath As String, startType As ServiceStartType, delayedStart As Boolean, type As ServiceType, errorControl As ServiceErrorControl, ntPrivileges As List(Of NTSecurityPrivilegeConstant), deps As String())
80+
Public Sub New(name As String, displayName As String, description As String, objectName As String, imagePath As String, startType As ServiceStartType, delayedStart As Boolean, type As ServiceType, errorControl As ServiceErrorControl, ntPrivileges As List(Of NTSecurityPrivilegeConstant), deps As String(), failureActions As ServiceFailureActions)
4281
Me.Name = name
4382
Me.DisplayName = displayName
4483
Me.Description = description
@@ -50,6 +89,7 @@
5089
Me.ErrorControl = errorControl
5190
Me.RequiredPrivileges = ntPrivileges
5291
Me.Dependencies = deps
92+
Me.FailureActions = failureActions
5393
End Sub
5494

5595
Public Function StartTypeToString() As String
@@ -101,4 +141,18 @@
101141
End Select
102142
End Function
103143

144+
Public Function FailureActionToString(FailureAction As ServiceFailureAction) As String
145+
Select Case FailureAction
146+
Case ServiceFailureAction.NoAction
147+
Return "Take no action"
148+
Case ServiceFailureAction.RestartService
149+
Return "Restart Service"
150+
Case ServiceFailureAction.RestartComputer
151+
Return "Restart Computer"
152+
Case ServiceFailureAction.RunProgram
153+
Return "Run a program"
154+
End Select
155+
Return ""
156+
End Function
157+
104158
End Class

Elements/ServiceManagement/WindowsServiceHelper.vb

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ Module WindowsServiceHelper
254254
serviceType As WindowsService.ServiceType = WindowsService.ServiceType.Unknown,
255255
serviceErrorControl As WindowsService.ServiceErrorControl = WindowsService.ServiceErrorControl.Unknown,
256256
serviceRequiredPrivilegesString() As String = New String() {},
257-
serviceDependencies() As String = New String() {}
257+
serviceDependencies() As String = New String() {},
258+
serviceFailActionByteArr() As Byte = New Byte() {}
258259
Using ServiceInfoRk As RegistryKey = Registry.LocalMachine.OpenSubKey(String.Format("zSYS\ControlSet{0}\Services\{1}", DefaultControlSet.ToString().PadLeft(3, "0"), ServiceName), False)
259260
' We explicitly tell that we want to grab the raw data without env var expansion because REG_EXPAND_SZ values
260261
' are still string values, but with unexpanded environment variables. If the variable exists in the target system,
@@ -286,6 +287,7 @@ Module WindowsServiceHelper
286287
serviceRequiredPrivilegesString = ServiceInfoRk.GetValue("RequiredPrivileges", New String() {})
287288
' Same goes for dependencies
288289
serviceDependencies = ServiceInfoRk.GetValue("DependOnService", New String() {})
290+
serviceFailActionByteArr = ServiceInfoRk.GetValue("FailureActions", New Byte() {})
289291

290292
Dim serviceRequiredPrivilegeList As New List(Of NTSecurityPrivilegeConstant)
291293

@@ -311,7 +313,8 @@ Module WindowsServiceHelper
311313
serviceType,
312314
serviceErrorControl,
313315
serviceRequiredPrivilegeList,
314-
serviceDependencies))
316+
serviceDependencies,
317+
ParseFailureActionByteArray(serviceFailActionByteArr)))
315318
End Using
316319
Next
317320
Catch ex As Exception
@@ -325,4 +328,51 @@ Module WindowsServiceHelper
325328
Return serviceList
326329
End Function
327330

331+
Private Function ParseFailureActionByteArray(FailureActions As Byte()) As WindowsService.ServiceFailureActions
332+
Dim scFailure As WindowsService.ServiceFailureActions = New WindowsService.ServiceFailureActions()
333+
Dim firstFail As WindowsService.ServiceFailureAction = WindowsService.ServiceFailureAction.Unknown,
334+
secondFail As WindowsService.ServiceFailureAction = WindowsService.ServiceFailureAction.Unknown,
335+
subsequentFails As WindowsService.ServiceFailureAction = WindowsService.ServiceFailureAction.Unknown
336+
Dim firstDelay As Long = 0,
337+
secondDelay As Long = 0,
338+
subsequentDelay As Long = 0
339+
Dim resetDelay As Integer = 0
340+
341+
If FailureActions.Count >= 1 Then
342+
Try
343+
resetDelay = GetDelay(FailureActions.Skip(0).Take(4).ToArray())
344+
345+
' We have to get the number of byte elements twice because undefined failure measures
346+
' cause our byte array to be smaller than expected, therefore causing indexes out of bounds.
347+
firstFail = FailureActions(20)
348+
firstDelay = GetDelay(FailureActions.Skip(24).Take(4).ToArray())
349+
If FailureActions.Count > 28 Then
350+
' We have defined second failure measures
351+
secondFail = FailureActions(28)
352+
secondDelay = GetDelay(FailureActions.Skip(32).Take(4).ToArray())
353+
End If
354+
If FailureActions.Count > 36 Then
355+
' We have defined subsequent failure measures
356+
subsequentFails = FailureActions(36)
357+
subsequentDelay = GetDelay(FailureActions.Skip(40).Take(4).ToArray())
358+
End If
359+
Catch ex As Exception
360+
361+
End Try
362+
363+
scFailure = New WindowsService.ServiceFailureActions(firstFail, firstDelay, secondFail, secondDelay, subsequentFails, subsequentDelay, resetDelay)
364+
End If
365+
Return scFailure
366+
End Function
367+
368+
Private Function GetDelay(ByteArray As Byte()) As Long
369+
Dim binary As String = ""
370+
371+
For x = ByteArray.Length - 1 To 0 Step -1
372+
binary &= Convert.ToString(ByteArray(x), 2).PadLeft(8, "0"c)
373+
Next
374+
375+
Return Convert.ToInt32(binary, 2)
376+
End Function
377+
328378
End Module

0 commit comments

Comments
 (0)