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.
44 Import-LocalizedData LocalizedData -filename MSFT_ServiceResource.strings.psd1
45 $EscapedLocalizedData = @{}
46 foreach( $key in $LocalizedData.Keys )
48 $EscapedLocalizedData.Add($key, $LocalizedData[$key].Replace('"','""'))
50 $LocalizedData = $EscapedLocalizedData
51 Import-Module "$PSScriptRoot\..\RunAsHelper.psm1"
55 Gets a service resource
57 function Get-TargetResource
62 [parameter(Mandatory = $true)]
63 [ValidateNotNullOrEmpty()]
68 $svc = GetServiceResource $Name
69 $svcWmi = GetWMIService $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()
79 DisplayName=$svc.DisplayName
80 Description=$svcWmi.Description
81 Dependencies=[string[]](@() + ($svc.ServicesDependedOn | %{$_.Name}))
88 Tests a service resource
90 function Test-TargetResource
94 [parameter(Mandatory = $true)]
95 [ValidateNotNullOrEmpty()]
100 [ValidateSet("Automatic", "Manual", "Disabled")]
104 [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
107 [System.Management.Automation.PSCredential]
112 [ValidateSet("Running", "Stopped")]
116 [ValidateNotNullOrEmpty()]
120 [ValidateNotNullOrEmpty()]
124 [ValidateNotNullOrEmpty()]
128 [ValidateNotNullOrEmpty()]
132 [ValidateSet("Present", "Absent")]
136 ValidateStartupType $Name $StartupType $State
138 $serviceExists = ServiceExists -Name $Name -Path $Path -ErrorAction SilentlyContinue
140 if($Ensure -eq "Absent")
154 $svc=GetServiceResource $Name
156 if($PSBoundParameters.ContainsKey("StartupType") -or $PSBoundParameters.ContainsKey("BuiltInAccount") -or $PSBoundParameters.ContainsKey("Credential"))
158 $svcWmi = GetWMIService $Name
160 $getUserNameAndPasswordArgs=@{}
161 if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$getUserNameAndPasswordArgs.Add("BuiltInAccount",$BuiltInAccount)}
162 if($PSBoundParameters.ContainsKey("Credential")) {$null=$getUserNameAndPasswordArgs.Add("Credential",$Credential)}
164 $userName,$password=GetUserNameAndPassword @getUserNameAndPasswordArgs
165 if($userName -ne $null -and !(TestUserName $SvcWmi $userName))
167 write-verbose ($LocalizedData.TestUserNameMismatch -f $svcWmi.Name,$svcWmi.StartName,$userName)
171 if($PSBoundParameters.ContainsKey("StartupType") -and !(TestStartupType $SvcWmi $StartupType))
173 write-verbose ($LocalizedData.TestStartupTypeMismatch -f $svcWmi.Name,$svcWmi.StartMode,$StartupType)
178 return ($State -eq "Stopped" -and $svc.Status -eq "Stopped") -or ($svc.Status -eq "Running" -and $State -eq "Running")
183 Sets properties for a service resource
185 function Set-TargetResource
187 [CmdletBinding(SupportsShouldProcess=$true)]
191 [parameter(Mandatory = $true)]
192 [ValidateNotNullOrEmpty()]
197 [ValidateSet("Automatic", "Manual", "Disabled")]
201 [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
204 [System.Management.Automation.PSCredential]
209 [ValidateSet("Running", "Stopped")]
213 [ValidateNotNullOrEmpty()]
217 [ValidateNotNullOrEmpty()]
221 [ValidateNotNullOrEmpty()]
225 [ValidateNotNullOrEmpty()]
229 [ValidateSet("Present", "Absent")]
233 ValidateStartupType $Name $StartupType $State
235 if($Ensure -eq "Absent")
237 $svc = GetServiceResource $Name
239 DeleteService $svc.Name
243 $serviceExists = ServiceExists -Name $Name -ErrorAction SilentlyContinue
245 if($PSBoundParameters.ContainsKey("Path") -and $serviceExists)
247 if(CompareServicePath -Path $Path -Name $Name)
249 ThrowInvalidArgumentError "ServiceExistsSamePath" ($LocalizedData.ServiceExistsSamePath -f $Name, $Path)
251 ThrowInvalidArgumentError "ServiceAlreadyExists" ($LocalizedData.ServiceAlreadyExists -f $Name)
253 elseif($PSBoundParameters.ContainsKey("Path") -and !$serviceExists)
255 $argumentsToNewService = @{}
256 $argumentsToNewService.Add("Name", $Name)
257 $argumentsToNewService.Add("BinaryPathName", $Path)
258 if($PSBoundParameters.ContainsKey("Credential"))
260 $argumentsToNewService.Add("Credential", $Credential)
262 if($PSBoundParameters.ContainsKey("StartupType"))
264 $argumentsToNewService.Add("StartupType", $StartupType)
266 if($PSBoundParameters.ContainsKey("DisplayName"))
268 $argumentsToNewService.Add("DisplayName", $DisplayName)
270 if($PSBoundParameters.ContainsKey("Description"))
272 $argumentsToNewService.Add("Description", $Description)
274 if($PSBoundParameters.ContainsKey("Dependencies"))
276 $argumentsToNewService.Add("DependsOn", $Dependencies)
280 New-Service @argumentsToNewService
281 $serviceIsNew = $true
285 Write-Log ("Error creating service `"$($argumentsToNewService["Name"])`"", $_.Exception.Message)
289 elseif(!$PSBoundParameters.ContainsKey("Path") -and !$serviceExists)
291 throw $LocalizedData.ServiceNotExists -f $Name
294 $svc=GetServiceResource $Name
298 Write-Verbose ($LocalizedData.WritePropertiesIgnored -f $Name)
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)}
306 WriteWriteProperties @writeWritePropertiesArguments
308 if($State -eq "Stopped")
310 # Ensure service is stopped
315 # Default state of a newly created service is 'stopped'. If $State=Running, ensure service is started.
316 if($State -eq "Running")
324 Validates if a service exist using the Name parameter
326 function ServiceExists
330 [parameter(Mandatory = $true)]
331 [ValidateNotNullOrEmpty()]
339 $service = Get-Service -Name $Name -ErrorAction SilentlyContinue
340 if($service -ne $null)
342 if($Path -ne $null -and $Path -ne '' -and !(CompareServicePath -Name $Name -Path $Path)){
352 Compares path to the service path, if the service exists. Returns true when path is same as service path.
354 function CompareServicePath
358 [parameter(Mandatory = $true)]
359 [ValidateNotNullOrEmpty()]
363 [parameter(Mandatory = $true)]
364 [ValidateNotNullOrEmpty()]
369 $servicePath = (Get-CimInstance -Class win32_service | where {$_.Name -eq $Name}).PathName
370 $result = [string]::Compare($Path, $servicePath, [System.Globalization.CultureInfo]::CurrentUICulture)
381 Validates a StartupType against the State parameter
383 function ValidateStartupType
387 [parameter(Mandatory = $true)]
388 [ValidateNotNullOrEmpty()]
396 [ValidateSet("Running", "Stopped")]
400 if($StartupType -eq $null) {return}
402 if($State -eq "Stopped")
404 if($StartupType -eq "Automatic")
406 # State = Stopped conflicts with Automatic or Delayed
407 ThrowInvalidArgumentError "CannotStopServiceSetToStartAutomatically" ($LocalizedData.CannotStopServiceSetToStartAutomatically -f $Name)
412 if($StartupType -eq "Disabled")
414 # State = Running conflicts with Disabled
415 ThrowInvalidArgumentError "CannotStartAndDisable" ($LocalizedData.CannotStartAndDisable -f $Name)
423 Writes all write properties if not already correctly set, logging errors and respecting whatif
425 function WriteWriteProperties
427 [CmdletBinding(SupportsShouldProcess=$true)]
430 [parameter(Mandatory = $true)]
435 [ValidateSet("Automatic", "Manual", "Disabled")]
439 [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
442 [System.Management.Automation.PSCredential]
447 if(!$PSBoundParameters.ContainsKey("StartupType") -and !$PSBoundParameters.ContainsKey("BuiltInAccount") -and !$PSBoundParameters.ContainsKey("Credential"))
452 $svcWmi = GetWMIService $Name
454 $writeCredentialPropertiesArguments=@{"SvcWmi"=$svcWmi}
455 if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$writeCredentialPropertiesArguments.Add("BuiltInAccount",$BuiltInAccount)}
456 if($PSBoundParameters.ContainsKey("Credential")) {$null=$writeCredentialPropertiesArguments.Add("Credential",$Credential)}
458 WriteCredentialProperties @writeCredentialPropertiesArguments
460 $writeStartupArguments=@{"SvcWmi"=$svcWmi}
461 if($PSBoundParameters.ContainsKey("StartupType")) {$null=$writeStartupArguments.Add("StartupType",$StartupType)}
462 WriteStartupTypeProperty @writeStartupArguments
467 Gets a Win32_Service object corresponding to the name
469 function GetWMIService
473 [parameter(Mandatory = $true)]
480 return Get-CimInstance -ClassName Win32_Service -Filter "Name='$Name'"
484 Write-Verbose ($LocalizedData.ErrorRetrievingServiceInformation -f $Name,$_.Exception.Message)
491 Writes StartupType if not already correctly set, logging errors and respecting whatif
493 function WriteStartupTypeProperty
495 [CmdletBinding(SupportsShouldProcess=$true)]
498 [parameter(Mandatory = $true)]
506 if($PSBoundParameters.ContainsKey("StartupType") -and !(TestStartupType $SvcWmi $StartupType) -and $PSCmdlet.ShouldProcess($svcWmi.Name,$LocalizedData.SetStartupTypeWhatIf))
508 $ret = Invoke-CimMethod -InputObject $SvcWmi -MethodName Change -Arguments @{StartMode=$StartupType}
509 if($ret.ReturnValue -ne 0)
511 $innerMessage = $LocalizedData.MethodFailed -f "Change","Win32_Service",$ret.ReturnValue
512 $message = $LocalizedData.ErrorChangingProperty -f "StartupType",$innerMessage
513 ThrowInvalidArgumentError "ChangeStartupTypeFailed" $message
521 Writes credential properties if not already correctly set, logging errors and respecting whatif
523 function WriteCredentialProperties
525 [CmdletBinding(SupportsShouldProcess=$true)]
529 [parameter(Mandatory = $true)]
535 [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
538 [System.Management.Automation.PSCredential]
542 if(!$PSBoundParameters.ContainsKey("Credential") -and !$PSBoundParameters.ContainsKey("BuiltInAccount"))
547 if($PSBoundParameters.ContainsKey("Credential") -and $PSBoundParameters.ContainsKey("BuiltInAccount"))
549 ThrowInvalidArgumentError "OnlyCredentialOrBuiltInAccount" ($LocalizedData.OnlyOneParameterCanBeSpecified -f "Credential","BuiltInAccount")
552 $getUserNameAndPasswordArgs=@{}
553 if($PSBoundParameters.ContainsKey("BuiltInAccount")) {$null=$getUserNameAndPasswordArgs.Add("BuiltInAccount",$BuiltInAccount)}
554 if($PSBoundParameters.ContainsKey("Credential")) {$null=$getUserNameAndPasswordArgs.Add("Credential",$Credential)}
556 $userName,$password=GetUserNameAndPassword @getUserNameAndPasswordArgs
558 if($userName -ne $null -and !(TestUserName $SvcWmi $userName) -and $PSCmdlet.ShouldProcess($SvcWmi.Name,$LocalizedData.SetCredentialWhatIf))
560 if($PSBoundParameters.ContainsKey("Credential"))
562 SetLogOnAsServicePolicy $userName
565 $ret = Invoke-CimMethod -InputObject $SvcWmi -MethodName Change -Arguments @{StartName=$userName;StartPassword=$password}
566 if($ret.ReturnValue -ne 0)
568 $innerMessage = $LocalizedData.MethodFailed -f "Change","Win32_Service",$ret.ReturnValue
569 $message = $LocalizedData.ErrorChangingProperty -f "Credential",$innerMessage
570 ThrowInvalidArgumentError "ChangeCredentialFailed" $message
577 Returns true if the service's StartName matches $UserName
579 function TestUserName
589 return (NormalizeUserName $SvcWmi.StartName) -ieq $UserName
592 function TestStartupType
596 [parameter(Mandatory = $true)]
604 return (NormalizeStartupType $SvcWmi.StartMode) -ieq $StartupType
610 Retrieves user name and password out of the BuiltInAccount and Credential parameters
612 function GetUserNameAndPassword
617 [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
620 [System.Management.Automation.PSCredential]
624 if($PSBoundParameters.ContainsKey("BuiltInAccount"))
626 return (NormalizeUserName $BuiltInAccount.ToString()),$null
629 if($PSBoundParameters.ContainsKey("Credential"))
631 return (NormalizeUserName $Credential.UserName),$Credential.GetNetworkCredential().Password
639 Stops a service if it is not already stopped logging the result
643 [CmdletBinding(SupportsShouldProcess=$true)]
646 [parameter(Mandatory = $true)]
651 if($svc.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Stopped)
653 Write-Log ($LocalizedData.ServiceAlreadyStopped -f $svc.Name)
657 # Exceptions will be thrown, caught and logged by the infrastructure
658 $err=Stop-Service $svc.Name -force 2>&1
661 Write-Log ($LocalizedData.ServiceStopped -f $svc.Name)
665 Write-Log ($LocalizedData.ErrorStoppingService -f $svc.Name,($err | Out-String))
672 Starts a service if it is not already started logging the result
674 function StartService
676 [CmdletBinding(SupportsShouldProcess=$true)]
679 [parameter(Mandatory = $true)]
684 if($svc.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Running)
686 Write-Log ($LocalizedData.ServiceAlreadyStarted -f $svc.Name)
690 if($PSCmdlet.ShouldProcess($svc.Name,$LocalizedData.StartServiceWhatIf))
695 $twoSeconds = New-Object timespan 20000000
696 $svc.WaitForStatus("Running",$twoSeconds)
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
705 Write-Log ($LocalizedData.ServiceStarted -f $svc.Name)
714 function DeleteService
716 [CmdletBinding(SupportsShouldProcess = $true)]
719 [parameter(Mandatory = $true)]
724 $err = & "sc.exe" "delete" "$Name"
726 for($i = 1; $i -lt 1000; $i++)
728 if(!(ServiceExists -Name $Name))
730 $serviceDeletedSuccessfully = $true
734 #try again after 2 millisecs if the service is not deleted.
735 Write-Verbose ($LocalizedData.TryDeleteAgain)
738 if(!$serviceDeletedSuccessfully)
740 Write-Log ($LocalizedData.ErrorDeletingService -f $Name)
741 throw $LocalizedData.ErrorDeletingService -f $Name
745 Write-Log ($LocalizedData.ServiceDeletedSuccessfully -f $Name)
749 function NormalizeStartupType([string]$StartupType)
751 if ($StartupType -ieq 'Auto') {return "Automatic"}
755 function NormalizeUserName([string]$UserName)
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 }
766 Throws an argument error
768 function ThrowInvalidArgumentError
774 [parameter(Mandatory = $true)]
775 [ValidateNotNullOrEmpty()]
779 [parameter(Mandatory = $true)]
780 [ValidateNotNullOrEmpty()]
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
793 Gets a service corresponding to a name, throwing an error if not found
795 function GetServiceResource
800 [parameter(Mandatory = $true)]
801 [ValidateNotNullOrEmpty()]
806 $svc=Get-Service $name -ErrorAction Ignore
810 ThrowInvalidArgumentError "ServiceNotFound" ($LocalizedData.ServiceNotFound -f $Name)
818 Grants log on as service right to the given user
820 function SetLogOnAsServicePolicy([string]$userName)
822 $logOnAsServiceText=@"
823 namespace LogOnAsServiceHelper
825 using Microsoft.Win32.SafeHandles;
827 using System.Runtime.ConstrainedExecution;
828 using System.Runtime.InteropServices;
829 using System.Security;
831 public class NativeMethods
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;
842 private const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
845 private const int UNLEN = 256;
846 private const int DNLEN = 15;
848 // Extra characteres for "\","@" etc.
849 private const int EXTRA_LENGTH = 3;
852 #region interop structures
854 /// Used to open a policy, but not containing anything meaqningful
856 [StructLayout(LayoutKind.Sequential)]
857 private struct LSA_OBJECT_ATTRIBUTES
859 public UInt32 Length;
860 public IntPtr RootDirectory;
861 public IntPtr ObjectName;
862 public UInt32 Attributes;
863 public IntPtr SecurityDescriptor;
864 public IntPtr SecurityQualityOfService;
866 public void Initialize()
869 this.RootDirectory = IntPtr.Zero;
870 this.ObjectName = IntPtr.Zero;
872 this.SecurityDescriptor = IntPtr.Zero;
873 this.SecurityQualityOfService = IntPtr.Zero;
880 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
881 private struct LSA_UNICODE_STRING
883 internal ushort Length;
884 internal ushort MaximumLength;
885 [MarshalAs(UnmanagedType.LPWStr)]
886 internal string Buffer;
888 internal void Set(string src)
891 this.Length = (ushort)(src.Length * sizeof(char));
892 this.MaximumLength = (ushort)(this.Length + sizeof(char));
897 /// Structure used as the last parameter for LSALookupNames
899 [StructLayout(LayoutKind.Sequential)]
900 private struct LSA_TRANSLATED_SID2
904 public int DomainIndex;
907 #endregion interop structures
911 /// Handle for LSA objects including Policy and Account
913 private class LsaSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
916 [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll")]
918 [DllImport("advapi32.dll")]
920 private static extern uint LsaClose(IntPtr ObjectHandle);
923 /// Prevents a default instance of the LsaPolicySafeHAndle class from being created.
925 private LsaSafeHandle(): base(true)
930 /// Calls NativeMethods.CloseHandle(handle)
932 /// <returns>the return of NativeMethods.CloseHandle(handle)</returns>
934 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
936 protected override bool ReleaseHandle()
938 long returnValue = LsaSafeHandle.LsaClose(this.handle);
939 return returnValue != 0;
945 /// Handle for IntPtrs returned from Lsa calls that have to be freed with
948 private class SafeLsaMemoryHandle : SafeHandleZeroOrMinusOneIsInvalid
951 [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll")]
953 [DllImport("advapi32")]
955 internal static extern int LsaFreeMemory(IntPtr Buffer);
957 private SafeLsaMemoryHandle() : base(true) { }
959 private SafeLsaMemoryHandle(IntPtr handle)
965 private static SafeLsaMemoryHandle InvalidHandle
967 get { return new SafeLsaMemoryHandle(IntPtr.Zero); }
970 override protected bool ReleaseHandle()
972 return SafeLsaMemoryHandle.LsaFreeMemory(handle) == 0;
975 internal IntPtr Memory
983 #endregion safe handles
985 #region interop function declarations
990 [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll", SetLastError = true, PreserveSig = true)]
992 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
994 private static extern uint LsaOpenPolicy(
996 ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
998 out LsaSafeHandle PolicyHandle
1002 /// Convert the name into a SID which is used in remaining calls
1005 [DllImport("api-ms-win-security-lsapolicy-l1-1-0.dll", CharSet = CharSet.Unicode, SetLastError = true)]
1007 [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
1009 private static extern uint LsaLookupNames2(
1010 LsaSafeHandle PolicyHandle,
1013 LSA_UNICODE_STRING[] Names,
1014 out SafeLsaMemoryHandle ReferencedDomains,
1015 out SafeLsaMemoryHandle Sids
1019 /// Opens the LSA account corresponding to the user's SID
1022 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1024 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1026 private static extern uint LsaOpenAccount(
1027 LsaSafeHandle PolicyHandle,
1030 out LsaSafeHandle AccountHandle);
1033 /// Creates an LSA account corresponding to the user's SID
1036 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1038 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1040 private static extern uint LsaCreateAccount(
1041 LsaSafeHandle PolicyHandle,
1044 out LsaSafeHandle AccountHandle);
1047 /// Gets the LSA Account access
1050 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1052 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1054 private static extern uint LsaGetSystemAccessAccount(
1055 LsaSafeHandle AccountHandle,
1056 out uint SystemAccess);
1059 /// Sets the LSA Account access
1062 [DllImport("advapi32legacy.dll", SetLastError = true, PreserveSig = true)]
1064 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
1066 private static extern uint LsaSetSystemAccessAccount(
1067 LsaSafeHandle AccountHandle,
1069 #endregion interop function declarations
1072 /// Sets the Log On As A Service Policy for <paramref name="userName"/>, if not already set.
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.
1085 public static void SetLogOnAsServicePolicy(string userName)
1087 if (String.IsNullOrEmpty(userName))
1089 throw new ArgumentNullException("userName");
1092 LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES();
1093 objectAttributes.Initialize();
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;
1103 uint status = LsaOpenPolicy(
1105 ref objectAttributes,
1106 POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT,
1111 throw new InvalidOperationException(@"CannotOpenPolicyErrorMessage");
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)
1119 throw new InvalidOperationException(@"UserNameTooLongErrorMessage");
1122 LSA_UNICODE_STRING lsaUserName = new LSA_UNICODE_STRING();
1123 lsaUserName.Set(userName);
1125 LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
1126 names[0].Set(userName);
1128 status = LsaLookupNames2(
1132 new LSA_UNICODE_STRING[] { lsaUserName },
1133 out referencedDomains,
1138 throw new InvalidOperationException(@"CannotLookupNamesErrorMessage");
1141 LSA_TRANSLATED_SID2 sid = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(sids.Memory, typeof(LSA_TRANSLATED_SID2));
1144 status = LsaOpenAccount(policyHandle,
1146 ACCOUNT_VIEW | ACCOUNT_ADJUST_SYSTEM_ACCESS,
1149 uint currentAccess = 0;
1153 status = LsaGetSystemAccessAccount(accountHandle, out currentAccess);
1157 throw new InvalidOperationException(@"CannotGetAccountAccessErrorMessage");
1161 else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1163 status = LsaCreateAccount(
1166 ACCOUNT_ADJUST_SYSTEM_ACCESS,
1171 throw new InvalidOperationException(@"CannotCreateAccountAccessErrorMessage");
1176 throw new InvalidOperationException(@"CannotOpenAccountErrorMessage");
1179 if ((currentAccess & SECURITY_ACCESS_SERVICE_LOGON) == 0)
1181 status = LsaSetSystemAccessAccount(
1183 currentAccess | SECURITY_ACCESS_SERVICE_LOGON);
1186 throw new InvalidOperationException(@"CannotSetAccountAccessErrorMessage");
1192 if (policyHandle != null) { policyHandle.Close(); }
1193 if (referencedDomains != null) { referencedDomains.Close(); }
1194 if (sids != null) { sids.Close(); }
1195 if (accountHandle != null) { accountHandle.Close(); }
1204 $existingType=[LogOnAsServiceHelper.NativeMethods]
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)
1218 $logOnAsServiceText = "#define CORECLR`n" + $logOnAsServiceText
1220 $null = Add-Type $logOnAsServiceText -PassThru -Debug:$false
1223 if($userName.StartsWith(".\"))
1225 $userName = $userName.Substring(2)
1230 [LogOnAsServiceHelper.NativeMethods]::SetLogOnAsServicePolicy($userName)
1234 $message = $LocalizedData.ErrorSetingLogOnAsServiceRightsForUser -f $userName,$_.Exception.Message
1235 ThrowInvalidArgumentError "ErrorSetingLogOnAsServiceRightsForUser" $message
1241 [CmdletBinding(SupportsShouldProcess=$true)]
1244 [parameter(Mandatory = $true)]
1245 [ValidateNotNullOrEmpty()]
1250 if ($PSCmdlet.ShouldProcess($Message, $null, $null))
1252 Write-Verbose $Message
1256 Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource