-
Notifications
You must be signed in to change notification settings - Fork 0
/
ManageWindowsServices.ps1
336 lines (314 loc) · 10.3 KB
/
ManageWindowsServices.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
[CmdletBinding()]
param()
Trace-VstsEnteringInvocation $MyInvocation
Write-Host "##################################################################################"
# Output the logo.
"Set of Task to Manage Window Service"
Write-Host "##################################################################################"
#####################################################################################
Import-VstsLocStrings "$PSScriptRoot\task.json"
# Get the inputs.
[string]$Action =Get-VstsInput -Name Action
[string]$ServiceName = Get-VstsInput -Name ServiceName
[string]$ServicesName = Get-VstsInput -Name ServicesName
[string]$BinPath = Get-VstsInput -Name BinPath
[string]$User = Get-VstsInput -Name User
[string]$Password = Get-VstsInput -Name Password
[string]$StartMode = Get-VstsInput -Name StartMode
[string]$DisplayName = Get-VstsInput -Name DisplayName
[string]$Description = Get-VstsInput -Name Description
##################################################################
# Output execution parameters.
Write-Host "####################################################"
" 1. Action: $Action"
if (![string]::IsNullOrEmpty($ServiceName))
{
" 2. Service Name: $ServiceName"
}
else
{
" 2. Services Name: $ServicesName"
}
" 3. Binary Path: $BinPath"
" 4. User: $User"
" 5. Start Mode: $StartMode"
" 6. Display Name: $DisplayName"
" 7. Description: $Description"
if (![string]::IsNullOrEmpty($Password))
{
" 8. Password: Is specified"
}
else
{
" 8. Password: Is not specified"
}
Write-Host "#####################################################"
##########################################################################
# Initialize the default script exit code.
$exitCode = 1
#########################################################################
##################################################################################
# Validation of the parameters
$Action = $Action.ToLower()
if (($Action -eq "create" -or $Action -eq "config") -and ![string]::IsNullOrEmpty($StartMode))
{
if ($StartMode.ToLower() -ne "automatic" -and
$StartMode.ToLower() -ne "manual" -and
$StartMode.ToLower() -ne "disabled")
{
$(throw "The Start mode specified is not recognized. The allowed choices are: Automatic, Manual or Disabled.")
}
}
##################################################################################
# Process the action
if ($Action -eq "create")
{
# Get the service Name.
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($service -ne $null)
{
$(throw "The service to create already exists.")
}
#Build the parameters needed to create the service
$arguments = New-Object System.Collections.Hashtable
# Service Name
$arguments.Add("Name", $ServiceName)
# Binary file path (cannot be modified, so only for create)
if (![string]::IsNullOrEmpty($BinPath))
{
$arguments.Add("BinaryPathName", $BinPath)
}
else
{
$(throw "The Binary path must be specified when creating a service.")
}
# Credentials
if (![string]::IsNullOrEmpty($user))
{
if ([string]::IsNullOrEmpty($Password))
{
$securedPassword = new-object System.Security.SecureString
}
else
{
$securedPassword = ConvertTo-SecureString $Password -AsPlainText -Force
}
$credentials = New-Object System.Management.Automation.PSCredential($User, $securedPassword)
$arguments.Add("Credential", $credentials)
}
# Start mode
if (![string]::IsNullOrEmpty($StartMode))
{
$arguments.Add("StartupType", $StartMode)
}
# Display name
if (![string]::IsNullOrEmpty($DisplayName))
{
$arguments.Add("DisplayName", $DisplayName)
}
# Description
if (![string]::IsNullOrEmpty($Description))
{
$arguments.Add("Description", $Description)
}
#Create the service
New-Service @arguments
# Ensure the service was created successfully
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($service -eq $null)
{
$(throw "The creation of the service failed.")
}
}
# Configure a windows service
elseif ($Action -eq "config")
{
# We get the service.
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
$wmiService = gwmi win32_service -filter "name='$ServiceName'" -ErrorAction SilentlyContinue
if ($service -eq $null -or $wmiService -eq $null)
{
$(throw "The service to configure does not exists.")
}
# If the service is started, stop it.
if ($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped)
{
$status = & "sc.exe" stop "$ServiceName"
}
$arguments = New-Object System.Collections.Hashtable
# Service Name
$arguments.Add("Name", $ServiceName)
# Start mode
if (![string]::IsNullOrEmpty($StartMode))
{
$arguments.Add("StartupType", $StartMode)
}
# Display name
if (![string]::IsNullOrEmpty($DisplayName))
{
$arguments.Add("DisplayName", $DisplayName)
}
# Description
if (![string]::IsNullOrEmpty($Description))
{
$arguments.Add("Description", $Description)
}
Set-Service @arguments -ErrorVariable modificationStatus
if ($modificationStatus.Count > 0)
{
$(throw "The service could not be modified (Set-Service).")
}
# Binary file path (cannot be modified, so only for create)
$binPathArg = $null
if (![string]::IsNullOrEmpty($BinPath))
{
$binPathArg = $BinPath
}
# Credentials
$userArg = $null
$passwordArg = $null
if (![string]::IsNullOrEmpty($user))
{
$userArg = $User
$passwordArg = $Password
}
$exitCode = $wmiService.change($null,$binPathArg,$null,$null,$null,$null,$userArg,$passwordArg).ReturnValue
if ($exitCode -gt 0)
{
switch ($exitCode)
{
1 { "Not Supported" }
2 { "Access Denied" }
3 { "Dependent Services Running" }
4 { "Invalid Service Control" }
5 { "Service Cannot Accept Control" }
6 { "Service Not Active" }
7 { "Service Request Timeout" }
8 { "Unknown Failure" }
9 { "Path Not Found" }
10 { "Service Already Running" }
11 { "Service Database Locked" }
12 { "Service Dependency Deleted" }
13 { "Service Dependency Failure" }
14 { "Service Disabled" }
15 { "Service Logon Failure" }
16 { "Service Marked For Deletion" }
17 { "Service No Thread" }
18 { "Status Circular Dependency" }
19 { "Status Duplicate Name" }
20 { "Status Invalid Name" }
21 { "Status Invalid Parameter" }
22 { "Status Invalid Service Account" }
23 { "Status Service Exists" }
24 { "Service Already Paused" }
Default { "Unknown return status" }
}
$(throw "The service could not be configured (gwmi.change).")
}
}
# delete a Windows service
elseif ($Action -eq "delete")
{
#Get The service Name
$name=$ServicesName.Split("`r`n")
foreach($ServiceName in $name)
{
"Working with service: $ServiceName"
#If the service exists, we first stop it to avoid "Marked for deletion" problems
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($service -eq $null)
{
$(throw "The specified $ServiceName doesnot exist.")
}
"Stop the service: $ServiceName before deletion"
$status = & "sc.exe" stop "$ServiceName"
"Stop status : $status"
Start-Sleep -Seconds 2
$status = & "sc.exe" $Action "$ServiceName"
"Delete status : $status"
#Ensure the service was deleted successfully
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($service -ne $null)
{
$(throw "The deletion of the service failed.")
}
else
{
$exitCode = 0
"Operation Done service: $ServiceName"
}
}
}
elseif (($Action -eq "start") -or ($Action -eq "stop") -or ($Action -eq "restart"))
{
#Get The service Name
$name=$ServicesName.Split("`r`n")
foreach($ServiceName in $name)
{
"Working with service: $ServiceName"
#Ensure the service exists
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($service -eq $null)
{
$(throw "The service $ServiceName does not exists.")
}
if (($Action -eq "stop") -or ($Action -eq "restart"))
{
#Stop the service
$status = & "sc.exe" stop "$ServiceName"
if ($status.Count -gt 2 -and
$status[0].ToLower().Contains("[sc] controlservice failed") -and
-not $status[2].ToLower().Contains("the service has not been started"))
{
"Stop status : $status"
$(throw "The service failed to stop.")
}
#Refresh the service status and ensure it is stopped
$service.Refresh()
while ($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped)
{
Start-Sleep -Seconds 2
$service.Refresh()
}
"Operation Done service: $ServiceName"
}
if (($Action -eq "start") -or ($Action -eq "restart"))
{
#Start the service
$status = & "sc.exe" start "$ServiceName"
if ($status.Count -gt 2 -and
$status[0].ToLower().Contains("[sc] startservice failed") -and
-not $status[2].ToLower().Contains("an instance of the service is already running"))
{
"Start status : $status"
if ($status[2].ToLower().Contains("the service did not start due to a logon failure."))
{
"Possible reasons for this error can be the credentials entered are not correct (wrong username or password) or the user does not have the right to start a service (Log on as a service)."
}
$(throw "The service failed to start.")
}
#Refresh the service status and ensure it is started
$service.Refresh()
while ($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Running)
{
Start-Sleep -Seconds 2
$service.Refresh()
}
"Operation Done service: $ServiceName"
}
}
} #Closing else if loop
else
{
$(throw "The action specified is not supported.")
}
$exitCode = 0
##################################################################################
# Indicate the resulting exit code to the calling process.
if ($exitCode -gt 0)
{
"`nERROR: Operation failed with error code $exitCode."
Write-VstsSetResult -Result 'Failed' -Message "ERROR: Operation failed" -DoNotThrow
}
"`nDone."
exit $exitCode