3

I have a custom deployment script written in Powershell. This script needs to update a service on a remote machine, and as such, it first needs to stop it to be able to modify the executable files.

This seems to be a problem.

To synchronously stop a service, I can use net stop servicename or stop-service servicename. The problem is that these two commands are confined to the local machine.

To stop a service on a remote machine, I know I can use the sc.exe program:

sc.exe \\computername stop servicename

But this is asynchronous, so I can't really use it (well, sleep 5 seems to do it, but that's rather dirty).

How can I synchronously stop a remote service using Powershell?

1
  • Run a loop that queries the service status every couple of seconds?
    – Bob
    Jul 11, 2012 at 21:24

3 Answers 3

4

Get-Service returns a ServiceController object, which you can then use to manipulate the service. It doesn't matter whether it's local or remote. I have the script below to stop the Spooler (Print Spooler) service and wait for it to stop, up to 5 seconds. I just added the -Name parameter to Get-Service, and I was able to stop the spooler on a remote server.

Note: Both servers in my case were Server 2008 R2. Your mileage may vary.

Set-StrictMode -Version "2.0"

[System.ServiceProcess.ServiceController]$service = Get-Service -Name "Spooler" -ComputerName "remote_server.domain.com"

[int]$waitCount = 5
do
{
    $waitCount--

    switch($service.Status)
    {
        { @(
        [System.ServiceProcess.ServiceControllerStatus]::ContinuePending,
        [System.ServiceProcess.ServiceControllerStatus]::PausePending,
        [System.ServiceProcess.ServiceControllerStatus]::StartPending,
        [System.ServiceProcess.ServiceControllerStatus]::StopPending) -contains $_ }
        {
            # A status change is pending. Do nothing.
            break;
        }

        { @(
        [System.ServiceProcess.ServiceControllerStatus]::Paused,
        [System.ServiceProcess.ServiceControllerStatus]::Running) -contains $_ }
        {
            # The service is paused or running. We need to stop it.
            $service.Stop()
            break;
        }

        [System.ServiceProcess.ServiceControllerStatus]::Stopped
        {
            # This is the service state that we want, so do nothing.
            break;
        }
    }

    # Sleep, then refresh the service object.
    Sleep -Seconds 1
    $service.Refresh()

} while (($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) -and ($waitCount -gt 0))

There is also Set-Service that will accept a computer name parameter, but it does not seem to be able to stop a service if that service has dependent services.

2
  • It seems I don't have Powershell 2, but I was able to use New-Object System.ServiceProcess.ServiceController -ArgumentList myservice, myserver to get a handle. Also, I used the WaitForStatus method instead of looping with a sleep.
    – zneak
    Jul 12, 2012 at 14:08
  • I am trying to param-atize that little script you have and wrapping it in a function. However, When I add parameters I get a null parameter exception. Jan 10, 2014 at 20:18
2

PowerShell 2 added a lot of stuff for accessing remote computers with it.

Here's some useful cmdlets to look into (info from PowerShell's get-help):

Enter-PSSession:

SYNOPSIS
Starts an interactive session with a remote computer.

DESCRIPTION
The Enter-PSSession cmdlet starts an interactive session with a single remote computer. During the session, the commands that you type run on the remote computer, just as though you were typing directly on the remote computer. Youcan have only one interactive session at a time.

Typically, you use the ComputerName parameter to specify the name of the remote computer. However, you can also use a session that you create by using New-PSSession for the interactive session.

To end the interactive session and disconnect from the remote computer, use the Exit-PSSession cmdlet, or type "exit".

New-PSSession:

SYNOPSIS
Creates a persistent connection to a local or remote computer.

DESCRIPTION
The New-PSSession cmdlet creates a Windows PowerShell session (PSSession) on a local or remote computer. When you create a PSSession, Windows PowerShell establishes a persistent connection to the remote computer.

Use a PSSession to run multiple commands that share data, such as a function or the value of a variable. To run commands in a PSSession, use the Invoke-Command cmdlet. To use the PSSession to interact directly with a remote computer, use the Enter-PSSession cmdlet. For more information, see about_PSSessions.

Invoke-Command:

SYNOPSIS
Runs commands on local and remote computers.

DESCRIPTION
The Invoke-Command cmdlet runs commands on a local or remote computer and returns all output from the commands, including errors. With a single Invoke-Command command, you can run commands on multiple computers.

To run a single command on a remote computer, use the ComputerName parameter. To run a series of related commands that share data, create a PSSession (a persistent connection) on the remote computer, and then use the Session parameter of Invoke-Command to run the command in the PSSession.

More info: Hey, Scripting Guy! Tell Me About Remoting in Windows PowerShell 2.0

1
  • With PS2, you also have a ComputerName argument on Get-Service.
    – zneak
    Jul 13, 2012 at 13:48
1

I would look into something like PsExec. It will execute the net stop on the remote machine, and will thus get the synchronous part, but it can be done remotely (that is the point of PsExec after all).

2
  • That might be a good idea, but I'd rather not have to install anything new on my own machine.
    – zneak
    Jul 11, 2012 at 21:48
  • @zneak I hear that. Techie007's answer is the way to go then :)
    – soandos
    Jul 11, 2012 at 22:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .