Back to top

FREE eBook: The Most USEFUL PowerShell CmdLets and more…

Grab a copy!

Write Own Powershell CmdLet That Handles Windows Services

Write Own Powershell CmdLet That Handles Windows Services
Approx Reading Time: 60 minutes

Windows Services are a vital part of Windows System and can be a vital part of some Application Solution as well so it is very important to have an overview and handle the Windows Services properly and efficiently both on the local machine and the remote servers.

In this article, we will show you how you can write your own PowerShell CmdLet that can handle Windows services and that means to get and change Windows Services properties, stop, start, restart, pause, resume, add new and delete Windows Services.

We have already written an article that handles the Windows Services using PowerShell with examples in a step by step fashion so please we highly recommend to you to read that article hand in hand with this article since both are very useful and on the topic of handling Windows Services using PowerShell.

So please read the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps” as well.

Handle Windows Services Using PowerShell With Easy Steps
Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

So let’s dive into the code of Use-WS PowerShell CmdLet.

How To Use Use-WS CmdLet – Tips

First, let’s try a few calls to Use-WS PowerShell CmdLet so we can see its capabilities, and later we can show you how we have done this by diving into the code.

Get Windows Service Properties Using Use-WS PowerShell CmdLet

This example will show to us Telephony Windows Service Properties on the local machine.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" 

Here is the result of above line of code.

Get Windows Service Properties using Use-WS CmdLet on local machine

If we want to get windows service properties on the remote servers we have several options.

We can use the computers input parameter of Use-WS PowerShell CmdLet and provide an array of strings that represents names of the remote servers (in my example we have used localhost twice just to mimick network):

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -computers 'localhost', 'localhost' | Out-GridView

Here is the result of above code in the PowerShell Grid.

Windows Service Properties using Use-WS CmdLet on remote servers

We can PowerShell Pipeline array of strings that represents the names of the remote servers into the Use-WS PowerShell CmdLet (in this example localhost has been used twice just to mimick network):

'localhost', 'localhost' | Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" | Out-GridView

Here is the result of above code in the PowerShell Grid.

Windows Service Properties using Use-WS CmdLet on remote servers

If we have lots of servers it is not convenient to list them as an array of strings since the code can be very long and cumbersome so we can use the filename input parameter of Use-WS with a value of the text file that contains all the remote servers names.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -filename "OKFINServers.txt" | Out-GridView

Here is the result of above code in the PowerShell Grid.

Windows Service Properties using Use-WS CmdLet on remote servers

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to get Windows Service Properties please read the Get section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Start Windows Service Using Use-WS PowerShell CmdLet

Let’s try to start Windows Service using Use-WS PowerShell CmdLet.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Start to tell the Use-WS CmdLet to run the part of the code dedicated for starting windows services.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Start

Here is the result of running the above line of code and we can see that Telephony windows service has been started.

Start Windows Service using Use-WS CmdLet on the local machine

If we want to start Windows Services on remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and again the action input parameter is on value Start.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Start -filename "OKFINServers.txt"

Here is the result of running the above line of code and we can see that Telephony windows service has been started and running.

Start Windows Services using Use-WS CmdLet on the remote machines

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to start Windows Services please read the Start section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Stop Windows Service Using Use-WS PowerShell CmdLet

Here we can test how we can stop Windows Service using Use-WS PowerShell CmdLet.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Stop to tell the Use-WS CmdLet to run the part of the code dedicated for stopping windows services.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Stop

Here is the result of running the above line of code and we can see that Telephony windows service has been stopped.

Stop Windows Service using Use-WS CmdLet on local machine

If we want to stop Windows Services on remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and again the action input parameter is on value Stop.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Stop -filename "OKFINServers.txt"

Here is the result of running the above line of code.

Stop Windows Services using Use-WS CmdLet on remote machines

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to stop Windows Services please read the Stop section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Restart Windows Service Using Use-WS PowerShell CmdLet

Now is the time to test the restarting of Windows Services using Use-WS PowerShell CmdLet.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Restart to tell the Use-WS CmdLet to run the part of the code dedicated for restarting windows services.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Restart

Here is the result of running the above line of code and we can see that Telephony windows service has been started and running after the restart.

Restart Windows Service using Use-WS CmdLet on the local machine

If we want to restart Windows Services on remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and the action input parameter is on value Restart.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Restart -filename "OKFINServers.txt" 

Here is the result of running the above line of code.

Restart Windows Services using Use-WS CmdLet on the remote machines

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to restart Windows Services please read the Restart section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Pause (Suspend) Windows Service Using Use-WS PowerShell CmdLet

Let’s now test how to suspend (pause) Windows Service using Use-WS PowerShell CmdLet.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Suspend to tell the Use-WS CmdLet to run the part of the code dedicated for pausing windows services.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Suspend

Here is the result of running the above line of code and we can see that Telephony windows service has been paused.

Pause (Suspend) Windows Service using Use-WS CmdLet on the local machine

If we want to pause (suspend) Windows Services on remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and the action input parameter is on value Suspend.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Suspend -filename "OKFINServers.txt"

Here is the result of running the above line of code and we can see that Telephony windows service has been paused.

Pause (Suspend) Windows Service using Use-WS CmdLet on the remote machines

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to pause (suspend) Windows Services please read the Pause (Suspend) section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Resume Windows Service Using Use-WS PowerShell CmdLet

If you have wondered can we resume Windows Service that has been paused using Use-WS PowerShell CmdLet the simplest answer is yes and here we will show you how you can do it.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Resume to tell the Use-WS CmdLet to run the part of the code dedicated for resuming windows services.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Resume

Here is the result of running the above line of code and we can see that Telephony windows service has been started after has been paused.

Resume Windows Service using Use-WS CmdLet on the local machine

If we want to resume Windows Services on remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and the action input parameter is on value Resume.

Use-WS -client "OK" -solution "FIN" -errorlog -name "TapiSrv" -action Resume -filename "OKFINServers.txt"

Here is the result of running the above line of code and we can see that Telephony windows service has been started and running again after being paused.

Resume Windows Service using Use-WS CmdLet on the remote machines

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to resume Windows Services after being paused please read the Resume section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Change (Set) Windows Service Properties Using Use-WS PowerShell CmdLet

Here we will see how to change (set) Windows Service Properties using Use-WS PowerShell CmdLet.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

It is important to say that we can change only three properties (Display Name, Description, and Startup Type) using this feature of Use-WS CmdLet.

Let’s first see the Windows Service Properties unchanged first (marked with yellow rectangular) and then we will apply the changes and see how it goes.

Windows Service current properties before change using Use-WS PowerShell CmdLet

We use the Action input parameter with the value Set to tell the Use-WS CmdLet to run the part of the code dedicated for setting (changing) windows services and we provide the new values for Display Name, Description, and Startup Type properties.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -DisplayName "New Con Deamon WS" -description "Windows Service New Description" -StartupType Disabled -action Set

Here is the result of running the above code and notice the values changed for properties Display Name, Description, and Startup Type (marked with yellow rectangular).

Windows Service properties changed on local machine using Use-WS CmdLet

If we want to change Windows Services Properties on remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and the action input parameter is of value Set.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -DisplayName "New Con Deamon WS" -description "Windows Service New Description" -StartupType Disabled -action Set -filename "OKFINServers.txt"

Since the previous line of code doesn’t return any feedback on the changes we have just done need to run the following line of code in order to check if changes have been applied. Basically we get the properties of windows services that has been just changed.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -filename "OKFINServers.txt" | Out-GridView

The result has been presented in PowerShell Grid and notice all windows services have changed Display Name, Description, and Startup Type values changed.

Windows Services Properties changed on remote servers using Use-WS CmdLet

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to change (set) Windows Services Properties please read the Change (Set) section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Add New Windows Service Using Use-WS PowerShell CmdLet

