Fun With PowerShell Basic Functions

Introduction

Like most languages, PowerShell supports the use of functions. Functions are reusable bits of code with a name wrapped around them. This lets you make multiple calls to your function name allowing you code reuse.

PowerShell actually has two types of functions, Basic and Advanced. Basic functions are a lot like the 1974 VW SuperBeetle I owned back in college. No frills but useful, gets you where you are going. Did 0 to 60 mph in under 5 minutes. Most of the time.

Advanced functions have a lot more capabilities, and are more akin to a Tesla. Lots of fancy design, can do cool things, and depending on your need might be worth the extra investment.

In this post we will focus on Basic functions, saving Advanced functions for a later post.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of any variable by highlighting it and using F8/F5.

Basic Functions

To declare a Basic Function you begin with the keyword function. You then follow it with the name of the function. After that are a set of parenthesis, in which you put in any values you want to pass into the function (if any) that the function can use internally. The values passed in are known as parameters.

function Get-AValue($one, $two)
{
  return $one * $two
}

This function is simple. You pass in two values, which it then multiplies by each other. The return keyword is used to return the result. So how to use it?

Well, first you need to highlight the function and use F8 in VSCode (or F5 in the IDE). This will put the function in memory so it can be used.

To call it, just use the name of the function followed by the values to pass in.

Get-AValue 33 42

Result:
1386

The 33 will go into the $one variable, then 42 will go into the $two variable. Note that when calling the function no commas are needed to separate the values. In addition, unlike other languages they don’t have to be placed in parenthsis.

You can also take a function and assign it to a variable which will then hold the results.

$returnValue = Get-AValue 33 42
"Returned value is $returnValue"

Result:
Returned value is 1386

You can also skip placing the result into a variable, and place the function call right into the string.

"Returned value is $(Get-AValue 33 42)"

Result:
Returned value is 1386

The $() will force PowerShell to evaluate the expression, then string interpolation will replace it with the value before returning the final string. (For more on string interpolation, see my recent article Fun With PowerShell Strings.)

Passing Parameters by Name

PowerShell also supports passing in the parameters by name.

$returnValue = Get-AValue -one 11 -two 13
"Returned value is $returnValue"

Result:
Returned value is 1386

With this, you use the names of the variables from the function declaration. Instead of a $ though, you use a - (dash) to show this is a parameter and not a variable, -one and -two.

The great thing about passing in by name is that the order doesn’t matter. You can list the parameters in any order you want.

$returnValue = Get-AValue -two 13 -one 11
"Returned value is $returnValue"

Result:
Returned value is 1386

As you can see in this example we listed the second parameter, -two, first. Because we used names, PowerShell knew which parameter to assign which value to.

No Return

Strictly speaking, the return keyword is not required. Whenever PowerShell finds a value that isn’t otherwise consumed, that is, used by assigning that value to a variable or used in some other way, PowerShell returns that value from the function.

function Get-AValue($one, $two)
{
  $one * $two
}

$returnValue = Get-AValue 33 42
"Returned value is $returnValue"

Result:
Returned value is 1386

As you can see, the result of the $one * $two calculation isn’t otherwise used in the function it is returned as you can see in the result.

This can lead to some interesting side effects. Look at this example.

function Get-AValue($one, $two)
{
  $one * $two
  "Hello from Get-AValue"
}

$returnValue = Get-AValue 33 42
"Returned value is $returnValue"

Result:
Returned value is 1386 Hello from Get-AValue

In this example, there are two things that aren’t consumed. First is the calculation results, second is the string Hello from Get-AValue.

So how to get around this? Using the return keyword has another use. When PowerShell sees return, it exits the function immediately returning the result, as in this example.

function Get-AValue($one, $two)
{
  if ($one -eq 33)
    { return $one + $two }
  else
    { return $one + $two }

  "Hello from Get-AValue"
}

$returnValue = Get-AValue 33 42
"Returned value is $returnValue"

Result:
Returned value is 75

The function saw the value for $one is 33, so took the first branch in the if statement, adding the two. It then exited the function immediately. The Hello from Get-AValue is never executed.

There is one problem with this demo. A basic rule of functions is that they should have one, and only one exit point (barring any error handling). Having two return statements violates this rule. It’s easy enough to fix though.

function Get-AValue($one, $two)
{
  if ($one -eq 33)
    { $retVal = $one + $two }
  else
    { $retVal = $one + $two }

  return $retVal
}

$returnValue = Get-AValue 33 42
"Returned value is $returnValue"

Result:
Returned value is 75

Here I assign the result of the equations to the variable $retVal (short for return value). At the end of the function I have a single return statement that returns the value.

The Case for Return

I have met some PowerShell professionals who say you should never use the return statement. I have to respectfully disagree.

First, using return speaks of clear intent. I didn’t get to a certain spot and my code and just stopped, forgetting to complete the function. Using return clearly says “this is the value I meant to return”.

Second, I have explicit control over my code. Using it I clearly control where my code exits. Typically the return is the last statement in my function, but it’s not required as I may want some error handling.

Third, it improves readability. When I read through the code the return statement clearly shows what value I intend to return.

For these reasons I use the return keyword in all my functions. The choice is of course up to you, but I wanted to make the case why I like it. You will see many code samples without the return keyword, so I wanted you to be aware of the difference and why some people use it and others don’t.

Using Multiple Functions

