Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

More PowerShell Toolmaking Fun

Posted on September 15, 2014September 11, 2014

blacksmith I am having so much fun making my own PowerShell tools that I just can't stop. I've been using my Get-Commandmetadata function that I wrote about a few weeks ago. A driving force in all of this is to have a toolset that I can use efficiently from the console. Or to put it in terms you might appreciate: the biggest bang for the least amount of typing. Today, I have another example. I took a common PowerShell expression and simplified it into its own command. And even though the final code looks like a lot, it didn't take me very long because my toolmaking tool "wrote" most of the script for me.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

So the common task is finding services that match a certain state such as running or stopped. You've most likely seen this expression:

get-service -computername server01 | where {$_.status -eq 'running'}

Not the most onerous command to type, but even I have mistyped and had to correct. If this is a common task, why not create an easy to use tool?

#requires -version 3.0

Function Get-MyService {
 <# 
 .Synopsis
 Get services by status.
 .Description
 This is a proxy version of Get-Service. The only real change is that you can specify services by their status. The default is to get all running services.
 .Notes
 Created:	9/11/2014 

 Learn more:
  PowerShell in Depth: An Administrator's Guide (http://www.manning.com/jones6/)
  PowerShell Deep Dives (http://manning.com/hicks/)
  Learn PowerShell 3 in a Month of Lunches (http://manning.com/jones3/)
  Learn PowerShell Toolmaking in a Month of Lunches (http://manning.com/jones4/)
  
    ****************************************************************
    * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
    * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *
    * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
    * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *
    ****************************************************************
 
 .Example
 PS C:\> Get-MyService b* -status stopped -comp chi-dc04

Status   Name               DisplayName                           
------   ----               -----------                           
Stopped  BITS               Background Intelligent Transfer Ser...
 
 .Link
 Get-Service
 
 #>

[CmdletBinding(DefaultParameterSetName='Default', RemotingCapability='SupportedByCommand')]
 param(
     [Parameter(ParameterSetName='Default', Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
     [Alias('ServiceName')]
     [string[]]$Name, 
     [ValidateNotNullorEmpty()]
     [System.ServiceProcess.ServiceControllerStatus]$Status="Running",
     [Parameter(ValueFromPipelineByPropertyName=$true)]
     [Alias('Cn')]
     [ValidateNotNullOrEmpty()]
     [string[]]$ComputerName = $env:COMPUTERNAME, 
     [Alias('DS')]
     [switch]$DependentServices, 
     [Alias('SDO','ServicesDependedOn')]
     [switch]$RequiredServices, 
     [Parameter(ParameterSetName='DisplayName', Mandatory=$true)]
     [string[]]$DisplayName, 
     [ValidateNotNullOrEmpty()]
     [string[]]$Include, 
     [ValidateNotNullOrEmpty()]
     [string[]]$Exclude, 
     [Parameter(ParameterSetName='InputObject', ValueFromPipeline=$true)]
     [ValidateNotNullOrEmpty()]
     [System.ServiceProcess.ServiceController[]]$InputObject
  ) 
  
 begin {
 
     Write-Verbose -Message "Starting $($MyInvocation.Mycommand)"  

     Write-Verbose "Getting services with a status of $status on $($Computername.toUpper())"
 
     try {
         $outBuffer = $null
         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
         {
             $PSBoundParameters['OutBuffer'] = 1
         }

         #remove Status parameter from bound parameters since Get-Service won't recognize it
         $PSBoundParameters.Remove("Status") | Out-Null

         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Get-Service', [System.Management.Automation.CommandTypes]::Cmdlet)
         #$scriptCmd = {& $wrappedCmd @PSBoundParameters }
         #my modified command 
         $scriptCmd = {& $wrappedCmd @PSBoundParameters | Where-Object {$_.status -eq $Status } }
         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
         $steppablePipeline.Begin($PSCmdlet)
     } catch {
         throw
     }
 } #begin
 
 process  {
     try {
         $steppablePipeline.Process($_)
     } catch {
         throw
     }
 } #process
 
 end {
     try {
         $steppablePipeline.End()
     } catch {
         throw
     }
     Write-Verbose -Message "Ending $($MyInvocation.Mycommand)" 
 } #end
  
} #end function Get-MyService

set-alias -Name gsv2 -Value Get-MyService

Yes, I could have written my own function that called Get-Service, but then I'd have to write all of the code to accommodate all of the parameters for Get-Service. With the proxy command, all I need to do is insert my own code.

#my modified command 
$scriptCmd = {& $wrappedCmd @PSBoundParameters | Where-Object {$_.status -eq $Status } }

In other words, I let Get-Service do its thing and then filter the result. Now I can easily do this:

PS C:\Scripts> get-myservice w* -Status stopped -ComputerName chi-dc01

Status   Name               DisplayName                           
------   ----               -----------                           
Stopped  wbengine           Block Level Backup Engine Service     
Stopped  WbioSrvc           Windows Biometric Service             
Stopped  WcsPlugInService   Windows Color System                  
Stopped  WdiServiceHost     Diagnostic Service Host               
Stopped  WdiSystemHost      Diagnostic System Host                
Stopped  Wecsvc             Windows Event Collector               
Stopped  WinHttpAutoProx... WinHTTP Web Proxy Auto-Discovery Se...
Stopped  wmiApSrv           WMI Performance Adapter               
Stopped  wudfsvc            Windows Driver Foundation - User-mo...

Or, because I'm typing this, I could use my own alias.

One thing I want to point out, is that for the new Status property, you'll notice I didn't cast it as a string.

[System.ServiceProcess.ServiceControllerStatus]$Status="Running"

I could have made it a string, but by using the actual enumeration, PowerShell will autocomplete possible values.
get-myservice

How did I know what to use? I used Get-Member.

PS C:\Scripts> get-service bits | get-member status

   TypeName: System.ServiceProcess.ServiceController

Name   MemberType Definition                                                 
----   ---------- ----------                                                 
Status Property   System.ServiceProcess.ServiceControllerStatus Status {get;}

It is really not that difficult or time consuming. I spent more time writing this blog post than I spent creating the function.

I hope this will inspire you to create your own PowerShell tools and that you will share the fruits of your labors.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

3 thoughts on “More PowerShell Toolmaking Fun”

  1. jvierra says:
    September 15, 2014 at 11:42 am

    Another excellent article.
    .

  2. simzdkon says:
    September 16, 2014 at 4:04 am

    How would you build startup type into this?

    1. Jeffery Hicks says:
      September 16, 2014 at 12:03 pm

      You can’t use Get-Service for that because the System.ServiceProcess.ServiceController class that the cmdlet uses doesn’t have a property for StartUp type. You can use WMI and query the Win32_Service class to get that information.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d