32
votes

I want to create a Windows Service using Powershell. Creating it for a given user is piece of cake. I used this function adapted from here.

function ReinstallService1 ($serviceName, $binaryPath, $login, $pass)
{  
    Write-Host "installing service"
    # creating credentials which can be used to run my windows service
    $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
    $mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpasswd)

    # creating widnows service using all provided parameters
    New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic -credential $mycreds
    Write-Host "installation completed"
}

My question is: How can I create for "Network Service" account?

If I modify New-Service line and remove credential parameter, the service is created for "Local System" account. Nearly miss.

New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic 

I googled a lot and saw no way of indicating service account. If I try to use Credential parameter for user "NETWORK SSERVICE", I don't know what password to put and if I invent one (just in case cmdlet ignores it) it doesn't work. The error is:

New-Service : Service 'XXXX (XXXX)' cannot be created due to the following error: The account name is invalid or does not exist, or the password is invalid for the account name specified

4
Could you share your exact New-Service Line? When I use something like this: New-Service -name $serviceName -binaryPathName $path -displayName $serviceName -startupType Automatic -Credential "NT AUTHORITY\NETWORK SERVICE" I get a password prompt.Aniket
The problem is that you are passing only username in -Credential. My line is as yours but I pass -Credential $MyCreds $MyCreds value is: $MyCreds= $mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpasswd) $login value is "NT AUTHORITY\NETWORK SERVICE" $secpassword can be anything.Oscar Foley
@Aniket, I have added an answer with the final version of the script so you can see it better than in my comment...Oscar Foley

4 Answers

19
votes

The correct name of the account is NT AUTHORITY\NETWORK SERVICE.

15
votes

This is the final version of Reinstall Service for everyone's benefit, specially for Aniket.

function ReinstallService ($serviceName, $binaryPath, $description, $login, $password, $startUpType)
{
        Write-Host "Trying to create service: $serviceName"

        #Check Parameters
        if ((Test-Path $binaryPath)-eq $false)
        {
            Write-Host "BinaryPath to service not found: $binaryPath"
            Write-Host "Service was NOT installed."
            return
        }

        if (("Automatic", "Manual", "Disabled") -notcontains $startUpType)
        {
            Write-Host "Value for startUpType parameter should be (Automatic or Manual or Disabled) and it was $startUpType"
            Write-Host "Service was NOT installed."
            return
        }

        # Verify if the service already exists, and if yes remove it first
        if (Get-Service $serviceName -ErrorAction SilentlyContinue)
        {
            # using WMI to remove Windows service because PowerShell does not have CmdLet for this
            $serviceToRemove = Get-WmiObject -Class Win32_Service -Filter "name='$serviceName'"

            $serviceToRemove.delete()
            Write-Host "Service removed: $serviceName"
        }

        # if password is empty, create a dummy one to allow have credentias for system accounts: 
        #NT AUTHORITY\LOCAL SERVICE
        #NT AUTHORITY\NETWORK SERVICE
        if ($password -eq "") 
        {
            #$secpassword = (new-object System.Security.SecureString)
            # Bug detected by @GaTechThomas
            $secpasswd = (new-object System.Security.SecureString)
        }
        else
        {
            $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
        }
        $mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpasswd)

        # Creating Windows Service using all provided parameters
        Write-Host "Installing service: $serviceName"
        New-Service -name $serviceName -binaryPathName $binaryPath -Description $description -displayName $serviceName -startupType $startUpType -credential $mycreds

        Write-Host "Installation completed: $serviceName"

        # Trying to start new service
        Write-Host "Trying to start new service: $serviceName"
        $serviceToStart = Get-WmiObject -Class Win32_Service -Filter "name='$serviceName'"
        $serviceToStart.startservice()
        Write-Host "Service started: $serviceName"

        #SmokeTest
        Write-Host "Waiting 5 seconds to give time service to start..."
        Start-Sleep -s 5
        $SmokeTestService = Get-Service -Name $serviceName
        if ($SmokeTestService.Status -ne "Running")
        {
            Write-Host "Smoke test: FAILED. (SERVICE FAILED TO START)"
            Throw "Smoke test: FAILED. (SERVICE FAILED TO START)"
        }
        else
        {
            Write-Host "Smoke test: OK."
        }

}
6
votes

