55

Does anyone have a Powershell script to change the credentials used by a Windows service?

2
  • Can you remove the bonus question text? I notice you posted that separately. Let's not confuse people and have the answers go to the wrong place. Commented Nov 24, 2008 at 13:35
  • 1
    Using sc.exe is also an option. Commented Apr 13, 2017 at 21:03

11 Answers 11

64

Bit easier - use WMI.

$service = gwmi win32_service -computer [computername] -filter "name='whatever'"
$service.change($null,$null,$null,$null,$null,$null,$null,"P@ssw0rd")

Change the service name appropriately in the filter; set the remote computer name appropriately.

Sign up to request clarification or add additional context in comments.

10 Comments

Just a note on this answer. If you want to update the user account, you need to be update the value preceding password. i.e. $service.change($null,$null,$null,$null,$null,$null,".\MyAccount","P@ssw0rd"). It seems you always need to prefix the account name with the domain name or ".\" otherwise it won't work. For more information regarding the other parameters please see here: msdn.microsoft.com/en-us/library/windows/desktop/…
Note that if you are specifying an account other than Local System as per @Rohland's comment above, you must also specify $false for parameter 6 ("DesktopInteract"). Only the Local System account can be granted permissions to interact with the desktop.
I had a lot of trouble with this approach... lots of assorted failures. I ended up finding that invoking sc was a lot more reliable: & sc.exe config "$servicename" obj= "[$domain\$username]" password= "[$password]" -- reference: stackoverflow.com/questions/308298
Instead of filtering on name, you can filter on DisplayName, might alleviate issues where there is a '$' in the name.
For anyone interested in the signature of that change() method of the Win32_Service class look here: msdn.microsoft.com/en-us/library/aa384901(v=vs.85).aspx
|
43

I wrote a function for PowerShell that changes the username, password, and restarts a service on a remote computer (you can use localhost if you want to change the local server). I've used this for monthly service account password resets on hundreds of servers.

You can find a copy of the original at http://www.send4help.net/change-remote-windows-service-credentials-password-powershel-495

It also waits until the service is fully stopped to try to start it again, unlike one of the other answers.

Function Set-ServiceAcctCreds([string]$strCompName,[string]$strServiceName,[string]$newAcct,[string]$newPass){
  $filter = 'Name=' + "'" + $strServiceName + "'" + ''
  $service = Get-WMIObject -ComputerName $strCompName -namespace "root\cimv2" -class Win32_Service -Filter $filter
  $service.Change($null,$null,$null,$null,$null,$null,$newAcct,$newPass)
  $service.StopService()
  while ($service.Started){
    sleep 2
    $service = Get-WMIObject -ComputerName $strCompName -namespace "root\cimv2" -class Win32_Service -Filter $filter
  }
  $service.StartService()
}

1 Comment

Great +1. You should edit and include usage line. Usage: Set-ServiceAcctCreds -strCompName "Computer1" -strServiceName "Service" -newAcct "DOM\ServiceUser" -newPass 'newSecureWord'
24

The PowerShell 6 version of Set-Service now has the -Credential parameter.

Here is an example:

$creds = Get-Credential
Set-Service -DisplayName "Remote Registry" -Credential $creds

At this point, it is only available via download via GitHub.

Enjoy!

2 Comments

I think -Credentials should actually be -Credential
Just want to say, anecdotally, that on Powershell 7.4.5 it appears that change() is no longer exposed on the Win32_Service object, possibly because Set-Service is the one true way going forward. As far as I know, the method hasn't been removed from the actual object and it appears when using Powershell 5.1 on the same machine. It's a shame since it means that working scripts will eventually fail when transitioning to new Powershell versions :(
16

I created a text file "changeserviceaccount.ps1" containing the following script:

$account="domain\user"
$password="passsword"
$service="name='servicename'"

$svc=gwmi win32_service -filter $service
$svc.StopService()
$svc.change($null,$null,$null,$null,$null,$null,$account,$password,$null,$null,$null)
$svc.StartService()

I used this as part of by post-build command line during the development of a windows service:

Visual Studio: Project properties\Build Events

Pre-build event command line:

"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.exe" myservice.exe /u

Post-build event command line:

"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.exe" myservice.exe
powershell -command - < c:\psscripts\changeserviceaccount.ps1

Comments

8

A slight variation on the other scripts here, is below. This one will set credentials for any/all services running under a given login account. It will only attempt to restart the service if it was already running, so that we don't accidentally start a service that was stopped for a reason. The script has to be run from and elevated shell (if the script starts telling you about ReturnValue = 2, you're probably running it un-elevated). Some usage examples are:

  • all services running as the currently logged in user, on the local host:

    .\set-servicecredentials.ps1 -password p@ssw0rd

  • all services running as user: somedomain\someuser on host somehost.somedomain:

    .\set-servicecredentials.ps1 somehost.somedomain somedomain\someuser p@ssw0rd

Set-ServiceCredentials.ps1:

param (
  [alias('computer', 'c')]
  [string] $computerName = $env:COMPUTERNAME,

  [alias('username', 'u')]
  [string] $serviceUsername = "$env:USERDOMAIN\$env:USERNAME",

  [alias('password', 'p')]
  [parameter(mandatory=$true)]
  [string] $servicePassword
)
Invoke-Command -ComputerName $computerName -Script {
  param(
    [string] $computerName,
    [string] $serviceUsername,
    [string] $servicePassword
  )
  Get-WmiObject -ComputerName $computerName -Namespace root\cimv2 -Class Win32_Service | Where-Object { $_.StartName -eq $serviceUsername } | ForEach-Object {
    Write-Host ("Setting credentials for service: {0} (username: {1}), on host: {2}." -f $_.Name, $serviceUsername, $computerName)
    $change = $_.Change($null, $null, $null, $null, $null, $null, $serviceUsername, $servicePassword).ReturnValue
    if ($change -eq 0) {
      Write-Host ("Service Change() request accepted.")
      if ($_.Started) {
        $serviceName = $_.Name
        Write-Host ("Restarting service: {0}, on host: {1}, to implement credential change." -f $serviceName, $computerName)
        $stop = ($_.StopService()).ReturnValue
        if ($stop -eq 0) {
          Write-Host -NoNewline ("StopService() request accepted. Awaiting 'stopped' status.")
          while ((Get-WmiObject -ComputerName $computerName -Namespace root\cimv2 -Class Win32_Service -Filter "Name='$serviceName'").Started) {
            Start-Sleep -s 2
            Write-Host -NoNewline "."
          }
          Write-Host "."
          $start = $_.StartService().ReturnValue
          if ($start -eq 0) {
            Write-Host ("StartService() request accepted.")
          } else {
            Write-Host ("Failed to start service. ReturnValue was '{0}'. See: http://msdn.microsoft.com/en-us/library/aa393660(v=vs.85).aspx" -f $start) -ForegroundColor "red"
          }
        } else {
          Write-Host ("Failed to stop service. ReturnValue was '{0}'. See: http://msdn.microsoft.com/en-us/library/aa393673(v=vs.85).aspx" -f $stop) -ForegroundColor "red"
        }
      }
    } else {
      Write-Host ("Failed to change service credentials. ReturnValue was '{0}'. See: http://msdn.microsoft.com/en-us/library/aa384901(v=vs.85).aspx" -f $change) -ForegroundColor "red"
    }
  }
} -Credential "$env:USERDOMAIN\$env:USERNAME" -ArgumentList $computerName, $serviceUsername, $servicePassword

1 Comment

@Kiquenet I've modified the script for you to prompt for credentials to the remote host.
5

Just making @alastairs's comment more visible: the 6th parameter must be $false instead of $null when you use domain accounts:

$service = Get-WMIObject -class Win32_Service -filter "name='serviceName'"
$service.change($null, $null, $null, $null, $null, $false, "DOMAIN\account", "mypassword")

Without that it was working for 4/5 of the services I tried to change, but some refused to be changed (error 21).

1 Comment

filter command should be -filter "name='serviceName'"
3

Considering that whithin this class:

$class=[WMICLASS]'\\.\root\Microsoft\SqlServer\ComputerManagement:SqlService'

there's a method named setserviceaccount(), may be this script will do what you want:

# Copyright Buck Woody, 2007
# All scripts provided AS-IS. No functionality is guaranteed in any way.
# Change Service Account name and password using PowerShell and WMI
$class = Get-WmiObject -computername "SQLVM03-QF59YPW" -namespace
root\Microsoft\SqlServer\ComputerManagement -class SqlService

#This remmed out part shows the services - I'll just go after number 6 (SQL
#Server Agent in my case):
# foreach ($classname in $class) {write-host $classname.DisplayName}
# $class[6].DisplayName
stop-service -displayName $class[6].DisplayName

# Note: I recommend you make these parameters, so that you don't store
# passwords. At your own risk here!
$class[6].SetServiceAccount("account", "password")
start-service -displayName $class[6].DisplayName

Comments

1
$svc = Get-WmiObject win32_service -filter "name='serviceName'"

the position of username and password can change so try this line to find the right place$svc.GetMethodParameters("change")

$svc.change($null,$null,$null,$null,$null,$null,$null,$null,$null,"admin-username","admin-password")

Comments

0

The given answers do the job.

Although, there is another important detail; in order to change the credentials and run the service successfully, you first have to grant that user account permissions to 'Log on as a Service'.

To grant that privilege to a user, use the Powershell script provided here by just providing the username of the account and then run the other commands to update the credentials for a service as mentioned in the other answers, i.e.,

$svc=gwmi win32_service -filter 'Service Name'

$svc.change($null,$null,$null,$null,$null,$null,'.\username','password',$null,$null,$null)

1 Comment

error gwmi : Invalid query "select * from win32_service where myservice"
0

Sc config example. First allowing modify access to a certain target folder, then using the locked down "local service" account. I would use set-service -credential, if I had PS 6 or above everywhere.

icacls c:\users\myuser\appdata\roaming\fahclient /grant "local service:(OI)(CI)(M)"
sc config "FAHClient" obj="NT AUTHORITY\LocalService"

Comments

-1

What I cannot find in the default PS stack, I find it implemented in Carbon:

http://get-carbon.org/help/Install-Service.html

http://get-carbon.org/help/Carbon_Service.html (Carbon 2.0 only)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.