]> insang Git - wevape-lu1_pos.git/blob
f3c714bc6fd50bad10f8c42d599100feab4b0da0
[wevape-lu1_pos.git] /
1 data LocalizedData
2 {
3     # culture="en-US"
4     ConvertFrom-StringData @"
5 ServiceNotFound=Service '{0}' not found.
6 CannotStartAndDisable=Cannot start and disable a service.
7 CannotStopServiceSetToStartAutomatically=Cannot stop a service and set it to start automatically.
8 ServiceAlreadyStarted=Service '{0}' already started, no action required.
9 ServiceStarted=Service '{0}' started.
10 ServiceStopped=Service '{0}' stopped.
11 ErrorStartingService=Failure starting service '{0}'. Please check the path '{1}' provided for the service. Message: '{2}'
12 OnlyOneParameterCanBeSpecified=Only one of the following parameters can be specified: '{0}', '{1}'.
13 StartServiceWhatIf=Start Service
14 ServiceAlreadyStopped=Service '{0}' already stopped, no action required.
15 ErrorStoppingService=Failure stopping service '{0}'. Message: '{1}'
16 ErrorRetrievingServiceInformation=Failure retrieving information for service '{0}'. Message: '{1}'
17 ErrorSettingServiceCredential=Failure setting credentials for service '{0}'. Message: '{1}'
18 SetCredentialWhatIf=Set Credential
19 SetStartupTypeWhatIf=Set Start Type
20 ErrorSettingServiceStartupType=Failure setting start type for service '{0}'. Message: '{1}'
21 TestUserNameMismatch=User name for service '{0}' is '{1}'. It does not match '{2}.
22 TestStartupTypeMismatch=Startup type for service '{0}' is '{1}'. It does not match '{2}'.
23 MethodFailed=The '{0}' method of '{1}' failed with error code: '{2}'.
24 ErrorChangingProperty=Failed to change '{0}' property. Message: '{1}'
25 ErrorSetingLogOnAsServiceRightsForUser=Error granting '{0}' the right to log on as a service. Message: '{1}'.
26 CannotOpenPolicyErrorMessage=Cannot open policy manager
27 UserNameTooLongErrorMessage=User name is too long
28 CannotLookupNamesErrorMessage=Failed to lookup user name
29 CannotOpenAccountErrorMessage=Failed to open policy for user
30 CannotCreateAccountAccessErrorMessage=Failed to create policy for user
31 CannotGetAccountAccessErrorMessage=Failed to get user policy rights
32 CannotSetAccountAccessErrorMessage=Failed to set user policy rights
33 BinaryPathNotSpecified=Specify the path to the executable when trying to create a new service
34 ServiceAlreadyExists=The service '{0}' to create already exists
35 ServiceExistsSamePath=The service '{0}' to create already exists with path '{1}'
36 ServiceNotExists=The service '{0}' does not exist. Specify the path to the executable to create a new service
37 ErrorDeletingService=Error in deleting service '{0}'
38 ServiceDeletedSuccessfully=Service '{0}' Deleted Successfully
39 TryDeleteAgain=Wait for 2 milliseconds for a service to get deleted
40 WritePropertiesIgnored=Service '{0}' already exists. Write properties such as Status, DisplayName, Description, Dependencies will be ignored for existing services. 
41 "@
42 }
43
44 Import-LocalizedData  LocalizedData -filename MSFT_ServiceResource.strings.psd1
45 $EscapedLocalizedData = @{}
46 foreach( $key in $LocalizedData.Keys )
47 {
48     $EscapedLocalizedData.Add($key, $LocalizedData[$key].Replace('"','""'))
49 }
50 $LocalizedData = $EscapedLocalizedData
51 Import-Module "$PSScriptRoot\..\RunAsHelper.psm1"
52
53 <#
54 .Synopsis
55 Gets a service resource
56 #>
57 function Get-TargetResource
58 {
59     param
60     (
61         
62         [parameter(Mandatory = $true)]
63         [ValidateNotNullOrEmpty()]
64         [System.String]
65         $Name
66     )
67
68     $svc = GetServiceResource $Name
69     $svcWmi = GetWMIService $Name
70
71     return @{
72         Name=$svc.Name
73         StartupType=(NormalizeStartupType $svcWmi.StartMode).ToString()
74         BuiltInAccount=if($svcWmi.StartName -ieq "LocalSystem") {"LocalSystem"} `
75             elseif($svcWmi.StartName -ieq "NT Authority\NetworkService") {"NetworkService"} `
76             elseif($svcWmi.StartName -ieq "NT Authority\LocalService") {"LocalService"} else {$null}
77         State=$svc.Status.ToString()
78         Path=$svcWmi.PathName
79         DisplayName=$svc.DisplayName
80         Description=$svcWmi.Description
81         Dependencies=[string[]](@() + ($svc.ServicesDependedOn | %{$_.Name}))
82     }
83 }
84
85
86 <#
87 .Synopsis
88 Tests a service resource
89 #>
90 function Test-TargetResource
91 {
92     param
93     (
94         [parameter(Mandatory = $true)]
95         [ValidateNotNullOrEmpty()]
96         [System.String]
97         $Name,
98                 
99         [System.String]
100         [ValidateSet("Automatic", "Manual", "Disabled")]
101         $StartupType,
102
103         [System.String]
104         [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
105         $BuiltInAccount,
106
107         [System.Management.Automation.PSCredential]
108         [ValidateNotNull()]
109         $Credential,
110
111         [System.String]
112         [ValidateSet("Running", "Stopped")]
113         $State="Running",
114
115         [System.String]
116         [ValidateNotNullOrEmpty()]
117         $DisplayName,
118
119         [System.String]
120         [ValidateNotNullOrEmpty()]
121         $Description,
122
123         [System.String]
124         [ValidateNotNullOrEmpty()]
125         $Path,
126
127         [System.String[]]
128         [ValidateNotNullOrEmpty()]
129         $Dependencies, 
130
131         [System.String]
132         [ValidateSet("Present", "Absent")]
133         $Ensure="Present"
134     )
135
136     ValidateStartupType $Name $StartupType $State
137
138     $serviceExists = ServiceExists -Name $Name -Path $Path -ErrorAction SilentlyContinue
139     
140     if($Ensure -eq "Absent")
141     {
142         if($serviceExists)
143         {
144            return $false
145         }
146         return $true
147     }
148
149     if(!$serviceExists)
150     {
151         return $false;
152     }
153
154     $svc=GetServiceResource $Name
155
156     if($PSBoundParameters.ContainsKey("StartupType") -or $PSBoundParameters.ContainsKey("BuiltInAccount") -or $PSBoundParameters.ContainsKey("Credential"))
157     {
158         $svcWmi = GetWMIService $Name
159         
160         $getUserNameAndPasswordArgs=@{}
161         if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$getUserNameAndPasswordArgs.Add("BuiltInAccount",$BuiltInAccount)}
162         if($PSBoundParameters.ContainsKey("Credential")) {$null=$getUserNameAndPasswordArgs.Add("Credential",$Credential)}
163
164         $userName,$password=GetUserNameAndPassword @getUserNameAndPasswordArgs
165         if($userName -ne $null -and !(TestUserName $SvcWmi $userName))
166         {
167             write-verbose ($LocalizedData.TestUserNameMismatch -f $svcWmi.Name,$svcWmi.StartName,$userName)
168             return $false
169         }
170
171         if($PSBoundParameters.ContainsKey("StartupType") -and !(TestStartupType $SvcWmi $StartupType))
172         {
173             write-verbose ($LocalizedData.TestStartupTypeMismatch -f $svcWmi.Name,$svcWmi.StartMode,$StartupType)
174             return $false
175         }
176      }
177
178      return ($State -eq "Stopped" -and $svc.Status -eq "Stopped") -or ($svc.Status -eq "Running" -and $State -eq "Running")
179 }
180
181 <#
182 .Synopsis
183 Sets properties for a service resource
184 #>
185 function Set-TargetResource
186 {
187     [CmdletBinding(SupportsShouldProcess=$true)]
188     param
189     (
190         
191         [parameter(Mandatory = $true)]
192         [ValidateNotNullOrEmpty()]
193         [System.String]
194         $Name,
195
196         [System.String]
197         [ValidateSet("Automatic", "Manual", "Disabled")]
198         $StartupType,
199
200         [System.String]
201         [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
202         $BuiltInAccount,
203
204         [System.Management.Automation.PSCredential]
205         [ValidateNotNull()]
206         $Credential,
207
208         [System.String]
209         [ValidateSet("Running", "Stopped")]
210         $State="Running",
211
212         [System.String]
213         [ValidateNotNullOrEmpty()]
214         $DisplayName,
215
216         [System.String]
217         [ValidateNotNullOrEmpty()]
218         $Description,
219
220         [System.String]
221         [ValidateNotNullOrEmpty()]
222         $Path,
223    
224         [System.String[]]
225         [ValidateNotNullOrEmpty()]
226         $Dependencies,
227         
228         [System.String]
229         [ValidateSet("Present", "Absent")]
230         $Ensure="Present"
231     )
232
233     ValidateStartupType $Name $StartupType $State
234
235     if($Ensure -eq "Absent")
236     {
237         $svc = GetServiceResource $Name
238         StopService $svc
239         DeleteService $svc.Name
240         return
241     }
242
243     $serviceExists = ServiceExists -Name $Name -ErrorAction SilentlyContinue
244
245     if($PSBoundParameters.ContainsKey("Path") -and $serviceExists)
246     {
247         if(CompareServicePath -Path $Path -Name $Name)
248         {
249             ThrowInvalidArgumentError "ServiceExistsSamePath" ($LocalizedData.ServiceExistsSamePath -f $Name, $Path)
250         }
251         ThrowInvalidArgumentError "ServiceAlreadyExists" ($LocalizedData.ServiceAlreadyExists -f $Name)
252     }
253     elseif($PSBoundParameters.ContainsKey("Path") -and !$serviceExists)
254     {
255         $argumentsToNewService = @{}
256         $argumentsToNewService.Add("Name", $Name)
257         $argumentsToNewService.Add("BinaryPathName", $Path)
258         if($PSBoundParameters.ContainsKey("Credential"))
259         {
260            $argumentsToNewService.Add("Credential", $Credential)
261         }
262         if($PSBoundParameters.ContainsKey("StartupType"))
263         {
264            $argumentsToNewService.Add("StartupType", $StartupType)
265         }
266         if($PSBoundParameters.ContainsKey("DisplayName"))
267         {
268            $argumentsToNewService.Add("DisplayName", $DisplayName)
269         }
270         if($PSBoundParameters.ContainsKey("Description"))
271         {
272            $argumentsToNewService.Add("Description", $Description)
273         }
274         if($PSBoundParameters.ContainsKey("Dependencies"))
275         {
276            $argumentsToNewService.Add("DependsOn", $Dependencies)
277         }
278         try
279         {
280            New-Service @argumentsToNewService
281            $serviceIsNew = $true
282         }
283         catch
284         {
285            Write-Log ("Error creating service `"$($argumentsToNewService["Name"])`"", $_.Exception.Message)
286            throw $_
287         }
288     }
289     elseif(!$PSBoundParameters.ContainsKey("Path") -and !$serviceExists)
290     {
291        throw $LocalizedData.ServiceNotExists -f $Name
292     }
293             
294     $svc=GetServiceResource $Name
295
296     if(!$serviceIsNew)
297     {
298        Write-Verbose ($LocalizedData.WritePropertiesIgnored -f $Name) 
299     }
300
301     $writeWritePropertiesArguments=@{Name=$svc.name}
302     if($PSBoundParameters.ContainsKey("StartupType")) {$null=$writeWritePropertiesArguments.Add("StartupType",$StartupType)}
303     if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$writeWritePropertiesArguments.Add("BuiltInAccount",$BuiltInAccount)}
304     if($PSBoundParameters.ContainsKey("Credential")) {$null=$writeWritePropertiesArguments.Add("Credential",$Credential)}
305
306     WriteWriteProperties @writeWritePropertiesArguments
307
308     if($State -eq "Stopped")
309     {
310         # Ensure service is stopped
311         StopService $svc
312         return
313     }
314
315     # Default state of a newly created service is 'stopped'. If $State=Running, ensure service is started.
316     if($State -eq "Running")
317     {
318        StartService $svc
319     }
320 }
321
322 <#
323 .Synopsis
324 Validates if a service exist using the Name parameter
325 #>
326 function ServiceExists
327 {
328     param
329     (
330         [parameter(Mandatory = $true)]
331         [ValidateNotNullOrEmpty()]
332         [System.String]
333         $Name, 
334
335         [System.String]
336         $Path 
337     )
338
339     $service = Get-Service -Name $Name -ErrorAction SilentlyContinue
340     if($service -ne $null)
341     {
342         if($Path -ne $null -and $Path -ne '' -and !(CompareServicePath -Name $Name -Path $Path)){
343            return $false 
344         }
345         return $true
346     }
347     return $false
348 }
349
350 <#
351 .Synopsis
352 Compares path to the service path, if the service exists. Returns true when path is same as service path. 
353 #>
354 function CompareServicePath
355 {
356     param
357     (
358         [parameter(Mandatory = $true)]
359         [ValidateNotNullOrEmpty()]
360         [System.String]
361         $Path,
362
363         [parameter(Mandatory = $true)]
364         [ValidateNotNullOrEmpty()]
365         [System.String]
366         $Name
367     )
368     
369     $servicePath = (Get-CimInstance -Class win32_service | where {$_.Name -eq $Name}).PathName
370     $result = [string]::Compare($Path, $servicePath, [System.Globalization.CultureInfo]::CurrentUICulture)
371
372     if($result -ne 0)
373     {
374         return $false
375     }
376     return $true
377 }
378
379 <#
380 .Synopsis
381 Validates a StartupType against the State parameter
382 #>
383 function ValidateStartupType
384 {
385     param
386     (
387         [parameter(Mandatory = $true)]
388         [ValidateNotNullOrEmpty()]
389         [System.String]
390         $Name,
391
392         [System.String]
393         $StartupType,
394
395         [System.String]
396         [ValidateSet("Running", "Stopped")]
397         $State="Running"
398     )
399
400     if($StartupType -eq $null) {return}
401
402     if($State -eq "Stopped")
403     {
404         if($StartupType -eq "Automatic")
405         {
406             # State = Stopped conflicts with Automatic or Delayed
407             ThrowInvalidArgumentError "CannotStopServiceSetToStartAutomatically" ($LocalizedData.CannotStopServiceSetToStartAutomatically -f $Name)
408         }
409     }
410     else
411     {
412         if($StartupType -eq "Disabled")
413         {
414             # State = Running conflicts with Disabled
415             ThrowInvalidArgumentError "CannotStartAndDisable" ($LocalizedData.CannotStartAndDisable -f $Name)
416         }
417     }
418 }
419
420
421 <#
422 .Synopsis
423 Writes all write properties if not already correctly set, logging errors and respecting whatif
424 #>
425 function WriteWriteProperties
426 {
427     [CmdletBinding(SupportsShouldProcess=$true)]
428     param
429     (
430         [parameter(Mandatory = $true)]
431         [ValidateNotNull()]
432         $Name,
433
434         [System.String]
435         [ValidateSet("Automatic", "Manual", "Disabled")]
436         $StartupType,
437
438         [System.String]
439         [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
440         $BuiltInAccount,
441
442         [System.Management.Automation.PSCredential]
443         [ValidateNotNull()]
444         $Credential
445     )
446
447     if(!$PSBoundParameters.ContainsKey("StartupType") -and !$PSBoundParameters.ContainsKey("BuiltInAccount") -and !$PSBoundParameters.ContainsKey("Credential"))
448     {
449         return
450     }
451     
452     $svcWmi = GetWMIService $Name
453
454     $writeCredentialPropertiesArguments=@{"SvcWmi"=$svcWmi}
455     if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$writeCredentialPropertiesArguments.Add("BuiltInAccount",$BuiltInAccount)}
456     if($PSBoundParameters.ContainsKey("Credential")) {$null=$writeCredentialPropertiesArguments.Add("Credential",$Credential)}
457
458     WriteCredentialProperties @writeCredentialPropertiesArguments
459
460     $writeStartupArguments=@{"SvcWmi"=$svcWmi}
461     if($PSBoundParameters.ContainsKey("StartupType")) {$null=$writeStartupArguments.Add("StartupType",$StartupType)}
462     WriteStartupTypeProperty @writeStartupArguments
463 }
464
465 <#
466 .Synopsis
467 Gets a Win32_Service object corresponding to the name
468 #>
469 function GetWMIService
470 {
471     param
472     (
473         [parameter(Mandatory = $true)]
474         [ValidateNotNull()]
475         $Name
476     )
477
478     try
479     {
480         return Get-CimInstance -ClassName Win32_Service -Filter "Name='$Name'"
481     }
482     catch
483     {
484         Write-Verbose ($LocalizedData.ErrorRetrievingServiceInformation -f $Name,$_.Exception.Message)
485         throw
486     }
487 }
488
489 <#
490 .Synopsis
491 Writes StartupType if not already correctly set, logging errors and respecting whatif
492 #>
493 function WriteStartupTypeProperty
494 {
495     [CmdletBinding(SupportsShouldProcess=$true)]
496     param
497     (
498         [parameter(Mandatory = $true)]
499         [ValidateNotNull()]
500         $SvcWmi,
501
502         [System.String]
503         $StartupType
504     )
505
506     if($PSBoundParameters.ContainsKey("StartupType") -and !(TestStartupType $SvcWmi $StartupType) -and $PSCmdlet.ShouldProcess($svcWmi.Name,$LocalizedData.SetStartupTypeWhatIf))
507     {
508         $ret = Invoke-CimMethod -InputObject $SvcWmi -MethodName Change -Arguments @{StartMode=$StartupType}
509         if($ret.ReturnValue -ne 0)
510         {
511             $innerMessage = $LocalizedData.MethodFailed -f "Change","Win32_Service",$ret.ReturnValue
512             $message = $LocalizedData.ErrorChangingProperty -f "StartupType",$innerMessage
513             ThrowInvalidArgumentError "ChangeStartupTypeFailed" $message
514         }
515     }
516 }
517
518
519 <#
520 .Synopsis
521 Writes credential properties if not already correctly set, logging errors and respecting whatif
522 #>
523 function WriteCredentialProperties
524 {
525     [CmdletBinding(SupportsShouldProcess=$true)]
526     param
527     (
528         
529         [parameter(Mandatory = $true)]
530         [ValidateNotNull()]
531         $SvcWmi,
532
533
534         [System.String]
535         [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
536         $BuiltInAccount,
537
538         [System.Management.Automation.PSCredential]
539         $Credential
540     )
541
542     if(!$PSBoundParameters.ContainsKey("Credential") -and !$PSBoundParameters.ContainsKey("BuiltInAccount"))
543     {
544         return
545     }
546     
547     if($PSBoundParameters.ContainsKey("Credential") -and $PSBoundParameters.ContainsKey("BuiltInAccount"))
548     {
549         ThrowInvalidArgumentError "OnlyCredentialOrBuiltInAccount" ($LocalizedData.OnlyOneParameterCanBeSpecified -f "Credential","BuiltInAccount")
550     }
551
552     $getUserNameAndPasswordArgs=@{}
553     if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$getUserNameAndPasswordArgs.Add("BuiltInAccount",$BuiltInAccount)}
554     if($PSBoundParameters.ContainsKey("Credential")) {$null=$getUserNameAndPasswordArgs.Add("Credential",$Credential)}
555
556     $userName,$password=GetUserNameAndPassword @getUserNameAndPasswordArgs
557
558     if($userName -ne $null -and !(TestUserName $SvcWmi $userName) -and $PSCmdlet.ShouldProcess($SvcWmi.Name,$LocalizedData.SetCredentialWhatIf))
559     {
560         if($PSBoundParameters.ContainsKey("Credential"))
561         {
562             SetLogOnAsServicePolicy $userName
563         }
564
565         $ret = Invoke-CimMethod -InputObject $SvcWmi -MethodName Change -Arguments @{StartName=$userName;StartPassword=$password}
566         if($ret.ReturnValue -ne 0)
567         {
568             $innerMessage = $LocalizedData.MethodFailed -f "Change","Win32_Service",$ret.ReturnValue
569             $message = $LocalizedData.ErrorChangingProperty -f "Credential",$innerMessage
570             ThrowInvalidArgumentError "ChangeCredentialFailed" $message
571         }
572     }
573 }
574
575 <#
576 .Synopsis
577 Returns true if the service's StartName matches $UserName
578 #>
579 function TestUserName
580 {
581     param
582     (
583         $SvcWmi,
584
585         [string]
586         $UserName
587     )
588
589     return  (NormalizeUserName $SvcWmi.StartName) -ieq $UserName
590 }
591
592 function TestStartupType
593 {
594     param
595     (
596         [parameter(Mandatory = $true)]
597         [ValidateNotNull()]
598         $SvcWmi,
599
600         [System.String]
601         $StartupType
602     )
603
604     return (NormalizeStartupType $SvcWmi.StartMode) -ieq $StartupType
605 }
606
607
608 <#
609 .Synopsis
610 Retrieves user name and password out of the BuiltInAccount and Credential parameters
611 #>
612 function GetUserNameAndPassword
613 {
614     param
615     (
616         [System.String]
617         [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
618         $BuiltInAccount,
619
620         [System.Management.Automation.PSCredential]
621         $Credential
622     )
623
624     if($PSBoundParameters.ContainsKey("BuiltInAccount"))
625     {
626         return (NormalizeUserName $BuiltInAccount.ToString()),$null
627     }
628
629     if($PSBoundParameters.ContainsKey("Credential"))
630     {
631         return (NormalizeUserName $Credential.UserName),$Credential.GetNetworkCredential().Password
632     }
633     
634     return $null,$null
635 }
636
637 <#
638 .Synopsis
639 Stops a service if it is not already stopped logging the result
640 #>
641 function StopService
642 {
643     [CmdletBinding(SupportsShouldProcess=$true)]
644     param
645     (
646         [parameter(Mandatory = $true)]
647         [ValidateNotNull()]
648         $svc
649     )
650
651     if($svc.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Stopped)
652     {
653         Write-Log ($LocalizedData.ServiceAlreadyStopped -f  $svc.Name)
654         return
655     }
656
657     # Exceptions will be thrown, caught and logged by the infrastructure
658     $err=Stop-Service $svc.Name -force 2>&1
659     if($err -eq $null)
660     {
661         Write-Log ($LocalizedData.ServiceStopped -f $svc.Name)
662     }
663     else
664     {
665         Write-Log ($LocalizedData.ErrorStoppingService -f $svc.Name,($err | Out-String))
666         throw $err
667     }
668 }
669
670 <#
671 .Synopsis
672 Starts a service if it is not already started logging the result
673 #>
674 function StartService
675 {
676     [CmdletBinding(SupportsShouldProcess=$true)]
677     param
678     (
679         [parameter(Mandatory = $true)]
680         [ValidateNotNull()]
681         $svc
682     )
683
684     if($svc.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Running)
685     {
686         Write-Log ($LocalizedData.ServiceAlreadyStarted -f  $svc.Name)
687         return
688     }
689
690     if($PSCmdlet.ShouldProcess($svc.Name,$LocalizedData.StartServiceWhatIf))
691     {
692         try
693         {
694             $svc.Start()
695             $twoSeconds = New-Object timespan 20000000
696             $svc.WaitForStatus("Running",$twoSeconds) 
697         }
698         catch
699         {
700             $servicePath = (Get-CimInstance -Class win32_service | where {$_.Name -eq $Name}).PathName
701             $message = $LocalizedData.ErrorStartingService -f $svc.Name,$servicePath,$_.Exception.Message
702             ThrowInvalidArgumentError "ErrorStartingService" $message
703         }
704
705         Write-Log ($LocalizedData.ServiceStarted -f $svc.Name)
706     }
707
708 }
709
710 <#
711 .Synopsis
712 Deletes a service
713 #>
714 function DeleteService
715 {
716     [CmdletBinding(SupportsShouldProcess = $true)]
717     param
718     (
719         [parameter(Mandatory = $true)]
720         [ValidateNotNull()]
721         $Name
722     )
723     
724     $err = & "sc.exe" "delete" "$Name"
725
726     for($i = 1; $i -lt 1000; $i++)
727     {
728         if(!(ServiceExists -Name $Name))
729         {
730             $serviceDeletedSuccessfully = $true
731             break
732         }
733
734         #try again after 2 millisecs if the service is not deleted.
735         Write-Verbose ($LocalizedData.TryDeleteAgain)
736         Start-Sleep .002
737     }
738     if(!$serviceDeletedSuccessfully)
739     {
740         Write-Log ($LocalizedData.ErrorDeletingService -f $Name)
741         throw $LocalizedData.ErrorDeletingService -f $Name
742     }
743     else
744     {
745         Write-Log ($LocalizedData.ServiceDeletedSuccessfully -f $Name)
746     }
747 }
748
749 function NormalizeStartupType([string]$StartupType)
750 {
751     if ($StartupType -ieq 'Auto') {return "Automatic"}
752     return $StartupType
753 }
754
755 function NormalizeUserName([string]$UserName)
756 {
757     if ($UserName -ieq 'NetworkService') {return "NT Authority\NetworkService"}
758     if ($UserName -ieq 'LocalService') {return "NT Authority\LocalService"}
759     if ($UserName -ieq 'LocalSystem') {return ".\LocalSystem"}
760     if ($UserName.IndexOf("\") -eq -1) { return ".\" + $userName }
761     return $UserName
762 }
763
764 <#
765 .Synopsis
766 Throws an argument error
767 #>
768 function ThrowInvalidArgumentError
769 {
770     [CmdletBinding()]
771     param
772     (
773         
774         [parameter(Mandatory = $true)]
775         [ValidateNotNullOrEmpty()]
776         [System.String]
777         $errorId,
778
779         [parameter(Mandatory = $true)]
780         [ValidateNotNullOrEmpty()]
781         [System.String]
782         $errorMessage
783     )
784
785     $errorCategory=[System.Management.Automation.ErrorCategory]::InvalidArgument
786     $exception = New-Object System.ArgumentException $errorMessage;
787     $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null
788     throw $errorRecord
789 }
790
791 <#
792 .Synopsis
793 Gets a service corresponding to a name, throwing an error if not found
794 #>
795 function GetServiceResource
796 {
797     param
798     (
799         
800         [parameter(Mandatory = $true)]
801         [ValidateNotNullOrEmpty()]
802         [System.String]
803         $Name
804     )
805
806     $svc=Get-Service $name -ErrorAction Ignore
807
808     if($svc -eq $null)
809     {
810         ThrowInvalidArgumentError "ServiceNotFound" ($LocalizedData.ServiceNotFound -f $Name)
811     }
812
813     return $svc
814 }
815
816 <#
817 .Synopsis
818 Grants log on as service right to the given user
819 #>
820 function SetLogOnAsServicePolicy([string]$userName)
821 {
822     $logOnAsServiceText=@"
823         namespace LogOnAsServiceHelper
824         {
825             using Microsoft.Win32.SafeHandles;
826             using System;
827             using System.Runtime.ConstrainedExecution;
828             using System.Runtime.InteropServices;
829             using System.Security;
830
831             public class NativeMethods
832             {
833                 #region constants
834                 // from ntlsa.h
835                 private const int POLICY_LOOKUP_NAMES = 0x00000800;
836                 private const int POLICY_CREATE_ACCOUNT = 0x00000010;
837                 private const uint ACCOUNT_ADJUST_SYSTEM_ACCESS = 0x00000008;
838                 private const uint ACCOUNT_VIEW = 0x00000001;
839                 private const uint SECURITY_ACCESS_SERVICE_LOGON = 0x00000010;
840
841                 // from LsaUtils.h
842                 private const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
843
844                 // from lmcons.h
845                 private const int UNLEN = 256;
846                 private const int DNLEN = 15;
847
848                 // Extra characteres for "\","@" etc.
849                 private const int EXTRA_LENGTH = 3;
850                 #endregion constants
851
852                 #region interop structures
853                 /// <summary>
854                 /// Used to open a policy, but not containing anything meaqningful
855                 /// </summary>
856                 [StructLayout(LayoutKind.Sequential)]
857                 private struct LSA_OBJECT_ATTRIBUTES
858                 {
859                     public UInt32 Length;
860                     public IntPtr RootDirectory;
861                     public IntPtr ObjectName;
862                     public UInt32 Attributes;
863                     public IntPtr SecurityDescriptor;
864                     public IntPtr SecurityQualityOfService;
865
866                     public void Initialize()
867                     {
868                         this.Length = 0;
869                         this.RootDirectory = IntPtr.Zero;
870                         this.ObjectName = IntPtr.Zero;
871                         this.Attributes = 0;
872                         this.SecurityDescriptor = IntPtr.Zero;
873                         this.SecurityQualityOfService = IntPtr.Zero;
874                     }
875                 }
876
877                 /// <summary>
878                 /// LSA string
879                 /// </summary>
880                 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
881                 private struct LSA_UNICODE_STRING
882                 {
883                     internal ushort Length;
884                     internal ushort MaximumLength;
885                     [MarshalAs(UnmanagedType.LPWStr)]
886                     internal string Buffer;
887
888                     internal void Set(string src)
889                     {
890                         this.Buffer = src;
891                         this.Length = (ushort)(src.Length * sizeof(char));
892                         this.MaximumLength = (ushort)(this.Length + sizeof(char));
893                     }
894                 }
895
896                 /// <summary>
897                 /// Structure used as the last parameter for LSALookupNames
898                 /// </summary>
899                 [StructLayout(LayoutKind.Sequential)]
900                 private struct LSA_TRANSLATED_SID2
901                 {
902                     public uint Use;
903                     public IntPtr SID;
904                     public int DomainIndex;
905                     public uint Flags;
906                 };
907                 #endregion interop structures
908
909                 #region safe handles
910                 /// <summary>
911                 /// Handle for LSA objects including Policy and Account
912                 /// </summary>
913                 private class LsaSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
914                 {
915 #if CORECLR
916                     [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll")]
917 #else
918                     [DllImport("advapi32.dll")]
919 #endif
920                     private static extern uint LsaClose(IntPtr ObjectHandle);
921
922                     /// <summary>
923                     /// Prevents a default instance of the LsaPolicySafeHAndle class from being created.
924                     /// </summary>
925                     private LsaSafeHandle(): base(true)
926                     {
927                     }
928
929                     /// <summary>
930                     /// Calls NativeMethods.CloseHandle(handle)
931                     /// </summary>
932                     /// <returns>the return of NativeMethods.CloseHandle(handle)</returns>
933 #if !CORECLR
934                     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
935 #endif
936                     protected override bool ReleaseHandle()
937                     {
938                         long returnValue = LsaSafeHandle.LsaClose(this.handle);
939                         return returnValue != 0;
940                 
941                     }
942                 }
943
944                 /// <summary>
945                 /// Handle for IntPtrs returned from Lsa calls that have to be freed with
946                 /// LsaFreeMemory
947                 /// </summary>
948                 private class SafeLsaMemoryHandle : SafeHandleZeroOrMinusOneIsInvalid
949                 {
950 #if CORECLR
951                     [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll")]
952 #else
953                     [DllImport("advapi32")]
954 #endif
955                     internal static extern int LsaFreeMemory(IntPtr Buffer);
956
957                     private SafeLsaMemoryHandle() : base(true) { }
958
959                     private SafeLsaMemoryHandle(IntPtr handle)
960                         : base(true)
961                     {
962                         SetHandle(handle);
963                     }
964
965                     private static SafeLsaMemoryHandle InvalidHandle
966                     {
967                         get { return new SafeLsaMemoryHandle(IntPtr.Zero); }
968                     }
969
970                     override protected bool ReleaseHandle()
971                     {
972                         return SafeLsaMemoryHandle.LsaFreeMemory(handle) == 0;
973                     }
974
975                     internal IntPtr Memory
976                     {
977                         get
978                         {
979                             return this.handle;
980                         }
981                     }
982                 }
983                 #endregion safe handles
984
985                 #region interop function declarations
986                 /// <summary>
987                 /// Opens LSA Policy
988                 /// </summary>
989 #if CORECLR
990                 [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll", SetLastError = true, PreserveSig = true)]
991 #else
992                 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
993 #endif
994                 private static extern uint LsaOpenPolicy(
995                     IntPtr SystemName,
996                     ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
997                     uint DesiredAccess,
998                     out LsaSafeHandle PolicyHandle
999                 );
1000
1001                 /// <summary>
1002                 /// Convert the name into a SID which is used in remaining calls
1003                 /// </summary>
1004 #if CORECLR
1005                 [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
1006 #else
1007                 [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
1008 #endif
1009                 private static extern uint LsaLookupNames2(
1010                     LsaSafeHandle PolicyHandle,
1011                     uint Flags,
1012                     uint Count,
1013                     LSA_UNICODE_STRING[] Names,
1014                     out SafeLsaMemoryHandle ReferencedDomains,
1015                     out SafeLsaMemoryHandle Sids
1016                 );
1017
1018                 /// <summary>
1019                 /// Opens the LSA account corresponding to the user's SID
1020                 /// </summary>
1021 #if CORECLR
1022                 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1023 #else
1024                 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1025 #endif
1026                 private static extern uint LsaOpenAccount(
1027                     LsaSafeHandle PolicyHandle,
1028                     IntPtr Sid,
1029                     uint Access,
1030                     out LsaSafeHandle AccountHandle);
1031
1032                 /// <summary>
1033                 /// Creates an LSA account corresponding to the user's SID
1034                 /// </summary>
1035 #if CORECLR
1036                 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1037 #else
1038                 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1039 #endif
1040                 private static extern uint LsaCreateAccount(
1041                     LsaSafeHandle PolicyHandle,
1042                     IntPtr Sid,
1043                     uint Access,
1044                     out LsaSafeHandle AccountHandle);
1045
1046                 /// <summary>
1047                 /// Gets the LSA Account access
1048                 /// </summary>
1049 #if CORECLR
1050                 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1051 #else
1052                 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1053 #endif
1054                 private static extern uint LsaGetSystemAccessAccount(
1055                     LsaSafeHandle AccountHandle,
1056                     out uint SystemAccess);
1057
1058                 /// <summary>
1059                 /// Sets the LSA Account access
1060                 /// </summary>
1061 #if CORECLR
1062                 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1063 #else
1064                 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1065 #endif
1066                 private static extern uint LsaSetSystemAccessAccount(
1067                     LsaSafeHandle AccountHandle,
1068                     uint SystemAccess);
1069                 #endregion interop function declarations
1070
1071                 /// <summary>
1072                 /// Sets the Log On As A Service Policy for <paramref name="userName"/>, if not already set.
1073                 /// </summary>
1074                 /// <param name="userName">the user name we want to allow logging on as a service</param>
1075                 /// <exception cref="ArgumentNullException">If the <paramref name="userName"/> is null or empty.</exception>
1076                 /// <exception cref="InvalidOperationException">In the following cases:
1077                 ///     Failure opening the LSA Policy.
1078                 ///     The <paramref name="userName"/> is too large.
1079                 ///     Failure looking up the user name.
1080                 ///     Failure opening LSA account (other than account not found).
1081                 ///     Failure creating LSA account.
1082                 ///     Failure getting LSA account policy access.
1083                 ///     Failure setting LSA account policy access.
1084                 /// </exception>
1085                 public static void SetLogOnAsServicePolicy(string userName)
1086                 {
1087                     if (String.IsNullOrEmpty(userName))
1088                     {
1089                         throw new ArgumentNullException("userName");
1090                     }
1091
1092                     LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES();
1093                     objectAttributes.Initialize();
1094
1095                     // All handles are delcared in advance so they can be closed on finally
1096                     LsaSafeHandle policyHandle = null;
1097                     SafeLsaMemoryHandle referencedDomains = null;
1098                     SafeLsaMemoryHandle sids = null;
1099                     LsaSafeHandle accountHandle = null;
1100
1101                     try
1102                     {
1103                         uint status = LsaOpenPolicy(
1104                             IntPtr.Zero,
1105                             ref objectAttributes,
1106                             POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT,
1107                             out policyHandle);
1108
1109                         if (status != 0)
1110                         {
1111                             throw new InvalidOperationException(@"CannotOpenPolicyErrorMessage");
1112                         }
1113
1114                         // Unicode strings have a maximum length of 32KB. We don't want to create
1115                         // LSA strings with more than that. User lengths are much smaller so this check
1116                         // ensures userName's length is useful
1117                         if (userName.Length > UNLEN + DNLEN + EXTRA_LENGTH)
1118                         {
1119                             throw new InvalidOperationException(@"UserNameTooLongErrorMessage");
1120                         }
1121
1122                         LSA_UNICODE_STRING lsaUserName = new LSA_UNICODE_STRING();
1123                         lsaUserName.Set(userName);
1124
1125                         LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
1126                         names[0].Set(userName);
1127
1128                         status = LsaLookupNames2(
1129                             policyHandle,
1130                             0,
1131                             1,
1132                             new LSA_UNICODE_STRING[] { lsaUserName },
1133                             out referencedDomains,
1134                             out sids);
1135
1136                         if (status != 0)
1137                         {
1138                             throw new InvalidOperationException(@"CannotLookupNamesErrorMessage");
1139                         }
1140
1141                         LSA_TRANSLATED_SID2 sid = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(sids.Memory, typeof(LSA_TRANSLATED_SID2));
1142
1143
1144                         status = LsaOpenAccount(policyHandle,
1145                                             sid.SID,
1146                                             ACCOUNT_VIEW | ACCOUNT_ADJUST_SYSTEM_ACCESS,
1147                                             out accountHandle);
1148
1149                         uint currentAccess = 0;
1150
1151                         if (status == 0)
1152                         {
1153                             status = LsaGetSystemAccessAccount(accountHandle, out currentAccess);
1154
1155                             if (status != 0)
1156                             {
1157                                 throw new InvalidOperationException(@"CannotGetAccountAccessErrorMessage");
1158                             }
1159
1160                         }
1161                         else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1162                         {
1163                             status = LsaCreateAccount(
1164                                 policyHandle,
1165                                 sid.SID,
1166                                 ACCOUNT_ADJUST_SYSTEM_ACCESS,
1167                                 out accountHandle);
1168
1169                             if (status != 0)
1170                             {
1171                                 throw new InvalidOperationException(@"CannotCreateAccountAccessErrorMessage");
1172                             }
1173                         }
1174                         else
1175                         {
1176                             throw new InvalidOperationException(@"CannotOpenAccountErrorMessage");
1177                         }
1178
1179                         if ((currentAccess & SECURITY_ACCESS_SERVICE_LOGON) == 0)
1180                         {
1181                             status = LsaSetSystemAccessAccount(
1182                                 accountHandle,
1183                                 currentAccess | SECURITY_ACCESS_SERVICE_LOGON);
1184                             if (status != 0)
1185                             {
1186                                 throw new InvalidOperationException(@"CannotSetAccountAccessErrorMessage");
1187                             }
1188                         }
1189                     }
1190                     finally
1191                     {
1192                         if (policyHandle != null) { policyHandle.Close(); }
1193                         if (referencedDomains != null) { referencedDomains.Close(); }
1194                         if (sids != null) { sids.Close(); }
1195                         if (accountHandle != null) { accountHandle.Close(); }
1196                     }
1197                 }
1198             }
1199         }
1200 "@
1201     
1202     try
1203     {
1204         $existingType=[LogOnAsServiceHelper.NativeMethods]
1205     }
1206     catch
1207     {
1208         $logOnAsServiceText=$logOnAsServiceText.Replace("CannotOpenPolicyErrorMessage",$LocalizedData.CannotOpenPolicyErrorMessage)
1209         $logOnAsServiceText=$logOnAsServiceText.Replace("UserNameTooLongErrorMessage",$LocalizedData.UserNameTooLongErrorMessage)
1210         $logOnAsServiceText=$logOnAsServiceText.Replace("CannotLookupNamesErrorMessage",$LocalizedData.CannotLookupNamesErrorMessage)
1211         $logOnAsServiceText=$logOnAsServiceText.Replace("CannotOpenAccountErrorMessage",$LocalizedData.CannotOpenAccountErrorMessage)
1212         $logOnAsServiceText=$logOnAsServiceText.Replace("CannotCreateAccountAccessErrorMessage",$LocalizedData.CannotCreateAccountAccessErrorMessage)
1213         $logOnAsServiceText=$logOnAsServiceText.Replace("CannotGetAccountAccessErrorMessage",$LocalizedData.CannotGetAccountAccessErrorMessage)
1214         $logOnAsServiceText=$logOnAsServiceText.Replace("CannotSetAccountAccessErrorMessage",$LocalizedData.CannotSetAccountAccessErrorMessage)
1215
1216         if(IsNanoServer)
1217         {
1218             $logOnAsServiceText = "#define CORECLR`n" + $logOnAsServiceText
1219         }
1220         $null = Add-Type $logOnAsServiceText -PassThru -Debug:$false
1221     }
1222
1223     if($userName.StartsWith(".\"))
1224     {
1225         $userName = $userName.Substring(2)
1226     }
1227
1228     try
1229     {
1230         [LogOnAsServiceHelper.NativeMethods]::SetLogOnAsServicePolicy($userName)
1231     }
1232     catch
1233     {
1234         $message = $LocalizedData.ErrorSetingLogOnAsServiceRightsForUser -f $userName,$_.Exception.Message
1235         ThrowInvalidArgumentError "ErrorSetingLogOnAsServiceRightsForUser" $message
1236     }
1237 }
1238
1239 function Write-Log
1240 {
1241     [CmdletBinding(SupportsShouldProcess=$true)]
1242     param
1243     (    
1244         [parameter(Mandatory = $true)]
1245         [ValidateNotNullOrEmpty()]
1246         [System.String]
1247         $Message
1248     )
1249
1250     if ($PSCmdlet.ShouldProcess($Message, $null, $null))
1251     {
1252         Write-Verbose $Message        
1253     }    
1254 }
1255
1256 Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource