Posted by: Preetam | January 11, 2007

Managing remote/local services with Pow6r Sh6ll

When I was exploring various possibilites from Admin point of view in Powershell, I was never aware that such CMDLET would not work for managing servers remotely. However it was not difficult to implement it when blogs like http://thepowershellguy.com/blogs/posh/ are available on the Internet. I happen to see MOW blog entry on blogspot (http://mow001.blogspot.com/)and there I realized yeah it is possible to do everything remotely same as sysinternal tools can do it. Again .NET Classes.With this idea in my mind, I was able to convert my all existing CMDLETS for managing stuff remotely. For doing this you should be aware of one very important thing, which classes to load. For example if you run this script as it, it will error out

Unable to find type [System.ServiceProcess.ServiceController]: make sure that the assembly containing this type is loaded.

It means nothing but load the revelant classes before I can do anything. Let me admit it I don’t know which class to load but to get it work you just run get-services before running the script below. It will internally load the relevant classes. Of course if the information comes from POWERSHELL GURU’s, I will post it here.

Write-host $args[0]
$LikeVar= $args[1]
$remSVC=[System.ServiceProcess.ServiceController]::GetServices($args[0])
$remSVC where {$_.name -like $LikeVar}

Let’s come to the script.

$args[0] which is standard variable(default) will pick first word which I have assigned for computername and second variable is your servicename string. Remember I have selected servicename not displayname to query.Above CMDLET is similiar to sc query findstr /i al*

NOW it is .\svcvar.ps1 computername al*. Much simpler.

———————————————————————————————————————————————————————————
Now there is scenario where in you need to stop three services on 200 servers across Enterprize. In fact I got this idea because I had dealt with it in reality and I have us SC STOP stuff which was quite murky in a way.

$Services=get-content “E:\PowerShell\MakesSense\Ser-ices.txt”
$Servers=get-content “E:\PowerShell\MakesSense\Servers.txt”
ForEach($Server in $Servers) {
$LOADSVC=[System.ServiceProcess.ServiceController]::GetServices($Server)
foreach($service in $services) {
$REMSVC=$LOADSVC where {$_.name -eq $service}
if ($REMSVC.status -eq “Running”) {
Write-host $REMSVC.stop()
$REMsvc.WaitForStatus(“stopped”, (New-TimeSpan -seconds 3))
Write-host $REMsvc.displayname been successfully stopped on $server
}
elseif ($REMSVC.status -eq “Stopped”) {
Write-host $REMsvc.displayname is already in $REMsvc.status state on $server -foregroundcolor “RED”
}
else {
write-host Please check if $service Service exists on $server -foregroundcolor “RED”
}
}
}

Write services which you wish to stop in ser-ices.txt and servers in servers.txt on which you wish to manage services. And then code is typical VBSCript code. Most important (new) thing here is how INFANTLY (Simply) I can manage output with $REMsvc.displayname, $REMsvc.status which Re-emphasize DO MORE WITH LESS Principle.

Technorati tags:
del.icio.us tags:
IceRocket tags:

Responses

  1. this code will test if this dll is loaded allready and else load it

    if (-not ([appdomain]::CurrentDomain.getassemblies() |? {$_.ManifestModule -like “system.serviceprocess”})) {[void][System.Reflection.Assembly]::LoadWithPartialName(‘system.serviceprocess’)}

    Greetings /\/\o\/\/

  2. Hello-
    I am trying to use this example but keep getting errors at the line: $REMSVC=$LOADSVC where {$_.name -eq $service}

    The error is – Unexpected token ‘where’ in expression or statement.

    I must be missing something any help would be greatly appreciated.

    • @Mark

      The author just forgot the pipe.
      should be : $REMSVC=$LOADSVC | where {$_.name -eq $service}

      Thanks a lot Preetam, this works as a charm.

  3. Hi,
    I am trying to execute the above code (that checking for 3 services on 200 servers – i have used the name Status.ps1) through scheduled task.

    Through windows powershell 1.0 – it executes perfectly.
    ie D:\Report\Status.ps1 | out-file -filepath D:\Report\Rpt.txt

    How to set a scheduled task to call the above statement. If i give in schtasks – powershell.exe D:\Report\Status.ps1 | out-file -filepath D:\Report\Rpt.txt ,
    it is not working. Please help me out.
    how do i set the scheduled tasks to call powershell script that is creating out-file.

    Thanks,
    Natalie.

  4. i think you could have already got the solution, But simple thing to do is create bat file and paste the above command in it. This should call powershell and start the script. Also always visit powershell forum for fast solution.

    http://groups.google.com/group/microsoft.public.windows.powershell/topics?lnk=iggc

    – Preetam

  5. I am trying to execute the above script to start a service on remote server. However, that service is set with startup type = ‘Disabled’. How can I change the type to Manual before running this script?

  6. Celine,
    If service is disabled you wouldn’t be able to change startup type unfortunately. This is one of thing missing in get-service. you would probably have to rely on WMI, I would recommend you manage services using WMI, Powershell may not be right choice as of NOW.

    Get-WmiObject -Class win32_service | where{$_.startmode -eq “disabled”} and then you could use logic to change the status of service to manual and start it. Let me know if you need help on it further

  7. Say I am trying to start the spooler service on a remote server, so I write something like this:
    $Spooler = Get-WmiObject -Class win32_service | where{$_.name -eq “Spooler”}
    if ($Spooler.startmode = “disabled”)
    {
    $Spooler.startmode = “manual”
    $Spooler.put()
    }

    But the startmode didn’t get changed. What am I missing?

    Also, I have another way to update the registry value to change the startup mode from disabled to manual, but it requires the system to be rebooted for the change to take effects, would I need to reboot too if I change the startup mode via WMI?

  8. Below should work for you

    $SpoolerSVC=get-wmiobject -query “select * from win32_service where
    name=’spooler'”
    If($Spoolersvc.startmode -eq “Disabled”) {
    $spoolersvc.changestartmode(“Manual”)
    }

  9. Great!! That works. Thanks!

  10. Thanks for this info. For my purposes -filter was WAY faster than the above method, since the method “where {$_.name -eq $service}” seems to loop through every service name, which is very latency dependent/slow remotely. I’m only cycling one service, so my code was able to be simplified.

    I added some logic that checks every second to be sure the service stopped cleanly and then started cleanly. Works very well, but could probably be improved upon to exit after X seconds if the status doesn’t change.

    write-host “Cycling BESd UAC”
    [void] (Get-WmiObject -ComputerName $domino_uac_server -Class win32_service -Filter “name=’BESUserAdminService'” ).StopService()
    do { sleep 1 ; write-host “waiting for UAC to stop” } until ( (Get-WmiObject -ComputerName $domino_uac_server -Class win32_service -Filter “name=’BESUserAdminService'” ).state -eq “stopped” )
    [void] (Get-WmiObject -ComputerName $domino_uac_server -Class win32_service -Filter “name=’BESUserAdminService'” ).StartService()
    do { sleep 1 ; write-host “waiting for UAC to start” } until ( (Get-WmiObject -ComputerName $domino_uac_server -Class win32_service -Filter “name=’BESUserAdminService'” ).state -eq “running” )


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: