Expert Solution for 2011 Scripting Games Beginner Event 2: Use PowerShell to Find Windows Services You Can Pause

Expert Solution for 2011 Scripting Games Beginner Event 2: Use PowerShell to Find Windows Services You Can Pause

  • Comments 8
  • Likes

Summary: Microsoft Windows PowerShell MVP, Shane Hoey, solves 2011 Scripting Games Event 2 by finding services that he can pause.

Microsoft Scripting Guy, Ed Wilson, here. Our expert commentator for Beginner Event 2 is Shane Hoey.

Photo of Shane Hoey

This is what Shane has to say about himself and his scenario:

My scripting experience started back when Windows XP was the new kid on the block, and I dabbled with VBScript, WMI, and ADSI. Fast forward to the 2009 Summer Scripting Games when I finally discovered Windows PowerShell—I have been hooked ever since. One of the things I like most about Windows PowerShell is its ability to easily automate, especially daily repetitive tasks. My background is system and network administration, but at work they just call me the PowerShell Geek these days. By the way, I also run the PowerShell Usergroup in Brisbane Australia (http://powershelldownunder.com), and you can follow me on twitter @shanehoey.

When I first started learning Windows PowerShell during the 2009 Scripting Games, I found one of the most challenging aspects was the concept of objects. With my sys-admin background, the GUI had always been my tool of choice, so understanding Windows PowerShell was a very foreign concept. PowerShell just seemed so complex and confusing with its execution policies, cmdlets, and a syntax that I thought only a developer would understand.

After the games finished, I decided to challenge myself and continue to learn PowerShell. One of the things I quickly learned was that Windows PowerShell is highly discoverable, and great amounts of information can be discovered by using the Get-Help, Get-Command, and Get-Member cmdlets. Never underestimate the importance of these three cmdlets.

Before we start today’s event, I’d like to explain how I came to script my solution. Generally whenever I start to write a new script I break it down to smaller steps, then while working interactively with the console, I’ll try to figure out how I can perform those smaller steps. Finally, I’ll start to create my script based on the information I learned while working interactively in the console.

Worked solution

Let’s start by using the Get-Command cmdlet to find the cmdlets that are related to services.

get-command *service

From this list, we can see that we need to use the Get-Service cmdlet. Now we use the Get-Help cmdlet to learn about using Get-Service.

get-help get-service -online

You may have noticed that I used the online parameter. This is a really cool parameter of the Get-Help cmdlet that can be used with cmdlet, function, and script Help topics. It will display the Help topic in the default browser.

After a quick read of the Help topic, you’ll notice that this cmdlet supports the computername parameter, which means that it will work on a local and on a remote computer. That’s a bonus for us because it will be easy to receive some bonus points for this event!

Now that we know how to use the Get-Service cmdlet, we need to find out what other bits of information Windows PowerShell can tell us. Remember everything that PowerShell returns is an object, and that object will have properties and methods. So to find this extra information, we pipe the Get-Service cmdlet to the Get-Member cmdlet, which returns a list of all the methods and properties of the objects.

get-service | get-member

The command and its associated output are shown in the following image.

From the output of this command, we can quickly find the properties that are required to complete our task, which in this case are CanPauseAndContinue, Status, Name, and DisplayName.

This is a good of example of how we can quickly discover information in PowerShell by using the Get-Help, Get-Command, and Get-Member cmdlets. We now have the information we need for a quick one-liner that meets the primary requirement and the first bonus item for today’s event.

Get-Service –ComputerName localhost | Where-Object { $_.CanPauseAndContinue} | Format-Table –Property Status,Name,DisplayName -Autosize

But we are not quite finished yet, let’s progress this one-liner into a script and try for a few more bonus points by taking the following into account:

  • By utilizing Help function tags, we can quickly produce standardized Help for our scripts, with the added benefit that they will integrate with the Get-Help cmdlet.
  • Ensure that a #requires –version 2.0 statement is included because the script will only execute in PowerShell 2.0
  • Use a Param statement so that we can use named arguments and validate parameter input.
  • Because the script will try to access remote computers, we should test the connection first with Test-Connection.
  • Whenever we have three or more conditional tests, use a switch statement as opposed to multiple if then else statements.
  • When using a switch statement it is a best practice to include a default condition. However, because we have already validated the parameter’s input, we can ignore a default condition.
  • Let’s aim for some bonus pointsby creating a switch parameter called GridView. When we include this parameter, it will display the results in a grid view window rather than in the console.

And here is our finished script...

<#

            .SYNOPSIS

            Script to retrieve information about services.

      .EXAMPLE

            .\Get-ServiceInfo.ps1

            Retrieve all services running on the local computer that can be Paused.

      .EXAMPLE

            .\Get-ServiceInfo.ps1 -CurrentState All -GridView

            Retrieve all services running on the local computer and display in a GridView.     

      .EXAMPLE

            .\Script.ps1 -Services S* -ComputerName <computername> -CurrentState CanStop -Sort DisplayName

            Retrieve all services starting with S, on a remote computer, that can be stopped, and sort by the DisplayName.

      .NOTES

            NAME: Get-ServiceInfo.ps1

            AUTHOR: Shane Hoey, powershelldownunder.com

            DATE: 3rd April 2011

#Requires -Version 2.0

#>

 

param(

 [string]$Name = '*',

 [string]$ComputerName = $env:computername,

 [ValidateSet('All','CanPause','CanContinue','CanPauseAndContinue','CanStop','CanShutdown')]

 [string]$CurrentState = 'CanPause',

 [ValidateSet('Status','Name','DisplayName')]

 [string]$Sort = 'Name',

 [switch]$GridView

)

 

If (Test-connection -ComputerName $ComputerName -count 1 -quiet)

{

 $svc = get-service $Name -computername $ComputerName

 

 switch($CurrentState)

 {

  'All' { }

  'CanPause' { $svc = $svc | Where-Object {$_.status -eq 'running' -and $_.CanPauseAndContinue} }

  'CanContinue' { $svc = $svc | Where-Object {$_.status -eq 'paused' -and $_.CanPauseAndContinue} }

  'CanPauseAndContinue' { $svc = $svc | Where-Object {$_.CanPauseAndContinue} }

  'CanStop'{ $svc = $svc | Where-Object {$_.CanStop} }

  'CanShutdown'{ $svc = $svc | Where-Object {$_.CanShutdown} }

 }

 if ($GridView)

 {    $svc | Select-Object -Property Status,Name,DisplayName | Sort-Object -Property $Sort | Out-GridView -Title 'Services - $CurrentState' }

 else

 { $svc | Select-Object -Property Status,Name,DisplayName | Sort-Object -Property $Sort | Format-Table -Autosize}

}

else

{

 "$ComputerName is Unreachable"

}

Thank you for writing this solution for Beginner Event 2, Shane.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • An excellent solution with a lot of extras and a detailed explanation how to get to the final solution ( and that's nearly the same approach, I usually use :-) But once again ... and I probably should stop mentioning that ... you don't handle the error I would definitly run into trying to use "$svc = get-service $Name -computername $ComputerName" where $ComputerName is the name of my office colleagues' computer!

    I can ping the machine and Test-Connection works! But I can't issue a "ps" command on his computer without errors! ( I know it for sure ... nosy as I am I already tried that :-)

    As you may all have an admin background, maybe that won't happen to you! But as I'm not ... though I sometimes would like to *sss* ...

    Well done anyway,

    kind regards, Klaus

  • I have a question.  When I would run the get-service | where-object {$_.CanPauseAndContinue -eq $True} against a service that was stopped the attribute was set to False, giving a "false negative" on the search.  What attribute/item would we look at for getting pausable services that were stopped?  Would we have to temporarily start all the services to get that attribute to report the proper setting?

  • I agree with cseiter, I ran into that all over the place. If a service was running and could pause it would return true, but if that same service were stopped, it would return false. I understand it's stopped, so it *can't* pause...but seems to me there might be someplace else that particular property would be persistent. I actually wrote up two different entries for this, the one I submitted used get-service, the second i didn't submit, used get-wmiobject. I thought perhaps by asking WMI for that information i would get a different answer...but apparently not.

    So as far as i was concerned i decided if the service wasn't running i didn't care...seems weak to me...but i had to make some sort of assumption.

  • oh, and really nice solution! sorry! should have said that first! lol

  • I just tried the –online parameter of PowerShell and found an error: In the German version (possibly in all international versions of PowerShell) the command "get-help get-server -online" does not work. The first URL in "Related Links" is wrong, there is an additional text:

    VERWANDTE LINKS

       Online version: go.microsoft.com/fwlink (möglicherweise auf Englisch)

    In the English version of PowerShell it is:

    RELATED LINKS

       Online version: go.microsoft.com/fwlink

    So the Browser opens the URL "go.microsoft.com/fwlink (möglicherweise auf Englisch)" which does not work. The Browser should only open the URL "go.microsoft.com/fwlink - or the text in the international help for PowerShell should only specify the URL without the addition of the text "(möglicherweise auf Englisch)".

    Kind regards, Frank

  • Hi Everyone, thanks for your comments,  

    Firstly to klaus you are indeed correct,  I broke the golden rule and assumed I had administrator access to the remote machine,  The script defiantly should have checked for admin access rather than just using test-connection and assuming I had administrator access.  A simple improvement on this script would be to use $erroractionpreference = 'inquire' which would have prompted us about the lack of privileges. There is a week of Hey Scripting Guy blogs dedicated to handling errors   http://bit.ly/go7u3d that you may be interested in to catch this type of error.

    Cseiter and Jeff, I found the same thing which was one of the reasons I added the canpause and cancontinue into the switch statement.  My take on this was once we stop a service, we can no longer determine if that service could be paused when running.  When you think about it makes sense, as when we run the get-service cmdlet we are querying the service at that point in time, and the properties should reflect that. Also how can we determine the state of a service in the future? for example, lets say we have 2 services, ServiceA and ServiceB, ServiceA is generally running and can be paused, however ServiceB is dependant on ServiceA, so if ServiceB is running then ServiceA can no longer be paused. I think the key here is that we are querying the service at this point in time, not the future, and CanPauseandContinue will reflect this.

    Hope that makes sense, it's a bit long winded so please reply back to this thread if you want more info,

    cheers

    Shane

  • Understandable.  I guesss that's more a feature of the service itself not being able to report all attributes when in different states rather than anything to do with PowerShell.  Thanks for the extra credit lesson.  I vaguely remember something about being able to run a powershell command in a test environment.  Would starting the service like that and getting the canpauseandcontinue status work with that?

  • thank you