You could get a cred of network service straightforward like this:

$login = "NT AUTHORITY\NETWORK SERVICE"
#### #just set a dummy psw since it's just used to get credentials

$psw = "dummy"

$scuritypsw = ConvertTo-SecureString $psw -AsPlainText -Force

$mycreds = New-Object System.Management.Automation.PSCredential($login, $scuritypsw)
#### #then you can use the cred to new a windows service

$serviceName = "Test"
$binaryPath = "C:\Test\Test.exe"

New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic -credential $mycreds
0
votes

Get-WmiObject is deprecated now. However, PowerShell now has built in cmdlets to work with services. Here is the updated version of ReinstallService from Oscar Foley's answer tweaked accordingly along with convenient default values and wrappers to start and stop a service:

# https://stackguides.com/questions/35064964/powershell-script-to-check-if-service-is-started-if-not-then-start-it
function TryStopService([string] $serviceName)
{
    Write-Host "Attempting to stop service: $serviceName..."
    $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue

    if($service)
    {
        if ($service.Status -ne 'Running')
        {
            Write-Host "    Service: $serviceName is not running."
        }
        else
        {
            Stop-Service -name $serviceName
            Write-Host "    Stopped service: $serviceName."
        }
    }
    else
    {
        Write-Host "    Service: $serviceName is not found."
    }
}

function UninstallService([string] $serviceName)
{
    Write-Host "Attempting to uninstall service: $serviceName..."
    if (Get-Service $serviceName -ErrorAction SilentlyContinue)
    {
        Remove-Service -Name $serviceName
        Write-Host "    Uninstalled service: $serviceName."
    }
    else
    {
        Write-Host "    Service: $serviceName is not found."
    }
}

function StartSertice([string] $serviceName)
{
    Write-Host "Attempting to start service: $serviceName..."
    $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue

    if($service)
    {
        if ($service.Status -eq 'Running')
        {
            Write-Host "    Service: $serviceName is already running."
            return
        }
    }

    # Trying to start new service.
    Write-Host "    Trying to start new service: $serviceName."
    Start-Service -Name $serviceName

    #Check that service has started.
    Write-Host "    Waiting 5 seconds to give service time to start..."
    Start-Sleep -s 5
    $testService = Get-Service -Name $serviceName

    if ($testService.Status -ne "Running")
    {
        [string] $errMessage = "    Failed to start service: $serviceName"
        Write-Host $errMessage
        Throw $errMessage
    }
    else
    {
        Write-Host "    Started service: $serviceName."
    }
}

function ReinstallService ([string] $serviceName, [string] $binaryPath, [string] $description = "", [string] $login = "NT AUTHORITY\NETWORK SERVICE", [string] $password = "", [string] $startUpType = "Automatic")
{
    Write-Host "Attempting to reinstall service: $serviceName..."

    #Check Parameters
    if ((Test-Path $binaryPath)-eq $false)
    {
        Write-Host "    BinaryPath to service was not found: $binaryPath."
        Write-Host "    Service was NOT installed."
        return
    }

    if (("Automatic", "Manual", "Disabled") -notcontains $startUpType)
    {
        Write-Host "    Value for startUpType parameter should be (Automatic or Manual or Disabled) and it was $startUpType"
        Write-Host "    Service was NOT installed."
        return
    }

    TryStopService -serviceName $serviceName
    UninstallService -serviceName $serviceName

    # if password is empty, create a dummy one to allow having credentias for system accounts:
    #     NT AUTHORITY\LOCAL SERVICE
    #     NT AUTHORITY\NETWORK SERVICE
    if ($password -eq "")
    {
        $secpassword = (new-object System.Security.SecureString)
    }
    else
    {
        $secpassword = ConvertTo-SecureString $password -AsPlainText -Force
    }

    $mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpassword)

    # Creating Windows Service using all provided parameters.
    Write-Host "Installing service: $serviceName with user name: '$login'..."
    New-Service -name $serviceName -binaryPathName $binaryPath -Description $description -displayName $serviceName -startupType $startUpType -credential $mycreds
    Write-Host "    Installed service: $serviceName."

    # Trying to start new service.
    StartSertice -serviceName $serviceName
}