It’s possible to have multiple functions in the same script, and even have those functions call each other. Let’s look at this example.

function Format-FileOutput($files)
{
  # Find the max length of a file name
  $maxLength = Get-MaxFileNameLength $files

  Write-Host "`r`nHere is the file output`r`n"
  $padding = (' ' * ($maxLength + 1))
  Write-Host "File Name $($padding) Size"
  Write-Host ('-' * ($maxLength + 16))

  foreach($file in $files)
  {
    Format-FileLine $file $maxLength
  }
}

function Get-MaxFileNameLength($files)
{
  $maxLength = 0

  foreach($file in $files)
  {
    if ($file.Name.Length -gt $maxLength)
      { $maxLength = $file.Name.Length }
  }

  return $maxLength
}

function Format-FileLine($file, $maxFileNameLength)
{
  # +1 will ensure there is always at least one space between
  # the file name and the size
  $spaces = ' ' * ($maxFileNameLength - $file.Name.Length + 1)
  $retVal = "$($file.Name)$($spaces){0,15:N0}" -f $file.Length

  return $retVal
}

Let’s break this down. The first function is Format-FileOutput. It takes one parameter, $files, which is intended to hold a list of file objects such as one returned by the Get-ChildItem cmdlet.

The first thing it does is call another function, Get-MaxFileNameLength and assign the result to a variable. This function will loop over all the file objects passed in and determine the length of the longest file name. This will be used later in formatting the output.

This also highlights another feature of PowerShell, the order you declare functions is not important. In some languages, you cannot declare a function that is called, in this case Get-MaxFileNameLength after a function it’s called from, here Format-FileOutput. Any called functions must be listed before the function they are called from.

Again, PowerShell doesn’t care, you can declare the functions in any order you wish.

Looking at Get-MaxFileNameLength, it sets a max length of zero, then loops over the list of file objects passed in. Each file object has a Name property, the name of the file. But the Name property has it’s own set of properties, one of which is Length.

This is not the length (or size) of the file, but the length of the file name. If the file name were MyScript.ps1, the length would be 12.

As it loops it compares the length of the file name, and if it’s greater than the max length already found it replaces it. Finally it returns that value.

Returning to Format-FileOutput, it uses some Write-Host statements to create a nice header to display in the output.

Note that some people say not to put Write-Host statements inside a function, that anything like Write-Host should be done in the main script that calls the function. Normally I might agree, however this is a simple demo so we’ll go with it.

After creating a nice header, it then loops over the list of file objects that were passed in, calling the Format-FileLine function. It passes in two parameters, the file object from the passed in array, and the maximum file name length.

The output will be in the format of:

FileName.ps1       12,345

We want the file sizes to line up neatly, so we first calculate the number of spaces we need to put between the end of the file name and the start of our file sizes. PowerShell lets you repeat a character by using the syntax char * numberoftimes, such as ' ' * 20 to get 20 spaces.

Here we use the length of the maximum file name, then subtract the length of the current file name, and finally add one extra space at the end.

We create a return value of the file name, plus the spaces to put at the end. We then use a string formatting command to put the file size at the end. For more on PowerShell’s string formatting syntax, see my post Fun With PowerShell String Formatting.

This formatted string is returned to the Format-FileOutput function, where it is displayed on the screen.

So how to use this? First, highlight all three functions then use F8/F5 to get them into memory. Then, just set your file location in the terminal to a spot you want to list the files in, and call the main function.

$myfiles = Get-ChildItem
Format-FileOutput $myfiles

Result:
File Name                                       Size
----------------------------------------------------
01 - Cmdlets.ps1                               3,732
02 - Providers.ps1                             1,819
03 - Variables.ps1                             4,717
04 - Strings.ps1                               7,970
05 - Arrays and Hashtables.ps1                 8,486
06 - Logic Branching and Looping.ps1           4,315
07 - Functions.ps1                             6,907
08 - Classes.ps1                               6,210
09 - Examples.ps1                              3,125
Company.csv                                    9,694
Company.json                                  19,479
ReadMe.md                                      1,115

As you can see it lists my header, then the list of files. The sizes are neatly right aligned.

You can use these same functions with other directories on your drive. I’m going to change my current folder to one that has some ISOs in it. Then I’ll run my same functions.

$myfiles = Get-ChildItem
Format-FileOutput $myfiles

Result:
File Name                                         Size
------------------------------------------------------
2018-11-13-raspbian-stretch-full.img     5,297,405,952
2018-11-13-raspbian-stretch-full.zip     1,978,611,497
Camtasia and Snagit MVP Keys.docx               63,229
Camtasia-2018-Key.txt                               71
Keys.txt                                           798
MediaCreationTool21H1.exe                   19,463,448
Office 2016 Professional Plus Keys.txt              77
SQLServer2019-x64-ENU-Dev.iso            1,433,974,784
Win10ProMultiActivationKey.txt                      31
win32diskimager-1.0.0-install.exe           12,567,188
Windows10-20H2.iso                       4,899,078,144
Windows10-21H1.iso                       4,556,128,256

The longer file names and sizes made the output slightly wider than the original example, but as you see the functions adapted easily to this. All without any changes.

This gives me a set of functions I can reuse over and over. And I don’t have to reuse them together, I could if I needed to have code that calls just the Get-MaxFileNameLength function.

Keep Functions Small and Focused