We can add a new Windows Service using Use-WS PowerShell CmdLet and here we will show you how.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Add to tell the Use-WS CmdLet to run the part of the code dedicated for adding new windows services combined with the BinaryPathName input parameter which provides the value for the file path to the Windows Service executable file.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -BinaryPathName "C:\Temp\WS\ConDaemon.exe" -action Add

Here is the result of running the above code.

Added New Windows Service using Use-WS CmdLet

If we want to know all the properties of the newly added Windows Service we can always run the following line of code.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon"

Here is the result that shows to us all the Windows Service Properties.

Windows Service Properties using Use-WS CmdLet

If we want to add new Windows Services on the remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and the action input parameter is of value Add combined with the BinaryPathName input parameter which provides the value for the file path to the Windows Service executable file.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -BinaryPathName "C:\Temp\WS\ConDaemon.exe" -action Add -filename "OKFINServers.txt" 

Here is the result of running the above line of code.

Windows Services Added using Use-WS CmdLet

If we want to list all the Windows Service Properties on the remote systems we can run this line of code.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -filename "OKFINServers.txt" | Out-GridView

Here is the result of above code in PowerShell Grid.

New Added Windows Services on the remote servers using Use-WS CmdLet

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to add new Windows Services to the system please read the Add New section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Delete Windows Service Using Use-WS PowerShell CmdLet

Since we can add a new Windows Service it is smart to be able to Remove (Delete) Windows Service using Use-WS PowerShell CmdLet providing that we want or need to do that.

NOTE: It is very important to start PowerShell Console as Administrator in order to have enough permissions for manipulating Window Services.

We use the Action input parameter with the value Delete to tell the Use-WS CmdLet to run the part of the code dedicated for deleting windows services.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -action Delete

Here is the result of running the above line of code. Notice that the value for the property Return Value is 0 and that tells us that Windows Service has been deleted successfully.

Windows Service deleted using Use-WS CmdLet on the local machine

We can also run the following line of code that will confirm to us that Windows Service has been removed from our system since cannot be found.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon"

Here is the result of running the above line of code.

Windows Service cannot be found since has been removed using Use-WS CmdLet

If we want to delete (remove) Windows Services from the remote machines using Use-WS CmdLet we have several options as we have seen in how to Get Windows Service Properties but here we will focus on using the filename input parameter with the name of the text file that holds the list of remote servers and the action input parameter is of value Delete.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -action Delete -filename "OKFINServers.txt" 

Here is the result of running the above line of code and again notice the value for Return Value property is 0 meaning that windows service has been deleted.

Windows Service deleted using Use-WS CmdLet on the remote machines

Again we can check that all the Windows Services from remote machines have been removed using the following line of code.

Use-WS -client "OK" -solution "FIN" -errorlog -name "ConDaemon" -filename "OKFINServers.txt"

This time we are getting errors but that is what we exactly want to happen since this confirms that the Windows Services cannot be found on the systems anymore and have been successfully removed.

Windows Services cannot be found on the remote machines using Use-WS CmdLet

The content of the text file that holds the list of remote computers is like this, please replace the values with the list of your own servers. For the sake of mimicking the network, we have copied localhost multiple times.

List of “remote” computers in text file

INFO: For a more step by step approach when you want to delete (remove) Windows Services from the system please read the Delete (Remove) section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Use-WS CmdLet Explained

Use-WS CmdLet handles (get, set, start, stop, restart, pause, resume, add, remove) Windows Services both on the local machine and remote servers for the list of servers and this CmdLet belongs to Efficiency Booster PowerShell Project. This project is the library of different CmdLets that can help us IT personal to do our everyday tasks more efficiently and accurately.

Source code for Use-WS CmdLet can be downloaded from this zip file so please feel free to download it and it would be easier for you to follow me along.

Use-WS CmdLet is part of Common module and if you have downloaded the source code it can be found in the folder …\[My] Documents\WindowsPowerShell\Modules\03common

IMPORTANT: In order for this code to work for you, please, you need to consider your PowerShell Remoting Configuration and your need for user credentials. We have marked few lines of code (marked in code with: REPLACE THIS VALUE!!) where you need to change the values to represent your environment.

INFO: If you want to know how to install and configure Efficiency Booster PowerShell Project files please read the following article: How To Install And Configure PowerShell: CmdLets, Modules, Profiles.

Use-WS CmdLet – Input Parameters

As input parameters we have:

  • computers – it is a list of servers passed as input parameter with default value ‘localhost’ and accepts both pipeline options. Parameter belongs to the “ServerNames” parameter set. The “ServerNames” parameter set is the default parameter set.
  • filename – it is the name of the text file with the list of servers and represents an alternative option to the “computers” parameter. The parameter belongs to the “FileName” parameter set.
  • action – is a very vital input parameter and provides information on which task we want to accomplish against Windows Service with the possible values (Get, Set, Start, Stop, Reset, Suspend, Resume, Add, Delete). The default parameter value is Get.
  • name – is a mandatory input parameter and provides the name of Window Service and not the Display Name just to avoid the confusion.
  • BinaryPathName – provides the path to the Windows Service binary (executable) file and combines with action parameter value “Add“.
  • DisplayName – is a new value for Display Name of the Windows Service and it is combined with the action parameter value “Set“.
  • description – is a new value for Description Windows Service Property and it is combined with the action parameter value “Set“.
  • StartupType – is a new value for Startup Type Windows Service Property with possible values (Automatic, AutomaticDelayedStart, Disabled, InvalidValue, Manual) and it is combined with the action parameter value “Set“.
  • errorlog – switch datatype and when turned on it will write errors into an external error log file using Write-ErrorLog CmdLet. The error log file is located in the PSLogs folder of [My] Documents.
  • client – it is a mandatory input parameter and by convention, I use two letters for client shortcode (for example, OK = O client, BK = B client, etc.). This parameter value is part of the filename parameter naming convention.
  • solution – it is a mandatory input parameter and by convention, I use two-three letters for solution shortcode (for example, FIN = Financial solution, HR = HR solution, etc.).

The naming convention for the filename parameter is as follows: Client + Solution + Text.txt. The text file should be located in …[My] Documents\WindowsPowerShell\Modules\01servers folder.

For example:

  • OKFINTestServers.txt – List of test environment servers for OK client and FIN solution
  • OKFINProdServers.txt – List of production environmentservers for OK client and FIN solution.
  • OKFINAllServers.txt – List of all servers for OK client and FIN solution.

INFO: To get a deeper explanation about client and solution input parameters please read these two sections Parameter clientParameter solution.

INFO: In order to customize the installation of CmdLet to your needs and set up the necessary CSV file please read the following article How To Install And Configure PowerShell: CmdLets, Modules, Profiles

Here is the parameters definition code:

Function Use-WS {
[CmdletBinding(DefaultParametersetName="ServerNames")]
param (
    [Parameter( ValueFromPipeline=$true,
                ValueFromPipelineByPropertyName=$true,
                ParameterSetName="ServerNames",
                HelpMessage="List of computer names separated by commas.")]
    [Alias('hosts')] 
    [string[]]$computers = 'localhost',
    
    [Parameter( ParameterSetName="FileName",
                HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")] 
    [string]$filename,

    [Parameter(Mandatory=$false,
                HelpMessage="Action agains Windows Service. (Get, Start, Stop, Restart, Suspend, Resume, Set, Add, Delete)")]
    [ValidateSet("Get", "Start", "Stop", "Restart", "Suspend", "Resume", "Set", "Add", "Delete")] 
    [string]$action = 'Get',

    [Parameter( Mandatory=$true,
                HelpMessage="Name of the Windows Service and accepts wildcards.")]
    [string]$name,

    [Parameter( Mandatory=$false,
                HelpMessage="Path to Windows Service Executable file that will be added to Services Console.")]
    [string]$BinaryPathName,
    
    [Parameter( Mandatory=$false,
                HelpMessage="New value for Windows Service Display Name.")]
    [string]$DisplayName,

    [Parameter( Mandatory=$false,
                HelpMessage="New value for Windows Service Description.")]
    [string]$description,

    [Parameter( Mandatory=$false,
                HelpMessage="New value for Windows Service Startup Type.")]
    [ValidateSet("Automatic", "AutomaticDelayedStart", "Disabled", "InvalidValue", "Manual")]
    [string]$StartupType,

    [Parameter( Mandatory=$false,
                HelpMessage="Write to error log file or not.")]
    [switch]$errorlog,
    
    [Parameter(Mandatory=$true, 
                HelpMessage="Client for example OK = O client, BK = B client")]
    [string]$client,
     
    [Parameter(Mandatory=$true,
                HelpMessage="Solution, for example FIN = Financial, HR = Human Resource")]
    [string]$solution     
)
}

INFO: To know more about PowerShell Parameters and Parameter Sets with some awesome examples please read the following articles How To Create Parameters In PowerShell and How To Use Parameter Sets In PowerShell Functions.

How To Create Parameters In PowerShell Step By Step
How To Create Parameters In PowerShell Step By Step
How to Use Parameter Sets in PowerShell Functions
How To Use Parameter Sets With Examples In PowerShell Functions

INFOPowerShell Pipelining is a very important concept and I highly recommend you to read the article written on the subject. PowerShell Pipeline Concept Explained With Awesome Examples. Here I have shown in many examples the real power of PowerShell using the Pipelining.

How PowerShell Pipeline Works
PowerShell Pipeline Concept Explained With Awesome Examples

BEGIN Block

In the BEGIN block we:

  • If the FileName parameter set has been used we test if a text file with a list of servers exists.
  • If the file exists read the file and create the list of servers as a string array in the $computers variable.
  • … and if not write a warning with information to the caller to create the file.
BEGIN {
    if ( $PsCmdlet.ParameterSetName -eq "FileName") {
        if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
            Write-Verbose "Read content from file: $filename"
            $computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )        
        } else {
            Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
            Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
            break;
        } 
    }
}

PROCESS Block

In the PROCESS block, we run this block of code for each server passed into the pipeline or read from the text file. This is the main engine of this CmdLet so please pay attention to the explanation of the code:

  • We replace the localhost default value for the local server with the actual name of the local machine.
  • We use Get-ComputerInfo CmdLet to read additional data about each server (name, environment, logical name, IP address).
  • We implement Error Handling using try-catch blocks and writing errors in an external text file using Write-ErrorLog CmdLet.
  • We prepare the Credentials since we are using Invoke-Command CmdLet in our code which needs PowerShell Remoting enabled and the user with enough permissions to run the code.
  • We use the PowerShell switch construct combined with the values of the action input parameter in order to execute the right PowerShell CmdLet that will handle Windows Service. I will go more into detail about each action in a minute.

Invoke-Command Credentials Explained

NOTE: Depending on your environment and your PowerShell Remoting Configuration you may or may not need to provide Credentials in the way presented for the user running the code.

We have already written about configuring PowerShell Remoting and Credentials so please read this if needed and come back to continue with this article “How To Configure PowerShell Remoting And Credentials“.

Same thing regarding these lines of code we have already explained them line by line here so please read that if you need explanation and come back to continue with this article.

<#
The following lines of code (4) are added in order to provide Credentials for PowerShell Remoting since we use Invoke-Command CmdLet
This is dependent on the type of Remoting Enabled in your environment and sometimes is not necessary if your user running the script
has enough privileges. 
#>

##REPLACE THIS VALUE!!
$EncryptedPasswordFile = "C:\Users\dekib\Documents\PSCredential\Invoke-Command.txt"
##REPLACE THIS VALUE!!
$username="mladenovic.bilja@gmail.com" 
$password = Get-Content -Path $EncryptedPasswordFile | ConvertTo-SecureString
$Credentials = New-Object System.Management.Automation.PSCredential($username, $password)

Start Windows Service Code Explained

When the action input parameter has the value Start the code will come to the switch block and run the block of code within the Start value.

Here is the explanation what the code does:

  • We prepare the Get-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $getscriptblock.
  • We run Invoke-Command with Get-Service prepared code in order to get all the Windows Services with a certain name.
  • Now we make a decision if the service is stopped:
    • We prepare the Start-Service and Select-Object CmdLets call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in a variable $scriptblock.
    • We run Invoke-Command with Start-Service and Select-Object prepared code in order to start Windows Service that has been stopped and return as feedback the new status of Windows Service to the end-user.
  • If the service is running we just write a verbose message to the user that the Windows Service already runs and no need to rerun it again.
switch($action) {
    'Start' {
                    
        Write-Verbose "Check Windows Service Status ($name)..."

        $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

        $services = $null

        $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

        if ( $services.Status -eq "Stopped" ) {
                        
            Write-Verbose "Start Windows Service ($name)..."

            $scriptblock = Convert-StringToScriptBlock -string "Start-Service -Name $name -PassThru -ErrorAction Stop | Select-Object Name, Status"

            Invoke-Command -ComputerName $computers -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

            Write-Verbose "Windows Service ($name) STARTED!"
                    
        } else {

            Write-Verbose "No ($name) Windows Service to start on computer: $computer"
                    
        }

        break
    }
}

INFO: For a more step by step approach when you want to start Windows Services please read the Start section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Stop Windows Service Code Explained

When the action input parameter has the value Stop the code will come to the switch block and run the block of code within the Stop value. This block of code has the same logic as the previous Start block but in reverse.

Here is the explanation what the code does:

  • We prepare the Get-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $getscriptblock.
  • We run Invoke-Command with Get-Service prepared code in order to get all the Windows Services with a certain name.
  • Now we make a decision if the service is running:
    • We prepare the Stop-Service and Select-Object CmdLets call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in a variable $scriptblock.
    • We run Invoke-Command with Stop-Service and Select-Object prepared code in order to stop Windows Service that is running and return as feedback the new status of Windows Service to the user.
  • If the service is stopped we just write a verbose message to the user that the Windows Service already has been stopped and no need to try to stop it again.
switch($action) {
    'Stop' {
                    
        Write-Verbose "Check Windows Service Status ($name)..."

        $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

        $services = $null

        $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

        if ( $services.Status -eq "Running" ) {
                        
            Write-Verbose "Stop Windows Service ($name)..."

            $scriptblock = Convert-StringToScriptBlock -string "Stop-Service -Name $name -Force -PassThru -ErrorAction Stop | Select-Object Name, Status"

            Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

            Write-Verbose "Windows Service ($name) STOPPED!"
                    
        } else {

            Write-Verbose "No ($name) Windows Service to stop on computer: $computer"
                    
        }
        break
    }
}

INFO: For a more step by step approach when you want to stop Windows Services please read the Stop section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Restart Windows Service Code Explained

When the action input parameter has the value Restart the code will come to the switch block and run the block of code within the Restart value.

Here is the explanation what the code does:

  • We prepare the Restart-Service and Select-Object CmdLets call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in a variable $scriptblock.
  • We run Invoke-Command with Restart-Service and Select-Object prepared code in order to restart Windows Services and return as feedback the new status of Windows Service to the user.
switch($action) {
    'Restart' {
                    
        Write-Verbose "Restart Windows Service ($name)..."

        $scriptblock = Convert-StringToScriptBlock -string "Restart-Service -Name $name -Force -PassThru -ErrorAction Stop | Select-Object Name, Status"

        Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

        Write-Verbose "Windows Service ($name) RESTARTED!"

        break
    }
}

INFO: For a more step by step approach when you want to restart Windows Services please read the Restart section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Suspend (Pause) Windows Service Code Explained

When the action input parameter has the value Suspend the code will come to the switch block and run the block of code within the Suspend value in order to pause the Windows Services.

Here is the explanation what the code does:

  • We prepare the Get-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $getscriptblock.
  • We run Invoke-Command with Get-Service prepared code in order to get all the Windows Services with a certain name.
  • Now we make a decision if the service can be Paused (Suspended) and Resumed and if the service has not been paused:
    • We prepare the Suspend-Service and Select-Object CmdLets call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in a variable $scriptblock.
    • We run Invoke-Command with Suspend-Service and Select-Object prepared code in order to pause (suspend) Windows Service that is running and return as feedback the new status of Windows Service to the user.
  • If the service cannot be paused or it has the status “Paused” we just write a verbose message to the user that no Windows Service can be paused.
switch($action) {
    'Suspend' {

        Write-Verbose "Check Windows Service Status ($name)..."

        $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

        $services = $null

        $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

        if ( $services.CanPauseAndContinue -eq $true -and $services.Status -ne "Paused") {
                        
            Write-Verbose "Suspend [Pause] Windows Service ($name)..."

            $scriptblock = Convert-StringToScriptBlock -string "Suspend-Service -Name $name -PassThru -ErrorAction Stop | Select-Object Name, Status"

            Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

            Write-Verbose "Windows Service ($name) SUSPENDED [PAUSED]!"
                    
        } else {

            Write-Verbose "No ($name) Windows Service to suspend [pause] on computer: $computer"
                    
        }

        break
    }
}

INFO: For a more step by step approach when you want to pause (suspend) Windows Services please read the Pause (Suspend) section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Resume Windows Service Code Explained

When the action input parameter has the value Resume the code will come to the switch block and run the block of code within the Resume value in order to start again the Windows Services that have been paused previously.

Here is the explanation what the code does:

  • We prepare the Get-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $getscriptblock.
  • We run Invoke-Command with Get-Service prepared code in order to get all the Windows Services with a certain name.
  • Now we make a decision if the service can be Paused (Suspended) and Resumed and if the service has been paused:
    • We prepare the Resume-Service and Select-Object CmdLets call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in a variable $scriptblock.
    • We run Invoke-Command with Resume-Service and Select-Object prepared code in order to resume (start again) Windows Service that has been paused previously and return as feedback the new status of Windows Service to the user.
  • If the service cannot be paused or it has a status other than “Paused” we just write a verbose message to the user that no Windows Service can be resumed.
switch($action) {
    'Resume' {
                    
        Write-Verbose "Check Windows Service Status ($name)..."

        $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

        $services = $null

        $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

        #We want to resume only paused service and that can be resumed
        if ( $services.CanPauseAndContinue -eq $true -and $services.Status -eq "Paused") {
                        
            Write-Verbose "Resume Windows Service ($name)..."

            $scriptblock = Convert-StringToScriptBlock -string "Resume-Service -Name $name -PassThru -ErrorAction Stop | Select-Object Name, Status"

            Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

            Write-Verbose "Windows Service ($name) resumed!"
                    
        } else {

            Write-Verbose "No ($name) Windows Service to resume on computer: $computer"
                    
        }

        break
    }
}

INFO: For a more step by step approach when you want to resume Windows Services after being paused please read the Resume section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Set (Change) Windows Service Properties Code Explained

When the action input parameter has the value Set the code will come to the switch block and run the block of code within the Set value in order to change (set) Windows Services Properties (Display Name, Description, Startup Type).

In addition to the value Set for the action parameter of Use-WS CmdLet, we can combine the values for properties that we want to change for the following input parameters: DisplayName, description, StartupType.

NOTE: Since we are using Set-Service CmdLet to change Windows Service Properties we can change many other properties but for simplicity, we have used just these three the most common.

NOTE: Set-Service can start, stop, restart, etc Windows Service but we prefer to do these actions using native Start, Stop, Restart PowerShell CmdLets using appropriate values for the action input parameter as described in other subtopics.

Here is the explanation what the code does:

  • We build up the Set-Service CmdLet call using the value in the variable $setstring depending on which of the values for input parameters (DisplayName, description, and or StartupType) has been provided.
  • We use our own PowerShell CmdLet Convert-StringToScriptBlock to convert a string into a script block that is accepted as an input parameter for Invoke-Command CmdLet.
  • Finally, we run Invoke-Command CmdLet that will change Windows Service Properties.
switch($action) {
    'Set' {
                    
        Write-Verbose "Set Windows Service Properties ($name)..."

        $setstring = "Set-Service -Name '" + $name + "' "

        if ($DisplayName){
            $setstring = $setstring + "-DisplayName '" + $DisplayName + "' " 
        }

        if ($description){
            $setstring = $setstring + "-Description '" + $description + "' " 
        }

        if ($StartupType){
            $setstring = $setstring + "-StartupType '" + $StartupType + "' " 
        }

        $scriptblock = Convert-StringToScriptBlock -string $setstring

        Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

        Write-Verbose $setstring

        Write-Verbose "Windows Service ($name) SET!"

        break
    }
}

INFO: For a more step by step approach when you want to change (set) Windows Services Properties please read the Change (Set) section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Add Windows Service Code Explained

When the action input parameter has the value Add the code will come to the switch block and run the block of code within the Add value in order to add a new Windows Service into the system.

In addition, we need to provide the value for BinaryPathName input parameter which is a path to the Windows Service executable file.

Here is the explanation what the code does:

  • We prepare the Get-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $getscriptblock.
  • We run Invoke-Command with Get-Service prepared code in order to get all the Windows Services with a certain name and save in variable $services.

NOTE: We have set the value for the ErrorAction parameter as SilentlyContinue since we do not want to stop the execution of the code when none services with that name have been found on the system.

  • Now we make a check if we have found any windows service on the system with that name:
    • If the service with that name has been found we cannot add that service so we send a Warning message to the end-user.
    • If no service has been found that means we can try to add that windows service to the system.
  • We prepare the New-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $scriptblock.
  • We run Invoke-Command with New-Service prepared code in order to add the Windows Services to the system.
  • We run again Invoke-Command with Get-Service prepared code in order to check if the Windows Service has been added to the system and send that feedback to the end-user by saving the result in variable $newservice.
  • We check the value of the $newservice variable and
    • If the value exists that means Windows Service has been added and we write a Verbose message.
    • If the value doesn’t exist that means something went wrong and the end-user needs to investigate further the cause for the issue.
switch($action) {
    'Add' {

        $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop | Select-Object *"

        $services = $null

        #If the service doesn't exist we do not want to get an error so we used SilentlyContinue error action value.
        $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction SilentlyContinue

        if ($services){
                    
            Write-Warning "Windows Service ($name) already exists and cannot be added again!"

        } else {
                    
            Write-Verbose "Add Windows Service ($name)..."

            $scriptblock = Convert-StringToScriptBlock -string "New-Service -Name $name -BinaryPathName $BinaryPathName"

            Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

            Write-Verbose "Check New Windows Service ($name) existence."

            $newservice = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

            if($newservice){
                         
                Write-Verbose "New Windows Service $name Added."
                            
            } else {

                Write-Warning "Something is wrong to rerun the command and investigate further!!!"
                        
            }

        } 

        break
    }
}

INFO: For a more step by step approach when you want to add new Windows Services to the system please read the Add New section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Delete (Remove) Windows Service Code Explained

When the action input parameter has the value Delete the code will come to the switch block and run the block of code within the Delete value in order to add a new Windows Service into the system.

Here we need to be aware that different PowerShell command has to be run dependent on the PowerShell Version. We use the Delete method of Win32_Service WMI Class for PowerShell version 5.1 and earlier and we use Remove-Service CmdLet for PowerShell versions 6 and 7.

Here is the explanation what the code does:

  • We find out the PowerShell version and keep that information in variable $hostversion.
  • We prepare the Get-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $getscriptblock.
  • We run Invoke-Command with Get-Service prepared code in order to get all the Windows Services with a certain name and save in variable $services.

NOTE: We have set the value for the ErrorAction parameter as SilentlyContinue since we do not want to stop the execution of the code when none services with that name have been found on the system.

  • Now we need to make several decisions depending on the existence or status of Windows Service.
    • If the Windows Service status is “Running” we send back a Warning Message that Windows Service needs to be stopped first before deleting. So we should run Use-WS CmdLet with the action parameter value Stop first.
    • If the Windows Service exists that means we can try to delete it from the system and we will explain that part of the code in a second.
    • If the Windows Service doesn’t exist we return Warning Message to the end-user.
  • In the case when we have Windows Service to delete we check PowerShell Version comparing the value of $Host.Version.Major variable.
  • If the PowerShell version is higher then 5 (6 or 7) we do the following
    • We prepare the Remove-Service CmdLet call using our own PowerShell CmdLet Convert-StringToScriptBlock and save in variable $scriptblock.
    • We run Invoke-Command with Remove-Service prepared code in order to delete the Windows Services from the system.
  • If the PowerShell Version is 5 and older we do the following.
    • We make a call to the Delete method of Win32_Service WMI Class using Get-WmiObject CmdLet.
switch($action) {
    'Delete' {
                    
        $hostversion="v$($Host.Version.Major).$($Host.Version.Minor)"

        $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop | Select-Object *"

        $services = $null
                    
        #If the service doesn't exist we do not want to get an error so we used SilentlyContinue error action value.
        $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction SilentlyContinue

        #Stop Windows Service Before Trying to Delete It.
        if ($services.Status -eq "Running"){

            Write-Warning "Stop Windows Service ($name) in order to be able to delete it afterward."

        } elseif ($services) {

            #We use different commands to delete Windows Service for PowerShell Version 5.1 and older comparing with PowerShell versions 6 and 7
            if ($Host.Version.Major -gt 5) {
                    
                Write-Verbose "Delete Windows Service ($name) in PowerShell $hostversion..."

                ## NEED Help with this part of code in PowerShell 6 returns error: 
                <#
                    The term 'Remove-Service' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again
                #>
                $scriptblock = Convert-StringToScriptBlock -string "Remove-Service -Name $name"

                Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                Write-Verbose "Windows Service ($name) DELETED [REMOVED]!"
                    
                    
            } else {

                Write-Verbose "Delete Windows Service ($name) in PowerShell $hostversion..."

                (Get-WmiObject -ClassName win32_service -Filter "Name='$name'" -ComputerName $computer -ErrorAction Stop).Delete()

                Write-Verbose "Windows Service ($name) DELETED [REMOVED]!"

            }
        } else { 
                    
            Write-Warning "Windows Service ($name) does NOT exist so cannot be deleted!"       
        }
                    

        break
    }
}

INFO: For a more step by step approach when you want to delete (remove) Windows Services from the system please read the Delete (Remove) section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

Get Windows Service Properties Code Explained

This is the default behavior of the action input parameter so When the action input parameter has the value Get or no value at all since it is the default the code will come to the switch block and run the block of code within the default value in order to get Windows Service Properties.

NOTE: Please pay attention to the code explanation since we have done some interesting things with it in order for all the data (properties) we want to have as feedback be presented to the end-user.

Here is the explanation what the code does:

  • We prepare the Get-Service and Select-Object CmdLets call and save in variable $script.
  • We use our own PowerShell CmdLet Convert-StringToScriptBlock to convert a string into a script block and save in variable $scriptblock.
  • We run Invoke-Command with Get-Service and Select-Object prepared code in order to get the Windows Services Properties with a certain name and save in variable $result.
  • Now is the interesting part since the description Windows Service property is not part of Get-Service CmdLet we need to find an alternative way to add a description to the final result.
  • We use Add-Member CmdLet to add Description Windows Service Property
  • We get Description Windows Service property calling Win32_Service WMI Class using Get-CimInstance CmdLet since Get-Service cannot provide that value.
  • Another trick is to use the ExpandProperty parameter of Select-Object CmdLet to expand the value of Description as a string and combine with other Windows Service Properties in variable $finalresult.
  • But we are not over yet since variable $finalresult will show the result to end-user with description column last which we do not want.
  • So we PowerShell Pipeline $finalresult variable to Select-Object CmdLet and decide which columns and in which order will be presented to the end-user.

I was really surprised that Get-Service for some strange reason is not returning Description Windows Service Property but we have managed to overcome that.

switch($action) {
    default {
                    
        Write-Verbose "Get Windows Service ($name) properties..."

        $script = "Get-Service -Name '" + $name + "' | Select-Object Name, Status, DisplayName, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType"
                     
        $scriptblock = Convert-StringToScriptBlock -string $script

        $result = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

        #We need to add description separately since Get-Service will not return that value plus we need to pass $name variable to Get-CimInstance as Query
        $result | Add-Member -NotePropertyName Description2 -NotePropertyValue (Get-CimInstance -Query "SELECT * from Win32_Service WHERE name LIKE '$name%'" | Select-Object Description) 

        #First we will return all the properties and expend the value from Description2 but the result will have Description as last column in result which we do not want
        $finalresult = $result | Select-Object -Property Name, Status, DisplayName, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType -ExpandProperty Description2

        #Finally we can list the properties (columns) in the order we want to the final result.
        $finalresult | Select-Object Name, Status, DisplayName, Description, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType
                    
        #Select-Object Name, Status, DisplayName, -ExpandProperty Description2, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType

        Write-Verbose "Windows Service ($name) properties."

    }
}

INFO: For a more step by step approach when you want to get Windows Service Properties please read the Get section of the article “Get, Start, Stop, Restart, Pause, Resume, Set, Add, Delete Windows Services Using PowerShell With Easy Steps

INFO: To learn about PowerShell Error Handling and code debugging please read the following articles: How To Log PowerShell Errors And Much More and How To Debug PowerShell Scripts.

How To Log PowerShell Errors And Much More
How To Log PowerShell Errors And Much More
How To Debug PowerShell Scripts Featured
How To Debug PowerShell Scripts

END Block

END block is empty.

INFO: To understand BEGINPROCESS, and END blocks in PowerShell please read PowerShell Function Begin Process End Blocks Explained With Examples.

PowerShell Function Begin Process End Blocks Explained With Examples Featured
PowerShell Function Begin Process End Blocks Explained With Examples

Comment-Based Help Section

For every one of my own CmdLets, I write Comment-Based help as well.

INFO: If you want to learn how to write comment-based Help for your own PowerShell Functions and Scripts please read these articles How To Write PowerShell Help (Step by Step). In this article How To Write PowerShell Function’s Or CmdLet’s Help (Fast), I explain the PowerShell Add-on that helps us to be fast with writing help content.

How to Write PowerShell Help Step by Step Featured
How To Write PowerShell Help (Step by Step)
How To Write PowerShell Function’s Or CmdLet’s Help (Fast)

Useful PowerShell CmdLets For Windows Services

Here are some useful articles and resources:

Use-WS CmdLet Source Code

DISCLAIMERUse-WS function is part of the Efficiency Booster PowerShell Project and as such utilizes other CmdLets that are part of the same project. So the best option for you in order for this function to work without any additional customization is to download the source code of the whole project from here.

INFO: My best advice to every PowerShell scripter is to learn writing own PowerShell Advanced Functions and CmdLets and I have written several articles explaining this, so please read them. How To Create A Custom PowerShell CmdLet (Step By Step). Here I explain how to use PowerShell Add-on Function to be faster in writing PowerShell Functions How To Write Advanced Functions Or CmdLets With PowerShell (Fast).

How To Create Custom PowerShell CmdLet
How To Create A Custom PowerShell CmdLet (Step By Step)
How to write Advanced Functions or own CmdLets with PowerShell Fast
How To Write Advanced Functions Or CmdLets With PowerShell (Fast)

Here is the source code of the whole Use-WS CmdLet:

<#
.SYNOPSIS
Handles Windows Services (Get, Start, Stop, Restart, Suspend [Pause], Resume, Set, Add, Delete) both on local and remote machines
.DESCRIPTION
Handles Windows Services (Get, Start, Stop, Restart, Suspend [Pause], Resume, Set, Add, Delete) both on local and remote machines
List of servers is in txt file in 01servers folder or list of strings with names of computers.
CmdLet has two ParameterSets one for the list of computers from file and another from the list of strings as computer names.

Errors will be saved in the log folder PSLogs with the name Error_Log.txt. Parameter errorlog controls the logging of errors in the log file.

Use-WS function uses: Get-Service, Start-Service, Stop-Service, Restart-Service, Suspend-Service, Resume-Service, Set-Service, New-Service, Remove-Service 
AND Get-WmiObject -Class Win32_Service PowerShell function with delete method

The result shows different columns (properties) depending on which action has been applied (get, start, stop, restart, suspend, resume, set, add, delete)
.PARAMETER computers
List of computers that we want to get All windows services info from. Parameter belongs to default Parameter Set = ServerNames.
.PARAMETER filename
Name of text file with a list of servers. Text file should be in 01servers folder.
Parameter belongs to Parameter Set = FileName.
.PARAMETER errorlog
Switch parameter that sets to write to log or not to write to the log. Error file is in PSLog folder with name Error_Log.txt.
.PARAMETER client
OK - O client
BK - B client
etc.
.PARAMETER solution
FIN - Financial solution 
HR - Human resource solution
etc. 
.PARAMETER action 
Defines the action that we want to do against the Windows Service and have these possible values:
---------------------------------------------------------------------------------------------------------
 Get - Gets Windows Service Properties using Get-Service PowerShell CmdLet
 Start - Starts Windows Service using Start-Service PowerShell CmdLet
 Stop - Stops Windows Service using Stop-Service PowerShell CmdLet
 Restart - Restarts Windows Service using Restart-Service PowerShell CmdLet
 Suspend - Suspends [Pause] Windows Service using Suspend-Service PowerShell CmdLet
 Resume - Resumes Windows Service after being suspended [paused] using Resume-Service PowerShell CmdLet
 Set - Set [changes] some Windows Service properties (Display Name, Description, Startup Type) using Set-Service PowerShell CmdLet
 Add - Adds New Windows Service using New-Service PowerShell CmdLet and needs in addition use of BinaryPathName parameter to point to a binary file location.
 Delete - Deletes [Remove] Windows Service using Remove-Service PowerShell CmdLet and Delete method of Win32_Service class depending on PowerShell Version
.PARAMETER name
It is a mandatory parameter and represents the name of Windows Service (not Display Name very important)
.PARAMETER BinaryPathName
It is a path to Windows Service Binary file that will be added to the system and it is combined with Action parameter value Add.
Look at the example of how to use it. 
.PARAMETER DisplayName
The new value for the Display Name of Window Service and it is combined with Action parameter value Set 
.PARAMETER description
The new value for the Description of Windows Service and it is combined with Action parameter value Set
.PARAMETER StartupType
The new value for the Startup Type of Windows Service and it is combined with Action parameter value Set
Possible values for this parameter are: "Automatic", "AutomaticDelayedStart", "Disabled", "InvalidValue", "Manual"

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -Name "TapiSrv"

Description
---------------------------------------
Test of default parameter with default value ( computers = 'localhost' ) in default ParameterSet = ServerName.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose

Description
---------------------------------------
Test of Verbose parameter. NOTE: Notice how localhost default value of parameter computers replaces with the name of the server.

.EXAMPLE
'ERROR' | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog

Description
---------------------------------------
Test of errorlog parameter. There is no server with the name ERROR so this call will fail and write to Error log since errorlog switch parameter is on. Look Error_Log.txt file in the PSLogs folder.

.EXAMPLE
Use-WS -computers 'APP100001' -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog

Description
---------------------------------------
Test of computers parameter with one value. The parameter accepts an array of strings.

.EXAMPLE
Use-WS -computers 'APP100001', 'APP100002' -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose

Description
---------------------------------------
Test of computers parameter with an array of strings. The parameter accepts an array of strings.

.EXAMPLE
Use-WS -hosts 'APP100001' -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog

Description
---------------------------------------
Test of computers paramater alias hosts.

.EXAMPLE
Use-WS -computers (Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" )) -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose

Description
---------------------------------------
Test of computers parameter and values for parameter comes from .txt file that has a list of servers.

.EXAMPLE
'APP100001' | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog

Description
---------------------------------------
Test of the pipeline by the value of computers parameter.

.EXAMPLE
'APP100001', 'APP100002' | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose

Description
---------------------------------------
Test of the pipeline by value with an array of strings of computers parameter.

.EXAMPLE
'APP100001', 'APP100002' | Select-Object @{label="computers";expression={$_}} | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog

Description
---------------------------------------
Test of values from the pipeline by property name (computers).

.EXAMPLE
Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" ) | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose

Description
---------------------------------------
Test of the pipeline by value that comes as the content of .txt file with the list of servers.

.EXAMPLE
Help Use-WS -Full

Description
---------------------------------------
Test of Powershell help.

.EXAMPLE
Use-WS -filename "OKFINkservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose

Description
---------------------------------------
This is test of ParameterSet = FileName and parameter filename. There is a list of servers in .txt file.

.EXAMPLE
Use-WS -filename "OKFINserverss.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose

Description
---------------------------------------
This is test of ParameterSet = FileName and parameter filename. This test will fail due to the wrong name of the .txt file with the warning message "WARNING: This file path does NOT exist:".

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "TapiSrv" 

Description
---------------------------------------
Gets Windows Service Properties. Get is the default action parameter value so we do not need to provide the value for the action parameter.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "TapiSrv" -action Start 

Description
---------------------------------------
Start Windows Service.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "TapiSrv" -action Stop

Description
---------------------------------------
Stop Windows Service

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "TapiSrv" -action Suspend 

Description
---------------------------------------
Suspend [Pause] Windows Service.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "TapiSrv" -action Resume

Description
---------------------------------------
Resume Windows Service that has been paused [suspended].

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "TapiSrv" -action Restart 

Description
---------------------------------------
Restart Windows Service.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon" -BinaryPathName "C:\Temp\WS\ConDaemon.exe" -action Add

Description
---------------------------------------
Adds New Window Service with name ConDaemon. It is important to combine both Action parameter with value Add and BinaryPathName parameter with the value pointing to the location of
Windows Service binary (executable) file.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon" -DisplayName "New Con Deamon WS" -description "Windows Service New Description" -StartupType Disabled -action Set

Description
---------------------------------------
Changes [Sets] Window Service Properties (Display Name, Description, Startup Type) and it is combined with Action parameter value Set.

.EXAMPLE
Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon" -action Delete

Description
---------------------------------------
Removes [Deletes] Windows Service from the system. 


.INPUTS
System.String

Computers parameter pipeline both by Value and by Property Name value and has the default value localhost. (Parameter Set = ComputerNames)
Filename parameter does not pipeline and does not have a default value. (Parameter Set = FileName)
.OUTPUTS
System.Management.Automation.PSCustomObject


.NOTES
FunctionName : Use-WS
Created by   : Dejan Mladenovic
Date Coded   : 11/20/2020 19:06:41
More info    : https://improvescripting.com/

.LINK 
https://improvescripting.com/write-own-powershell-cmdlet-that-handles-windows-services/
Get-Service 
Start-Service 
Stop-Service 
Restart-Service 
Suspend-Service 
Resume-Service
Set-Service
New-Service
Remove-Service
#>
Function Use-WS {
[CmdletBinding(DefaultParametersetName="ServerNames")]
param (
    [Parameter( ValueFromPipeline=$true,
                ValueFromPipelineByPropertyName=$true,
                ParameterSetName="ServerNames",
                HelpMessage="List of computer names separated by commas.")]
    [Alias('hosts')] 
    [string[]]$computers = 'localhost',
    
    [Parameter( ParameterSetName="FileName",
                HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")] 
    [string]$filename,

    [Parameter(Mandatory=$false,
                HelpMessage="Action agains Windows Service. (Get, Start, Stop, Restart, Suspend, Resume, Set, Add, Delete)")]
    [ValidateSet("Get", "Start", "Stop", "Restart", "Suspend", "Resume", "Set", "Add", "Delete")] 
    [string]$action = 'Get',

    [Parameter( Mandatory=$true,
                HelpMessage="Name of the Windows Service and accepts wildcards.")]
    [string]$name,

    [Parameter( Mandatory=$false,
                HelpMessage="Path to Windows Service Executable file that will be added to Services Console.")]
    [string]$BinaryPathName,
    
    [Parameter( Mandatory=$false,
                HelpMessage="New value for Windows Service Display Name.")]
    [string]$DisplayName,

    [Parameter( Mandatory=$false,
                HelpMessage="New value for Windows Service Description.")]
    [string]$description,

    [Parameter( Mandatory=$false,
                HelpMessage="New value for Windows Service Startup Type.")]
    [ValidateSet("Automatic", "AutomaticDelayedStart", "Disabled", "InvalidValue", "Manual")]
    [string]$StartupType,

    [Parameter( Mandatory=$false,
                HelpMessage="Write to error log file or not.")]
    [switch]$errorlog,
    
    [Parameter(Mandatory=$true, 
                HelpMessage="Client for example OK = O client, BK = B client")]
    [string]$client,
     
    [Parameter(Mandatory=$true,
                HelpMessage="Solution, for example FIN = Financial, HR = Human Resource")]
    [string]$solution     
)

BEGIN {

    if ( $PsCmdlet.ParameterSetName -eq "FileName") {

        if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
            Write-Verbose "Read content from file: $filename"
            $computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )        
        } else {
            Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
            Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
            break;
        }
       
    }

}
PROCESS { 

<#
The following lines of code (4) are added in order to provide Credentials for PowerShell Remoting since we use Invoke-Command CmdLet
This is dependant on the type of Remoting Enabled in your environment and sometimes is not necessary if your user running the script
has enough privileges. 
#>


##REPLACE THIS VALUE!!
$EncryptedPasswordFile = "C:\Users\dekib\Documents\PSCredential\Invoke-Command.txt"
##REPLACE THIS VALUE!!
$username="mladenovic.bilja@gmail.com" 
$password = Get-Content -Path $EncryptedPasswordFile | ConvertTo-SecureString
$Credentials = New-Object System.Management.Automation.PSCredential($username, $password)

    foreach ($computer in $computers ) {

        if ( $computer -eq 'localhost' ) {
            $computer = $env:COMPUTERNAME
            Write-Verbose "Replace localhost with real name of the server."
        }
        
        $computerinfo = Get-ComputerInfo -computername $computer -client $client -solution $solution
        $hostname = $computerinfo.hostname
        $env = $computerinfo.environment
        $logicalname = $computerinfo.logicalname
        $ip = $computerinfo.ipaddress
        
        try {
            Write-Verbose "Start processing: $computer - $env - $logicalname"        
            Write-Verbose "Handle Windows Service ($name)..."

            switch($action) {
                'Start' {
                    
                    Write-Verbose "Check Windows Service Status ($name)..."

                    $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

                    $services = $null

                    $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

                    if ( $services.Status -eq "Stopped" ) {
                        
                        Write-Verbose "Start Windows Service ($name)..."

                        $scriptblock = Convert-StringToScriptBlock -string "Start-Service -Name $name -PassThru -ErrorAction Stop | Select-Object Name, Status"

                        Invoke-Command -ComputerName $computers -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                        Write-Verbose "Windows Service ($name) STARTED!"
                    
                    } else {

                      Write-Verbose "No ($name) Windows Service to start on computer: $computer"
                    
                    }

                    break
                }
                'Stop' {
                    
                    Write-Verbose "Check Windows Service Status ($name)..."

                    $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

                    $services = $null

                    $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

                    if ( $services.Status -eq "Running" ) {
                        
                        Write-Verbose "Stop Windows Service ($name)..."

                        $scriptblock = Convert-StringToScriptBlock -string "Stop-Service -Name $name -Force -PassThru -ErrorAction Stop | Select-Object Name, Status"

                        Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                        Write-Verbose "Windows Service ($name) STOPPED!"
                    
                    } else {

                      Write-Verbose "No ($name) Windows Service to stop on computer: $computer"
                    
                    }
                    break
                }
                'Restart' {
                    
                    Write-Verbose "Restart Windows Service ($name)..."

                    $scriptblock = Convert-StringToScriptBlock -string "Restart-Service -Name $name -Force -PassThru -ErrorAction Stop | Select-Object Name, Status"

                    Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                    Write-Verbose "Windows Service ($name) RESTARTED!"

                    break
                }
                'Suspend' {

                    Write-Verbose "Check Windows Service Status ($name)..."

                    $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

                    $services = $null

                    $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

                    if ( $services.CanPauseAndContinue -eq $true -and $services.Status -ne "Paused") {
                        
                        Write-Verbose "Suspend [Pause] Windows Service ($name)..."

                        $scriptblock = Convert-StringToScriptBlock -string "Suspend-Service -Name $name -PassThru -ErrorAction Stop | Select-Object Name, Status"

                        Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                        Write-Verbose "Windows Service ($name) SUSPENDED [PAUSED]!"
                    
                    } else {

                      Write-Verbose "No ($name) Windows Service to suspend [pause] on computer: $computer"
                    
                    }

                    break
                }
                'Resume' {
                    
                    Write-Verbose "Check Windows Service Status ($name)..."

                    $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop"

                    $services = $null

                    $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

                    #We want to resume only paused service and that can be resumed
                    if ( $services.CanPauseAndContinue -eq $true -and $services.Status -eq "Paused") {
                        
                        Write-Verbose "Resume Windows Service ($name)..."

                        $scriptblock = Convert-StringToScriptBlock -string "Resume-Service -Name $name -PassThru -ErrorAction Stop | Select-Object Name, Status"

                        Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                        Write-Verbose "Windows Service ($name) resumed!"
                    
                    } else {

                      Write-Verbose "No ($name) Windows Service to resume on computer: $computer"
                    
                    }

                    break
                }
                'Set' {
                    
                    Write-Verbose "Set Windows Service Properties ($name)..."

                    $setstring = "Set-Service -Name '" + $name + "' "

                    if ($DisplayName){
                        $setstring = $setstring + "-DisplayName '" + $DisplayName + "' " 
                    }

                    if ($description){
                        $setstring = $setstring + "-Description '" + $description + "' " 
                    }

                    if ($StartupType){
                        $setstring = $setstring + "-StartupType '" + $StartupType + "' " 
                    }

                    $scriptblock = Convert-StringToScriptBlock -string $setstring

                    Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                    Write-Verbose $setstring

                    Write-Verbose "Windows Service ($name) SET!"

                    break
                }
                'Add' {

                    $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop | Select-Object *"

                    $services = $null

                    #If the service doesn't exist we do not want to get an error so we used SilentlyContinue error action value.
                    $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction SilentlyContinue

                    if ($services){
                    
                        Write-Warning "Windows Service ($name) already exists and cannot be added again!"

                    } else {
                    
                        Write-Verbose "Add Windows Service ($name)..."

                        $scriptblock = Convert-StringToScriptBlock -string "New-Service -Name $name -BinaryPathName $BinaryPathName"

                        Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                        Write-Verbose "Check New Windows Service ($name) existence."

                        $newservice = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction Stop

                        if($newservice){
                         
                            Write-Verbose "New Windows Service $name Added."
                            
                        } else {

                            Write-Warning "Something is wrong so rerun the command and investigate further!!!"
                        
                        }

                    } 

                    break
                }
                'Delete' {
                    
                    $hostversion="v$($Host.Version.Major).$($Host.Version.Minor)"

                    $getscriptblock = Convert-StringToScriptBlock -string "Get-Service -Name $name -ErrorAction Stop | Select-Object *"

                    $services = $null
                    
                    #If the service doesn't exist we do not want to get an error so we used SilentlyContinue error action value.
                    $services = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $getscriptblock -ErrorAction SilentlyContinue

                    #Stop Windows Service Before Trying to Delete It.
                    if ($services.Status -eq "Running"){

                        Write-Warning "Stop Windows Service ($name) in order to be able to delete it afterward."

                    } elseif ($services) {

                        #We use different commands to delete Windows Service for PowerShell Version 5.1 and older comparing with PowerShell versions 6 and 7
                        if ($Host.Version.Major -gt 5) {
                    
                            Write-Verbose "Delete Windows Service ($name) in PowerShell $hostversion..."

                            ## NEED Help with this part of code in PowerShell 6 returns error: 
                            <#
                             The term 'Remove-Service' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again
                            #>
                            $scriptblock = Convert-StringToScriptBlock -string "Remove-Service -Name $name"

                            Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                            Write-Verbose "Windows Service ($name) DELETED [REMOVED]!"
                    
                    
                        } else {

                            Write-Verbose "Delete Windows Service ($name) in PowerShell $hostversion..."

                            (Get-WmiObject -ClassName win32_service -Filter "Name='$name'" -ComputerName $computer -ErrorAction Stop).Delete()

                            Write-Verbose "Windows Service ($name) DELETED [REMOVED]!"

                        }
                    } else { 
                    
                        Write-Warning "Windows Service ($name) does NOT exist so cannot be deleted!"       
                    }
                    

                    break
                }
                default {
                    
                    Write-Verbose "Get Windows Service ($name) properties..."

                    $script = "Get-Service -Name '" + $name + "' | Select-Object Name, Status, DisplayName, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType"
                     
                    $scriptblock = Convert-StringToScriptBlock -string $script

                    $result = Invoke-Command -ComputerName $computer -Credential $Credentials -ScriptBlock $scriptblock -ErrorAction Stop

                    #We need to add description separately since Get-Service will not return that value plus we need to pass $name variable to Get-CimInstance as Query
                    $result | Add-Member -NotePropertyName Description2 -NotePropertyValue (Get-CimInstance -Query "SELECT * from Win32_Service WHERE name LIKE '$name%'" | Select-Object Description) 

                    #First we will return all the properties and expend the value from Description2 but the result will have Description as last column in result which we do not want
                    $finalresult = $result | Select-Object -Property Name, Status, DisplayName, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType -ExpandProperty Description2

                    #Finally we can list the properties (columns) in the order we want to the final result.
                    $finalresult | Select-Object Name, Status, DisplayName, Description, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType
                    
                    #Select-Object Name, Status, DisplayName, -ExpandProperty Description2, StartType, DependentServices, RequiredServices, ServicesDependedOn, CanPauseAndContinue, CanShutdown, CanStop, MachineName, ServiceName, ServiceHandle, ServiceType

                    Write-Verbose "Windows Service ($name) properties."

                }
            }
           
        } catch {
            Write-Warning "Computer failed: $computer - $env - $logicalname Service failed: $AllWindowsService"
            Write-Warning "Error message: $_"

            if ( $errorlog ) {

                $errormsg = $_.ToString()
                $exception = $_.Exception
                $stacktrace = $_.ScriptStackTrace
                $failingline = $_.InvocationInfo.Line
                $positionmsg = $_.InvocationInfo.PositionMessage
                $pscommandpath = $_.InvocationInfo.PSCommandPath
                $failinglinenumber = $_.InvocationInfo.ScriptLineNumber
                $scriptname = $_.InvocationInfo.ScriptName

                Write-Verbose "Start writing to Error log."
                Write-ErrorLog -hostname $hostname -env $env -logicalname $logicalname -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace
                Write-Verbose "Finish writing to Error log."
            }
        }
    }
}
END { 
}
}
#region Execution examples
#Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon"

#Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon" -BinaryPathName "C:\Temp\WS\ConDaemon.exe" -action Add

#Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon" -DisplayName "New Con Deamon WS" -description "Windows Service New Description" -StartupType Disabled -action Set

#Use-WS -client "OK" -solution "FIN" -errorlog -Verbose -name "ConDaemon" -action Delete
          	                  
                                 
<#
#Test ParameterSet = ServerName
Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" 
Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog
Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose
Use-WS -computers 'APP100001' -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog
Use-WS -computers 'APP100001', 'APP100002' -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose
Use-WS -hosts 'APP100001' -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog
Use-WS -computers (Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" )) -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose

#Pipeline examples
'APP100001' | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog
'APP100001', 'APP100002' | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose
'APP100001', 'APP100002' | Select-Object @{label="computers";expression={$_}} | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog
Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" ) | Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose
'ERROR' | Use-WS -client "OK" -solution "FIN" -errorlog

#Test CmdLet help
Help Use-WS -Full

#SaveToExcel
Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose | Save-ToExcel -errorlog -ExcelFileName "Use-WS" -title "Windows Services info of servers in Financial solution for " -author "Dejan Mladenovic" -WorkSheetName "Windows services Info" -client "OK" -solution "FIN" 
#SaveToExcel and send email
Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Save-ToExcel -sendemail -errorlog -ExcelFileName "Use-WS" -title "Windows Services info of servers in Financial solution for " -author "Dejan Mladenovic" -WorkSheetName "Windows services Info" -client "OK" -solution "FIN" 

#Benchmark
#Time = 5.5 sec; Total Items = 12
Measure-BenchmarksCmdLet { Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose }
#Time = 4.9 sec; Total Items = 12
Measure-BenchmarksCmdLet { Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" }

#Baseline create
Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose | Save-Baseline -errorlog -BaselineFileName "Use-WS" -client "OK" -solution "FIN" -Verbose
Use-WS -client "OK" -solution "FIN" -errorlog -Name "TapiSrv" -Verbose | Save-Baseline -errorlog -BaselineFileName "Use-WS" -client "OK" -solution "FIN" -Verbose 
#Baseline archive and create new
Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose | Save-Baseline -archive -errorlog -BaselineFileName "Use-WS"  -client "OK" -solution "FIN" -Verbose
Use-WS -client "OK" -solution "FIN" -Name "TapiSrv" -errorlog -Verbose | Save-Baseline -archive -errorlog -BaselineFileName "Use-WS" -client "OK" -solution "FIN" -Verbose

#Test ParameterSet = FileName
Use-WS -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose
Use-WS -filename "OKFINserverss.txt" -errorlog -client "OK" -solution "FIN" -Name "TapiSrv" -Verbose

#>
#endregion

About Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals!
I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials
About Me...

My Posts | Website

Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals! I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials About Me...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Recent Content