diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs
index c8986ab7089..61d4232705d 100644
--- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs
+++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs
@@ -1466,6 +1466,14 @@ public class SetServiceCommand : ServiceOperationBaseCommand
}
internal string displayName = null;
+ ///
+ /// Account under which the service should run
+ ///
+ ///
+ [Parameter]
+ [Credential()]
+ public PSCredential Credential { get; set; }
+
///
@@ -1589,6 +1597,7 @@ protected override void ProcessRecord()
{
ServiceController service = null;
string ServiceComputerName = null;
+ IntPtr password = IntPtr.Zero;
foreach (string computer in ComputerName)
{
bool objServiceShouldBeDisposed = false;
@@ -1679,9 +1688,9 @@ protected override void ProcessRecord()
continue;
}
- // modify startup type or display name
+ // Modify startup type or display name or credential
if (!String.IsNullOrEmpty(DisplayName)
- || (ServiceStartMode)(-1) != StartupType)
+ || (ServiceStartMode)(-1) != StartupType || null != Credential)
{
DWORD dwStartType = NativeMethods.SERVICE_NO_CHANGE;
switch (StartupType)
@@ -1701,6 +1710,13 @@ protected override void ProcessRecord()
"bad StartupType");
break;
}
+
+ string username = null;
+ if (null != Credential)
+ {
+ username = Credential.UserName;
+ password = Marshal.SecureStringToCoTaskMemUnicode(Credential.Password);
+ }
bool succeeded = NativeMethods.ChangeServiceConfigW(
hService,
NativeMethods.SERVICE_NO_CHANGE,
@@ -1710,8 +1726,8 @@ protected override void ProcessRecord()
null,
IntPtr.Zero,
null,
- null,
- IntPtr.Zero,
+ username,
+ password,
DisplayName
);
if (!succeeded)
@@ -1847,6 +1863,10 @@ protected override void ProcessRecord()
} //End try
finally
{
+ if (IntPtr.Zero != password)
+ {
+ Marshal.ZeroFreeCoTaskMemUnicode(password);
+ }
if (objServiceShouldBeDisposed)
{
service.Dispose();
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1
index 5a30db2fe0b..10ae344eb79 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1
@@ -110,6 +110,39 @@ Describe "Set/New-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows"
$newServiceCommand.$parameter | Should Be $value
}
+ It "Set-Service can change credentials of a service" {
+ try {
+ $startUsername = "user1"
+ $endUsername = "user2"
+ $testPass = "Secret123!"
+ $servicename = "testsetcredential"
+ net user $startUsername $testPass /add > $null
+ net user $endUsername $testPass /add > $null
+ $password = ConvertTo-SecureString $testPass -AsPlainText -Force
+ $creds = [pscredential]::new(".\$startUsername", $password)
+ $parameters = @{
+ Name = $servicename;
+ BinaryPathName = "$PSHOME\powershell.exe";
+ StartupType = "Manual";
+ Credential = $creds
+ }
+ $service = New-Service @parameters
+ $service | Should Not BeNullOrEmpty
+ $service = Get-CimInstance Win32_Service -Filter "name='$servicename'"
+ $service.StartName | Should BeExactly $creds.UserName
+
+ $creds = [pscredential]::new(".\$endUsername", $password)
+ Set-Service -Name $servicename -Credential $creds
+ $service = Get-CimInstance Win32_Service -Filter "name='$servicename'"
+ $service.StartName | Should BeExactly $creds.UserName
+ }
+ finally {
+ Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue
+ net user $startUsername /delete > $null
+ net user $endUsername /delete > $null
+ }
+ }
+
It "New-Service can create a new service called ''" -TestCases @(
@{name = "testautomatic"; startupType = "Automatic"; description = "foo" ; displayname = "one"},
@{name = "testmanual" ; startupType = "Manual" ; description = "bar" ; displayname = "two"},