This brings up another rule of functions. Keep the function small and focused. Each function should do one thing and return the result. This will make it much easier to reuse your functions in other projects.

The Get-MaxFileNameLength function in the above demo is a good example. It does one thing, gets the maximum file name length, and returns it.

I could call this from my main script, but I could also write a second function similar to Format-FileOutput but perhaps it could include additional information such as the last modified date. The new function could also reference Get-MaxFileNameLength, providing good code reuse.

It also reduces the amount of code you need to write in a new function, as well as reduces what you need to test, assuming Get-MaxFileNameLength has already been tested of course.

Parameter Names versus Variable Names

I want to call out something you may not have noticed. When we called Format-FileName we passed in:

Format-FileLine $file $maxLength

The variable $maxLength was used for the second parameter. But look at the declaration for the function:

function Format-FileLine($file, $maxFileNameLength)

In the function, the second parameter is named $maxFileNameLength. The point in this demo was to show the variable named being passed in does not need to match the variable used in the function declaration. PowerShell can happily take $maxLength and copy its value into $maxFileNameLength.

Good Function Names

You probably know by now that PowerShell uses the Verb-Noun naming method for its cmdlets. In these demos we could have used any names we wanted for the functions. function Adam(), function John(), or function Robert() are all valid names. Well almost.

It is generally a best practice to use the Verb-Noun naming convention when creating your own function names. Additionally, PowerShell likes you to use an approved verb. You don’t have to, but PowerShell can display a warning if you don’t.

So what are the list of approved verbs? The easiest way is to let PowerShell tell you.

Get-Verb | Sort-Object Verb

The screen shot below shows a short sample of what PowerShell has (the list is too long to reprint here). Click on it for a larger view.

You can then select an appropriate verb from the list for your function.

Conclusion

In this post we covered the use of Basic Functions in PowerShell. You saw how to declare a function, how parameters worked, as well as the pros and cons of the return keyword.

We then got into the use of multiple functions in a PowerShell script, and how they can call one another.

In a future post we’ll dive into the concepts of Advanced Functions.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Fun with PowerShell Loops

Introduction

Continuing my series on PowerShell basics, in this installment we’ll talk bout looping in PowerShell. Looping is a mechanism for repeating a set of instructions multiple times, ending once a condition is met. Looping is also known as iterating, as in “iterating over an array”.

Loops continue until one of two things happen. In one type of loop, the loop continues until a certain condition is true. In the second type, the loop will iterate over a collection (also called an array) of objects until the entire collection has been gone through.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of an array variable (or any variable) by highlighting it and using F8/F5.

While

The while loop continues as long as a condition is true. Let’s take a look at an example.

$i = 1
while ($i -le 5)
{
  "`$i = $i"
  $i = $i + 1
}

Result:
$i = 1
$i = 2
$i = 3
$i = 4
$i = 5

In a while loop, you start with the keyword while, then pass in a condition. In this case, it will keep looping as long as $i is less than or equal to 5. Once $i is greater than 5, it will exit the loop.

Inside the loop we print out the value of $i, then increment the value of $i by 1.

So what happens if $i had been set to the value of 6, as in:



$i = 6
while ($i -le 5)
{
  "`$i = $i"
  $i = $i + 1
}

Result:
(Nothing is displayed)

In this case, the while keyword checked the value at the start of the loop. Since $i was already greater than 5, the loop never executed. So when using a while loop, be sure to understand there may be conditions under which the while loop will never execute.

Fun with Unary Operators

Before we see the next type of loop, I just want to mention unary operators. In the previous section you saw $i = $i + 1. Obviously this increased the value of $i by one.

There is an alternative syntax, the unary operator. With the unary operator, you use ++ either before or after the variable, as in $i++ or ++$i, to increment it. You can also use -- to decrement the value by one.

So what is the difference between $i++ and ++$i? It has to do with when the value is incremented. Let’s look at this example.

$i = 1
"`$i is $(($i++))"
"`$i is now $i"

Result:
$i is 1
$i is now 2

In this case we start by assigning the value of 1 to $i. We then have a string, "`$i is $(($i++))". In the results, it prints out $i = 1.

In this case, when ++ follows a variable the value is returned, then the variable is incremented. As PowerShell evaluates the string, it replaces $i with the value of 1, prints out $i is 1, and then it increments the value $i to 2.

In the final statement it displays the result of the incremented value.

What if the ++ occurs before the variable?

$i = 1
"`$i is $((++$i))"
"`$i is now $i"

Result:
$i is 2
$i is now 2

With ++ before the variable, the value in $i is incremented first, then the result is returned. So when PowerShell evaluated $((++$i)) it incremented the value of $i by one, now making it 2, then returned it to the string.

We took this detour into unary operators because it’s very common to use an expression like $i++ within a loop to increment the value, as you’ll see in the remaining examples.

Do While

With the while loop, you saw that it was possible that it might not execute, if the while condition was already true. What if, though, you always wanted the loop to execute at least once?

That’s where do while comes into play.

$i = 1
do
{
  "`$i = $i"
  $i++
} while($i -le 5)

Result:
$i = 1
$i = 2
$i = 3
$i = 4
$i = 5

This is a similar result to what we experienced with while. But, what if $i was already greater than 5, as in the next example.

$i = 33
do
{
  "`$i = $i"
  $i++
} while($i -le 5)

Result:
$i = 33

Because the while check didn’t occur until the very end of the loop, we are guaranteed that it will execute the code within our do‘s script block at least once, and hence it printed $i = 33.

Do Until

As an alternative to do while, there is do until. With do while it continues to loop as long as a condition is true.

Contrast this with do until, which keeps looping as long as the condition is not true.

$i = 1
do
{
  "`$i = $i"
  $i++
} until($i -gt 5)

Result:
$i = 1
$i = 2
$i = 3
$i = 4
$i = 5

In this case, once $i is greater than 5, the loop exits. There’s not much difference between do while and do until. It’s mostly a matter of how you like to think about your code.

Does it make more sense, or will it increase code readability, to write your code so that it keeps looping while a condition is true, or until it becomes true.

For

Another loop you can have fun with is the for loop. The for loop is ideal when you want to iterate over code a set number of times.

for ($f = 0; $f -le 5; $f++)
{
  "`$f = $f"
}

Result:
$f = 0
$f = 1
$f = 2
$f = 3
$f = 4
$f = 5

After the for, you pass in three expressions, separated by semicolons ; . The first expression you pass in sets the starting value for the variable we’ll increment each time through the loop. In this case, $f = 0 will (obviously) set the variable $f to 0 (zero). $f will be come the value we’ll increment each time through the loop.

The second expression is just like what you would use on a while/do while loop. As long as this condition is true it will keep looping. In this case, the expression $f -le 5 will keep looping as long as $f is less than or equal to 5.

Finally we have an expression that we want to execute at the end of the loop. Here, we’ll use a unary operator to increase the value of $f by 1.

So let’s express this in human terms.

  1. Set the value of $f to zero.
  2. Is $f less than or equal to 5? If yes, go into the script block. If no, exit the loop.
  3. Now execute all the code in the script block.
  4. At the end of the script block, add 1 to $f.
  5. Go back to step 2.

As you can see, the for is very similar to a while loop. If $f is already over 5 (in this example) the loop will not execute at all. Like while, it will keep looping as long as our condition is true.

The for is a little more compact than a while loop as you can include the increment option in the for command rather than having to include it in the script block.

ForEach

By far, the foreach loop is the one I use more than any other. The foreach loop allows you to iterate over an array (or a collection of objects, which is really just an array).

With for each you create a place holder variable then pass in the name of the array. Here, take a look at this example.

$array = 11,12,13,14,15   # Simple Array
foreach ($item in $array)
{
  "`$item = $item"
}

Result:
$item = 11
$item = 12
$item = 13
$item = 14
$item = 15

We create an array of numbers and assign them to the variable $array. Then in the foreach loop, we go over the array item by item. As each item is read from the array it is copied into the first variable in the foreach clause, in this case $item.

It then simply executes the code in the script block, when done it grabs the next item from $array, copies it into $item, and repeats the script block.

In this case we looped over a simple array of integers, but foreach can also loop over something more complex like a collection of objects. In this next example we’ll use the Get-ChildItem cmdlet to get a list of files from the current directory. As it goes over each one it will copy that file object into our $file variable, then we can use it in the script block.

foreach ($file in Get-ChildItem)
{
  $file.Name
}

Result:
01 - Cmdlets.ps1
02 - Providers.ps1
03 - Variables.ps1
04 - Strings.ps1
05 - Arrays and Hashtables.ps1
06 - Logic Branching and Looping.ps1
07 - Functions.ps1
08 - Classes.ps1
09 - Examples.ps1
ReadMe.md

The script block is very simple, it just references the Name property of the $file object and displays it on the screen.

Now many people might have coded this as:

$myFiles = Get-ChildItem
foreach($file in $myFiles)
...

Which is perfectly valid code. I just wanted to show that if the only reason you needed the $myFiles variable was to hold information to iterate over, and you weren’t going to reference it again in your code, you could skip it and just use the cmdlet right in the foreach loop.

Code Formatting

In my previous post I dove into the Code Formatting around PowerShell. In all my examples, I used a space between the loop keyword and parenthesis that enclosed the condition. In addition I put the opening squiggly brace on the next line.

Neither is necessary, this is perfect valid code:]

$i = 1
while($i=1){
  # Do some stuff
}

Conclusion

In this post, we looked at several ways to iterate over your code. This included several variations on while, as well as for and the useful foreach. Now you have several tools at your disposal when you need to run the same piece of code multiple times.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Fun With PowerShell Code Formatting

Introduction

In this post, we’ll take a look at some of PowerShell’s rules around code formatting. Code formatting is how you can layout your code statements.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of an array variable (or any variable) by highlighting it and using F8/F5.

In either environment, you can run your entire script by pressing F5.

Code Formatting

Unlike some languages, such as Python, PowerShell is extremely flexible when it comes to how you format your code. There are, in fact, very few rules around it.

Let’s take this first example. When I’m developing a script I tend to do so in steps. I write short pieces at a time, then I use the method of highlighting those lines of code and running using F8/F5 (depending on if I’m in VSCode or the IDE).

Here’s one downside, if you don’t have any lines of code highlighted pressing F5 will run your entire script (in either VSCode or the IDE). I have to admit, even though I’ve been using VSCode for a few years now old habits die hard and I still press F5 sometimes.

To prevent my entire script from running I add the following line at the top of my scripts. Once it is complete can remove it or comment it out.

if ( 1 -eq 1 ) { exit }

