DEV Community

ToolGBRMaker
ToolGBRMaker

Posted on • Originally published at toolgbrmaker.wordpress.com on

Building a function | Powershell

Version: 5.1.x

During this post, I’ll share some concepts that I’ve used to build a function from a piece of code already shared on my blog in an earlier post. If you want to give it a look, please use the following link.

The piece of code that I’ll reuse and change to fit my function needs is:

#starting the stopped services or restarting the running ones
Get-Service -ComputerName 'PTPOPF247203' -Name '*Pharma*' |
Where-Object { 
    if ($_.Status -eq 'Running') {
        Write-Host 'Attempting to restart' $_.DisplayName 'with status' $_.Status -BackgroundColor DarkRed
        Restart-Service $_
    }
    elseif ($_.Status -eq 'Stopped') {
        Write-Host 'Attempting to start' $_.DisplayName 'with status' $_.Status -BackgroundColor DarkGreen
        Start-Service $_
    }      
}
Enter fullscreen mode Exit fullscreen mode

The above code has the goal to restart executing services and start stopped ones.

Our new function…

Our function will have the name of Set-ServiceRunningStatus and will need as Parameters the ComputerName , Name , and Force. Regarding Name I’ll set this one as mandatory, to avoid a restart of all running services or the start of all stopped services, by mistake. Furthermore, the types used for these parameters are, by order, a string array, string, and a switch type, if the user wants a service restart no matter what’s.

function Set-ServiceRunningStatus{
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline=$true)]
        [string[]]$ComputerName,
        [Parameter(Mandatory=$true,
            HelpMessage = "Enter a service name (or filter for multiple) to set Running Status")]
        [string]$Name,
        [switch]$Force
    )
    BEGIN { } #BEGIN
    PROCESS { } #PROCESS
    END { } #END  
}
Enter fullscreen mode Exit fullscreen mode

So far so good, we have already our function structure. If you give a close look at our preliminary function structure you’ll be able to see that we have the BEGIN , PROCESS and END blocks. Let’s explain these input processing methods one by one:

  • BEGIN – Contains all the code that is needed to execute at the beginning of the function;
  • PROCESS – Contains the main functionality of the function;
  • END – Contains all the code that is needed to execute at the end of the function.

These methods can be read as follows – Begin to Process to end.

In our example won’t be strictly necessary to use all these blocks, but why not start to get used to them!?

Begin:

Let’s start with our BEGIN block, firstly I’ll enforce our coding rules in expressions, scripts, and script blocks (Set-StrictMode), afterward I’ll write a verbose to indicate in which step is our function and start to handle some of the service parameters to use on my cmdlets. These parameters will be dynamically set, because of the non-mandatory ones.

BEGIN {
  Set-StrictMode -Version 2.0

  Write-Verbose "[BEGIN] Starting: $($MyInvocation.Mycommand)"

  $serviceParam = @{ Name = $Name }
} #BEGIN
Enter fullscreen mode Exit fullscreen mode

PROCESS:

Now, time to get into our PROCESS block, where the action will happens… By first, I’ll need to ensure that Parameter $ComputerName has been used and if so, I’ll add the $ComputerName to my $serviceParam. To accomplish that I’m using the automatic variable $PSBoundParameters. Also, take note that I’m switching the $ComputerName parameter in case of being called more than once when our function is being invoked.

if ($PSBoundParameters.ContainsKey('ComputerName')) {
  if($serviceParam.ContainsKey('ComputerName')){
    $serviceParam.ComputerName = $ComputerName
  } else {
    $serviceParam.add('Computername',$ComputerName)
  } #if already have
  Write-Verbose "[PROCESS] Getting Services for $($ComputerName)"
} else {
  Write-Verbose "[PROCESS] Getting Services"    
}#if param ComputerName
Enter fullscreen mode Exit fullscreen mode

After, I’ve built my list of parameters to be used on my Services cmdlets, I’ll start by getting the services result list, using Get-Service cmdlet, and pipe it to my Where-Object, where I’ll check if it’s a service to restart or to start.

    PROCESS {
        if ($PSBoundParameters.ContainsKey('ComputerName')) {
            if($serviceParam.ContainsKey('ComputerName')){
                $serviceParam.ComputerName = $ComputerName
            } else {
                $serviceParam.add('Computername',$ComputerName)
            } #if already have
            Write-Verbose "[PROCESS] Getting Services for $($ComputerName)"
        } else {
            Write-Verbose "[PROCESS] Getting Services"    
        }#if param ComputerName

        Get-Service @serviceParam |
        Where-Object {

            Try {
                If ($_.status -eq 'Running') {
                    if ($Force) {
                        Write-Verbose "[PROCESS] Restarting Service $($_.Name) with -Force"
                        Restart-Service $_ -Force    
                    } else {
                        Write-Verbose "[PROCESS] Restarting Service $($_.Name)"
                        Restart-Service $_       
                    }#if force
                } elseif ($_.status -eq 'Stopped') {
                    Write-Verbose "[PROCESS] Starting Service $($_.Name)"
                    Start-Service $_    
                } #if status 
            } Catch {
                Write-Warning "[PROCESS] Attemp Failed for Service $($_.Name). Reason: $($_.Exception.message)"
            } #try

        } #Where-Object
    } #PROCESS
Enter fullscreen mode Exit fullscreen mode

All PROCESS block

You should notice, by reading the code above, that besides normal Service cmdlet invocation, I’m also writing some verbose to keep the user aware of what is being done during PROCESS execution. Parallelly to that, I’m also checking if our function was been invoked with Force option, and if so, combined if it’s a restart, I’m forcing the cmdlet execution with force option.

END:

By last, on my end block, I’m only writing as a verbose mentioning the ending of my function execution.

    END {
        Write-Verbose "[END] Ending: $($MyInvocation.Mycommand)"
    } #END 
Enter fullscreen mode Exit fullscreen mode

And that’s it. Now I have a function, that will be available to reuse in multiple scenarios, like importing a new license (that demands a restart for the impacted services). Another example could be a start/restart service, at the end of the day, to ensure that the services get the last released code.

Examples of Execution:

This function will, by definition, execute the Get-Service cmdlet on your local machine and it’s optional the use of parameter $ComputerName , so only if you want to play it on a list of Computer Names, you’ll need to use it. A possible call would be…

'localhost' | Set-ServiceRunningStatus -Name '*Pharma*' -Verbose
Enter fullscreen mode Exit fullscreen mode

I’ll use this function in future references to show you how we can use it in different tasks and also introduce the Automated testing on PowerShell. Keep aware of future posts.

Note: Besides internet references, I’ve also used the learning concepts acquired in the following book. I advise it as a good lecture.

Hint: On any doubts about cmdlets, always look for help on official internet pages, about those cmdlets, and from PowerShell helper.

Ps: I didn’t handle all possible function calls, so by now, this function is not bulletproof. If you detected the missing approach on it, please comment on this post. Good hunt!

Stay safe!

Top comments (0)