How Can I Use Windows PowerShell to Start a Service on a Remote Computer?

How Can I Use Windows PowerShell to Start a Service on a Remote Computer?

  • Comments 7
  • Likes

Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I use Windows PowerShell to start a service on a remote computer?

-- NA

SpacerHey, Scripting Guy! AnswerTechNet Script Center

Hey, NA. You know, a few years ago a professor named Francis Fukuyama wrote a book called The End of History and the Last of Man, a book which stated (well, sort of) that now that the Cold War was over nothing particularly interesting and exciting would ever happen again. What do the Scripting Guys have to say to Dr. Fukuyama? Just this: ha!

Why are the Scripting Guys (of all people!) willing to challenge one of the foremost intellects of our generation? Well, for one thing, we’re willing to bet that Francis Fukuyama doesn’t read this column very often. More important, however, is the fact that we have proof that interesting and exciting things still do happen. After all, not only are we in the midst of the Hey, Scripting Guy! 500th column celebration, but now we’re answering our first-ever Windows PowerShell question. Take that, Francis Fukuyama!

Note. You say you’ve never even heard of Windows PowerShell? You say you have no idea what you can even do with Windows PowerShell? We say you should take a look at the new Script Center series What Can I Do With Windows PowerShell?

As you noted, NA, you’re trying to use the Start-Service cmdlet to restart a service on a remote computer, something like this (for educational purposes, we’ve simplified your script a little):

Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'" | Start-Service

In other words, you’re trying to connect to the Alerter service on the computer atl-fs-01, and then “pipe” that object to the Start-Service cmdlet. As you noted, you’re able to connect to the Alerter service on the remote computer without any problem. When you call Start-Service, however, the command fails, even though the Start-Service cmdlet works just fine on your local computer.

And that’s the problem right there. Windows PowerShell is an interesting and powerful new technology, but (at the time we’re writing this column of course) it’s still in beta; among other things, that means that some of the features that are expected to appear in the released version of the product aren’t ready just yet. Unfortunately, one of those features is the ability to run cmdlets against remote computers. Someday you should be able to start a service on a remote computer using a command similar to this:

Start-Service alerter -computer atl-fs-01

But not today.

So then why are you able to get information about the Alerter service on the remote computer? Well, as it turns out, the Get-WMIObject cmdlet is an exception to the rule: because it piggybacks onto WMI, Get-WMIObject can do anything WMI can do. That’s why Get-WMIObject can operate against remote computers: rather than relying on Windows PowerShell cmdlets to make the connection and carry out its tasks Get-WMIObject uses WMI to take care of business.

A general rule of thumb: you can use Get-WMIObject to work with remote computers, providing, of course, that you’re using WMI properties and methods. Otherwise, you’re limited to working against the local computer when using Windows PowerShell. (And, yes, that will change, although we can’t say for sure when remote computer capabilities will be added to Windows PowerShell.)

So does that mean we can use Get-WMIObject and a standard WMI method (like, say, StartService) to start a service on a remote computer? As a matter of fact it does, although even here there’s a bit of a trick involved. Let’s show you the Windows PowerShell script/command that will start a service on a remote computer, and then see if we can explain how it works:

(Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'").InvokeMethod`
("StartService",$null)

There are really two parts to this command, the part that connects to the Alerter service and the part that starts the service. Let’s start with Part 1, the part that connects us to the WMI service:

(Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'")

What we’re doing here is connecting to the WMI service on the computer atl-fs-01 and retrieving all instances of the Win32_Service class where the Name property is equal to Alerter. What we have here is equivalent to the following VBScript code:

Set objWMIService = GetObject("winmgmts:\\atl-fs-01")

Set colServiceList = objWMIService.ExecQuery _
    ("Select * From Win32_Service Where Name='Alerter'")

Notice that we don’t call the ExecQuery method in our Windows PowerShell command; instead we use the -Filter parameter, specifying that the only services we want back are those where the Name is equal to Alerter.

Good question: why did we put parentheses around our Get-WMIObject statement? We did that to ensure that Windows PowerShell treats the returned object as an object, that is, as something we can call a method on. And once we have an object we can then follow the closing parenthesis with a dot (.), just like we would using VBScript. In our Windows PowerShell command we do this:

(Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'").InvokeMethod`
("StartService",$null)

Whereas in VBScript we’d do something like this (most often inside a For Each loop):

objItem.StartService

Got that? OK. Now it gets tricky. As you can see, in the second part of our command, we don’t directly call the StartService method. Instead, we do this:

InvokeMethod("StartService",$null)

What’s the deal with that? Well, as it turns out, we do get an object back when we call Get-WMIObject; in this case, however, it’s a .NET Framework object (specifically, a System.Management.ManagementObject#root\cimv2\Win32_Service object). We can’t call the StartService method for one simple reason: this type of object doesn’t have a StartService method. Instead, we call InvokeMethod, passing two parameters:

“StartService”, the name of the WMI method we want to invoke.

$Null, which simply indicates a Null value.

InvokeMethod expects two parameters: the method to be called, followed by any additional arguments needed by the method. In this case there are no method arguments; however, InvokeMethod expects two parameters whether those parameters exist or not. To satisfy InvokeMethod we pass a null value as the second parameter.

That’s another good question: how did we know that the object we got back was a System.Management.ManagementObject#root\cimv2\Win32_Service object, and that this object didn’t support the StartService method? Well, we’d like to tell you that this is because we’re all really smart and we know anything; however, we didn’t think anyone would buy that. Therefore, we’ll tell you the truth: we grabbed the object in question and ran it through the Get-Member cmdlet in order to get back a list of its properties and methods. In other words, we did this:

Get-WmiObject Win32_Service -Filter "Name='Alerter'" | Get-Member

From there we simply engaged in a little old-fashioned trial and error until we figured out how to start the service.

A caveat or two. The command we came up with works just fine, but we wouldn’t go so far as to say that it’s the best way to do this, or even that it’s the only way to do this. If anyone knows of a better way to carry out this same task using Windows PowerShell, please let us know; after all, we’re still learning about this new technology ourselves. (Francis Fukuyama, we’re especially interested in hearing from you!)

Likewise, in the interest of keeping this discussion at a relatively superficial level, we skipped over some technical details concerning what Windows PowerShell does, and why. But those aren’t important right now; for now, we just wanted you to give a basic idea of how Windows PowerShell works, as well as why it doesn’t work (at least not yet) in certain situations. Oh: and also show you how to use Windows PowerShell to start a service on a remote computer. That was all we were hoping to accomplish today.

Well, that and prove to the world that interesting and exciting things still happen. And we consider that to be a job well-done.

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi, thanks for post very helpfull.

    I basically did everything the same but i found out that (Get-WmiObject -computerName ComputerName Win32_Service -Filter "Name='ServiceName'") doesn't contain InvokeMethod instead i use

    (Get-WmiObject -computerName  ComputerName Win32_Service -Filter "Name='ServiceName'").StartService()

    thanks

  • #######################################

    ## Your new reg add psremoting Vista ##

    #######################################

    ## By Rossco                         ##

    #######################################

    $ComputerArray = "Server1", "Server2"

    $serviceArray = "WinRM", "RasAuto",  "RpcLocator", "RemoteRegistry", "RemoteAccess"

    Import-Module PSRemoteRegistry

    foreach ($Computer in $ComputerArray)

    {

    foreach ($service in $serviceArray)

    {

    set-service "$service" -startuptype Automatic -passthru -computername $computer

    set-service "$service" -status Running -passthru -computername $computer

    }

    $computer | New-RegKey -Key SOFTWARE\Microsoft\PowerShell\1\ShellIds -Name ScriptedDiagnostics -PassThru |

    Set-RegString -Value ExecutionPolicy -Data Unrestricted -Force -PassThru |

    Set-RegString -Key SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell -Value ExecutionPolicy -Data Unrestricted -Force

    }

    #End

  • I had issues on some services using the above methods.

    After a bit of playing around I found this worked for me and is heaps easier.

    Store your service in a variable however you like, EG:

    $svc = Get-Service -computername <servername> -display <display name of service>

    ...and then use the stop and start methods, EG:

    $svc.Stop()

    $svc.Start()

  • Hi, thanks for the tips.

    @9 : use so much convenient pipes :

    > Get-Service -ComputerName myserver | Where-Object { $_.Name -imatch "Backupexec" } | ForEach-Object {$_.Start() }

    and if you prefer to check before :

    > Get-Service -ComputerName myserver | Where-Object { $_.Name -imatch "Backupexec" } | Format-List *

    nb : tested in PS v2

  • You can restart a service on remote computer much easily using below method.

    techibee.com/.../1201

  • Having issues using this with variables as a server and service on windows 7.  The following is working on my XP machine.  Both are running the same version of powershell 2

    (Get-WmiObject -computer $computer Win32_Service -Filter "Name='$servicename'").InvokeMethod`("StartService",$null)

  • I have a weird situation: When I go to the service properties and enter log in credentials, permission is granted and I can start, stop and/or restart the service. But the password seems to get corrupted. The next day if I try to stop/(re)start the service I cannot because of log in failure. If I re-enter my password, permission is granted and I can start or restart the service. Is there some way to automate the starting of the service and pass in log in and password values? I don't see those as parameters I can pass in or reset.