Here, 1 will always equal 1, so it will run the code in the script block. This is the exit command, which will cause a script to exit, or in other words stop running.

The real point of this example though isn’t the exit command, but the formatting of the if statement. As you can see, since the script block was so short, I was able to put it all on a single line.

But I didn’t have to. I could have placed it on multiple lines.

if ( 1 -eq 1 )
  { exit }

In this example, I placed my single line script block on the next line. Whenever I have a short script block like this, I usually indent two spaces, just because I think it is more readable. But that’s my personal preference. I could have placed it all the way on the left.

if ( 1 -eq 1 )
{ exit }

I could also have spread it out over multiple lines, as I did in the previous section, even though the code (the exit statement) was still only a single line.

if ( 1 -eq 1 )
{
  exit
}

Many people have a preference for putting the opening squiggly brace at the end of the line with the if statement, and PowerShell supports that as well.

if ( 1 -eq 1 ) {
  exit
}

I tend to prefer the former method as it makes lining up your opening and closing squiggly braces much easier, but fortunately PowerShell supports what ever method you wish to use to format your code.

More Fun with Code Formatting

Next, I’d like I to mention two small things that fall into the code formatting realm.

First, it is possible to compact multiple lines of code into a single line in PowerShell. All you have to do is use a semicolon ; to separate each one.

$a = 'Hi'; $b = 'Mom'; "$a $b"

Result:
Hi Mom

The second thing I’ll mention is comments. Comments begin with a # (pound sign, or as some call it a hash tag).

# This is a comment

Comments can go after a section of code.

$var = 2   # Assign 2 to the variable $var

PowerShell also supports multi-line comments. You start and end them with <# and #>.

<#
   This is a multi line comment.
   You can also put blank lines in here.

   See, easy.
#>

The opening and closing <# #> don’t have to be at the beginning of the line.

<#--------------------------------------------
  You don't have to indent either.
--------------------------------------------#>

Documenting Your Code Formatting Standards

If you work in an organization, even one with just two of you doing PowerShell development, it’s incredibly important to document your coding standards. This will ensure the code produced by all developers in your organization has a consistent look and feel.

So what types of things should go into the document? Well how about something as simple as indenting your code. When you indent, for example as part of an if statement, should it be two spaces? Four? More?

And should it be spaces, or should you use the TAB character? Personally I hate the TAB character, leads to formatting issues when going between platforms. Remember, PowerShell runs on Windows, macOS and Linux. But as I like to say “hey you do you”.

How about the opening squiggly brace of a script block. Should that be at the end of (for example) your if statement, or should it go on the next line?

How about comments? Let’s say you decide each script (PS1 file) should have a header. What should go in it? A copyright notice? The author name? A description of the script? What order should it be in?

There is one rule that is almost universally accepted, never use the short version of names for cmdlets, always spell them out. For example, gci is short for Get-ChildItem. When you are in the terminal just looking around, it’s perfectly valid to use gci, but in a script always spell out the full Get-ChildItem cmdlet name.

These are just a few ideas to get the ball rolling. You should keep your standards document as brief as possible, but cover as many things as necessary to create a consistent look and feel when coding new PowerShell scripts.

There are hundreds of good books and blog sites that discuss and have examples of coding standards. In the end go with what works best for you, but the important part, stick with it!

Make it a group decision as much as possible. Your entire coding team should have input into the standards. Even more important, when a new member comes into the team before they write the first line of code they should be introduced to your coding standards.

I would also avoid using something like a Word document to store the standards. Instead, put them online in a place that is easy to search and index. If your team has it’s own internal Wiki, that’s a great place. Or, author them in Markdown format and store them in a GitHub repository.

Wherever you put them, accessibility is key. Standards should be easy to reference, and to find the item you need.

Conclusion

This post covered the flexibility of code formatting in PowerShell, as well as touched on a few items such as commenting. More importantly, it touched on the importance of documenting and standardizing your code formatting rules.

With this info I hope you jump right on creating your own set of coding standards!

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Fun With PowerShell Logic Branching

Introduction

In this post, we’ll see how some of PowerShell’s logic branching works. Logic branching is where you execute certain lines of code only when a condition is true.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of an array variable (or any variable) by highlighting it and using F8/F5.

In either environment, you can run your entire script by pressing F5.

Logic Branching – if

No, I don’t mean “if” we want to do logic branching. if is a keyword in PowerShell. With it, you can pass in a condition, then execute code based on the value of the condition. This example will make it a bit more clear.

$var = 2
if ($var -eq 1)
{
  Clear-Host
  'If branch'
}
else
{
  Clear-Host
  'else branch'
}

Result:
else branch

Beside the if keyword are a set of parenthesis ( ). In it, you create some kind of expression, but, and this is important, the result of the equation must be either True or False.

In this example, I created a variable $var and set the value to 2. Then, inside the parenthesis I used $var - eq 1.

Following this I have a set of squiggly braces { } with code inside it. In PowerShell, this is known as a script block.

If my condition is true, it will execute the first script block. But what if you want to do something if it evaluates to false? That’s where the next keyword comes in, else.

Immediately after the script block associated with the if, you add the else keyword, followed by a second script block to be executed.

In the example above, the condition will evaluate to false, so the code in the else script block will run, displaying the result of “else branch“.

PowerShell also supports another keyword, elseif. I almost hesitate to provide a demo, because most developers say if you need to fall into an elseif, you should then change your code to use another branching method, which we’ll cover next. However for completeness let’s see an example.

$var = 2
if ($var -eq 1)
{
  Clear-Host
  'If branch'
}
elseif ($var -eq 33)
{
  Clear-Host
  'elseif branch'
}
else
{
  Clear-Host
  'else branch'
}

Result:
else branch

As before, we start with an if ($var -eq 1), but following that is our elseif. It will then check the condition in the elseif, ($var -eq 33). If it doesn’t find a match for it, it flows to the next section, the else.

Obviously if it finds a match, it executes the script block associated with the elseif. Once done it skips over any following elseif or else statements and goes on to the following our entire if construct.

A few things, first you can have elseif statements without an else. However it’s generally a good idea to have a default code handler should you not execute any of the other if / elseif statements.

Second, you can have as many elseif statements as you want. But as the old saying goes, just because you can do something, doesn’t mean you should. Most PowerShell developers (myself included) say if you have to resort to an elseif, you should really be using a switch.

Speaking of the switch….

More Fun with Logic Branching – switch

In addition to the if statement, there is another way to branch your code, the switch statement.

$var = 42
switch  ($var)
{
  41 {'Forty One'}
  42 {'Forty Two'}
  43 {'Forty Three'}
  default {'default'}
}

Result:
Forty Two

With the switch statement, you pass in a value. Unlike the if, the value does not need to evaluate to True or False, it can be any value.

It will then execute the script block that follows, evaluating each value in the list. If it finds a match, it will execute the code in the script block that follows.

In the example above, it finds a match on 42, and runs the code in the script block which prints out the text ‘Forty Two‘.

One issue you may encounter is multiple matches.

$var = 42
switch  ($var)
{
  41   {'Forty One'}
  42   {'Forty Two'}
  '42' {'Forty Two'}
  43   {'Forty Three'}
  default {'default"}
}

Result:
Forty Two
Forty Two

Here, it went down the list and found the first match of integer 42. It executed the script block, and continued down the list.

It next found the string of '42'. It converted the string to the same datatype as what was passed in, an integer 42, found a match, and executed that script block.

So how to stop execution after the first match? That’s where break comes in. When PowerShell finds break it will stop code execution and exit to the next line after the switch.

$var = 42
switch  ($var)
{
  41   {'Forty One'; break}
  42   {'Forty Two'; break}
  '42' {'Forty Two'; break}
  43   {'Forty Three'; break}
  default {'default'; break}
}

'Exit to this point'

Result:
Forty Two
Exit to this point

As you can see from the results, the switch found the first match at the int 42. The break statement said “skip the rest and go to the next line after”, which prints out Exit to this point.

This brings up the subject of type coercion. This is the converting of one data type before comparing to another. In PowerShell, anytime it compares values of two different datatypes, it converts the datatype on the right to match the datatype on the left.

For example, if you had an equation if ( 33 -eq '33') it will convert the string '33', on the right side of the -eq, to the datatype on the left side of the -eq, an integer 42.

With the switch statement, the left value is the one being passed in, in this case the variable $var. The right side are the values switch is looking at, here 41, 42, 43. This is something to keep in mind whenever you are writing your code.

In this example, it won’t make a difference.

$var = '42'
switch  ($var)
{
  41 {'Forty One'}
  42 {'Forty Two'}
  43 {'Forty Three'}
  default {'default'}
}

Result:
Forty Two

The code went down the list, converting each value to a string. It took the int, 42 and converted it to a string. It then found a match with the original string of 42 in the $var variable and printed out the ‘Forty Two‘ as found in the script block.

Let’s take a slightly different example.

$var = '042'
switch  ($var)
{
  41 {'Forty One'}
  42 {'Forty Two'}
  43 {'Forty Three'}
  default {'default'}
}

Result:
default

In this case it compared each value, but the string 042 doesn’t match the converted int of '42' so it didn’t match.

So what’s with the output of default? If the switch statement doesn’t find a match, it will execute in the script block associated with default.

The default is optional, if you omit it and no match is found and the switch simply exits and continues to the next line after the switch.

As a final point, I want to mention you don’t have to contain everything in the switch’s script blocks to a single line. This is perfectly valid code.

$var = 42
switch  ($var)
{
  41   {
         'Forty One'
         break
       }
  42   {
         'Forty Two'
         break
       }
  '42' {
         'Forty Two'
         break
       }
  43   {
         'Forty Three'
         break
       }
  default {
            'default'
            break
          }
}

While this example is a bit harder to read, you will encounter situations where trying to condense your script block to a single line will be difficult so don’t hesitate to use multiple lines if it improves readability.

Conslusion

This post focused on the logic branching mechanisms built into PowerShell, if and switch. Hopefully this will give you a better understanding of your options for handling conditional code execution in PowerShell.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Fun With PowerShell Hash Tables

Introduction

Hash tables are powerful, flexible items. In some languages, hash tables are also called dictionaries. In this post we’ll start with a few basics, then get into some fun things you can do with hash tables.

A quick note, some documentation calls them a hash table, others read hashtable, one word. For this post I’ll use the two word hash table, but it’s the same thing no matter what documentation or blog you read.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of an array variable (or any variable) by highlighting it and using F8/F5.

Hash Table Basics

To create a hash table you will need to use the @{} syntax to create a set of key / value pairs.

$hash = @{'Key'                 = 'Value'
          'PowerShell'          = 'PowerShell.com'
          'Arcane Code'         = 'arcanecode.com'
          'Pluralsight'         = 'pluralsight.com'
          'GitHub - ArcaneCode' = 'github.com/arcanecode'
         }
$hash                  # Display all values

Result:
Name                           Value
----                           -----
Arcane Code                    arcanecode.com
Key                            Value
Pluralsight                    pluralsight.com
PowerShell                     PowerShell.com
GitHub - ArcaneCode            github.com/arcanecode

In this example I lined up the equal signs because, in my humble opinion, it’s easier to read. But it’s not required.

Similar to an array, you can use positional notation to retrieve a value, only instead of a numeric value you pass in the key.

$hash['PowerShell']

Result:
PowerShell.com

The hash table manifests each key as a property. This means instead of positional notation you can instead use . (dot) notation.

$hash.PowerShell

Result:
PowerShell.com

But Arcane, you may ask, some of those keys have spaces in them. How does that work?

Well all you have to do is put the key in quotes.

$hash.'Arcane Code'

Result:
arcanecode.com

Well that was fun, but what about updating a value for a key? All you have to do is assign the new value.

$hash.'Arcane Code' = 'ArcaneCode.me'
$hash

Result:
Name                           Value
----                           -----
GitHub - ArcaneCode            github.com/arcanecode
Key                            Value
PowerShell                     PowerShell.com
Pluralsight                    pluralsight.com
Arcane Code                    arcanecode.me

As you can see the value for the 'Arcane Code' key has changed from arcanecode.com to arcanecode.me.

In addition to updating, you will have times you want to add a new item to an array. Doing so isn’t intuitive, but it’s easy. Just use the hash table, provide the new key and assign the value to it.

$hash.Ubuntu = 'Ubuntu.com'
$hash

Result:
Name                           Value
----                           -----
GitHub - ArcaneCode            github.com/arcanecode
Key                            Value
Ubuntu                         Ubuntu.com
PowerShell                     PowerShell.com
Pluralsight                    pluralsight.com
Arcane Code                    arcanecode.me

Fun Properties and Methods of Hash Tables

Hash tables have a variety of useful properties and methods you can call. The first, Keys, will return a list of all the keys.

$hash.Keys

Result:
GitHub - ArcaneCode
Key
PowerShell
Pluralsight
Arcane Code
Ubuntu

As you might guess, there’s a corresponding property to return all the values.

$hash.Values

Result:
github.com/arcanecode
Value
PowerShell.com
pluralsight.com
arcanecode.me
Ubuntu.com

Just like the array data type, hash tables also have a Count property to let you know how many key/value pairs are in the table.

$hash.Count

Result:
6

Earlier in this post I showed how to add a new key/value pair. Before adding, it would probably be a good idea to check and see if it is already there. There is a ContainsKey method that will do that.

$hash.ContainsKey('Arcane Code')

Result:
True

This method will return either True or False depending on the presence of the key.

Likewise, there is a method to check to see if a value is present.

$hash.ContainsValue('pluralsight.com')

Result:
True

What if we’d wanted to use ContainsKey to see if a key was present, and if so we wanted to remove it? There is a Remove method that will delete a key/value pair from our hash table.

$hash.Remove('Ubuntu')
$hash

Result:
Name                           Value
----                           -----
GitHub - ArcaneCode            github.com/arcanecode
Key                            Value
PowerShell                     PowerShell.com
Pluralsight                    pluralsight.com
Arcane Code                    arcanecode.me

As you can see in the results, the key / value pair for the Ubuntu entry is now gone.

The final method we’ll look at in this section will allow us to remove all key / value pairs from the hash table.

$hash.Clear()
$hash

Result:
(Nothing is displayed because the hash table is empty)

Creating an Empty Hash Table

Much as with arrays, there are times you will want to create an empty hash table. You could then enter a loop that added new key / value pairs to the hash table.

To declare an empty hash table, you simply assign @{} to a variable.

$empty = @{}

Now you can assign values to it. Here we’ll do it in individual lines, but as I indicated this technique is most useful in a loop.

$empty['Pluralsight'] = 'pluralsight.com'
$empty['DataFabricator'] = 'datafabricator.com'
$empty

Result:
Name                           Value
----                           -----
Pluralsight                    pluralsight.com
DataFabricator                 datafabricator.com

Ordered Hash Tables

Let’s reset our hash table, then look at the output.

$hash = @{'Key'                 = 'Value'
          'PowerShell'          = 'PowerShell.com'
          'Arcane Code'         = 'arcanecode.com'
          'Pluralsight'         = 'pluralsight.com'
          'GitHub - ArcaneCode' = 'github.com/arcanecode'
         }
$hash

Result:
Name                           Value
----                           -----
Arcane Code                    arcanecode.com
Key                            Value
Pluralsight                    pluralsight.com
PowerShell                     PowerShell.com
GitHub - ArcaneCode            github.com/arcanecode

Look at the output carefully. The returned list is not in the same order we added them to the hash table. Most of the time you are referencing the hash table via a specific key, so the ordering isn’t a concern.

What if you needed them to be returned in the same order they were added in? Fortunately PowerShell has an [ordered] instruction you can place before declaring the hash table.

$hash = [ordered]@{
  'Key'                 = 'Value'
  'PowerShell'          = 'PowerShell.com'
  'Arcane Code'         = 'arcanecode.com'
  'Pluralsight'         = 'pluralsight.com'
  'GitHub - ArcaneCode' = 'github.com/arcanecode'
}
$hash

Result:
Name                           Value
----                           -----
Key                            Value
PowerShell                     PowerShell.com
Arcane Code                    arcanecode.com
Pluralsight                    pluralsight.com
GitHub - ArcaneCode            github.com/arcanecode

As you can see, the results are returned in the exact same order they were added to the hash table. This example also demonstrates you can begin the list of key / value pairs on the next line after the single squiggly bracket {.

Iterating (Looping) Over a Hash Table

It is possible to loop over the contents of a hash table. But it isn’t quite as intuitive as it is with arrays. If you were to use foreach($item in $hash) you’d get an error, because PowerShell isn’t sure if you want to loop over the keys, values, or something else.

Instead, the hash table has a special method called GetEnumerator which will allow you to iterate over the table, returning one key / value pair each time through the loop.

foreach($item in $hash.GetEnumerator())
{
  "$($item.Name) has a value of $($item.Value)"
}

Result:
Key has a value of Value
PowerShell has a value of PowerShell.com
Arcane Code has a value of arcanecode.com
Pluralsight has a value of pluralsight.com
GitHub - ArcaneCode has a value of github.com/arcanecode

This is the way I prefer to iterate over a hash table. Just my personal opinion, but I think the code is cleaner and easier to read. That said, there is a second method you may like better.

In it you loop over the Key values, then reference the value from the hash table, using the key as the position. Do notice that instead of using the key[] notation, you have to reference the Item method then pass the key into it.

foreach($key in $hash.Keys)
{
  "$key value is $($hash.Item($key))"
}

Result:
Key value is Value
PowerShell value is PowerShell.com
Arcane Code value is arcanecode.com
Pluralsight value is pluralsight.com
GitHub - ArcaneCode value is github.com/arcanecode

As you can see, the result is the same either way. Use which ever method makes the most sense for you.

Splatting

Right now you are probably asking yourself “Splatting? Hey Arcane, are you trying to confuse us with silly names?”

Fear not, splatting is a real thing. First, let’s start with an example. Here, we are going to take the output of GetChildItem and pipe it to a cmdlet called Join-String. If you aren’t familiar with it, Join-String will take a list of objects and join them to a single string.

Get-ChildItem -Directory D:\ |
  Join-String -Property Name -Separator ', '

Result:
Backups_Temp, CamtasiaWorkspace, Hyper-V, ISOs, Mobile Report Publisher

With splatting, we create a hash table, Each key is the name of a parameter that needs to be passed in, and the value is what we want to use for that parameter.

$splat = @{Property = 'Name'
           Separator = ', '
          }

Here you can see the Property and Separator parameter names were passed in as keys, and the values are what we want to pass in.

Now we can call our cmdlet, passing in the name of our hash table. Only, and this is important, instead of a $ we use an @ at the front of the name of our hash table.

Get-ChildItem -Directory D:\ | Join-String @splat

Result:
Backups_Temp, CamtasiaWorkspace, Hyper-V, ISOs, Mobile Report Publisher

Whenever PowerShell sees a @ in front of a name that corresponds to a hash table, it understand you are using a splat and expands each key / value pair into parameters. As you can see, it shortens the call to Join-String significantly.

What if we want to change the value of one of our parameters? That’s easy, we just assign a new value. The rest of the hash table remains the same.

$splat.Separator = ' - '
Get-ChildItem -Directory D:\ | Join-String @splat

Result:
"Backups_Temp" - "CamtasiaWorkspace" - "Hyper-V" - "ISOs" - "Mobile Report Publisher"

All of the parameters don’t have to be included in the splat. For example, Join-String has a switch that, when included, will wrap each item in single quotes.

$splat = @{Property = 'Name'
           Separator = ', '
          }

Get-ChildItem -Directory D:\ |
  Join-String @splat -SingleQuote

Result:
'Backups_Temp', 'CamtasiaWorkspace', 'Hyper-V', 'ISOs', 'Mobile Report Publisher'

Here I used a switch, but it could be another parameter with a value added after the splat.

What if you wanted to include the switch in the hash table though? Switches don’t have a value that is passed in.

That turns out to be a simple answer, just include the switch as a key, and for the value use either $True or $False.

$splat = @{Property = 'Name'
           Separator = ', '
           SingleQuote = $True
          }
Get-ChildItem -Directory D:\ | Join-String @splat

Result:
'Backups_Temp', 'CamtasiaWorkspace', 'Hyper-V', 'ISOs', 'Mobile Report Publisher'

You could also include the switch in the splat, but set the value to $False if you didn’t want to use single quoted every time.

While this example only had a few parameters, I’ve worked with some cmdlets that had a dozen or more parameters that were required to pass in. SQL Server’s cmdlets come to mind.

I often had scripts that had a dozen parameters, but the only one that changed with each call was the actual SQL command I was sending to the server. Using a splat let me reduce the amount of code significantly.

Conclusion

In this post, we saw a lot of fun things you can do with hash tables. A few were creating, updating, adding and removing values. We also covered iterating over a hash table, and even the very useful concept of splatting.

Now you can use these features in your own scripts where a hash table comes into play.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.