PSMonday #34: December 19, 2016

Topic: Switch Statement IV

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

Here we are again. It’s Monday morning and we’re discussing the Switch language construct; we’re wrapping it up, in fact. Last week we determined that Switch included a Wildcard parameter. Today we’ll discuss the Regex parameter, and a bit more.

The below example does a few things. To make this as easiest as possible to follow, I’ve numbered both the list, and the matching code:

  1. Write a string to the host (the screen), to help indicate what the user should do.
  2. Create a prompt to accept the user’s input, and assign that user’s input, to the LastName variable.
  3. Help the user determine their Human Resource representative using a Switch construct and the Regex parameter.
# 1
Write-Output -InputObject 'Enter your last name to determine your Human Resources representative.'

# 2
$LastName = Read-Host -Prompt 'Enter your last name'

# 3
Switch -Regex ($LastName.ToLower()) {
    '^[a-g]' {"Please see Barbara in Room 202."}
    '^[h-m]' {"Please see Mark in Room 203."}
    '^[n-z]' {"Please see Allison in Room 204."}
    default {"$LastName did not work, please try again."}
}

In #3, we’ve set up the Switch statement the same as the other examples; however, we’ve included the Regex parameter. Additionally, the test-value uses the ToLower method, against the value stored in the LastName variable. This ensures our value is in lowercase before we start checking the conditions inside the Switch.

What these conditions do is check the first letter of the last name. Depending on the letter, it’ll report the proper HR representative to visit. One of the things that this example also includes is a default condition. While I could’ve mentioned this week’s ago, I’ve saved it. This is the action to take if there’s no conditional match. Think of this as the Else in an If-Else statement. This could’ve have been included in any of the previous Switch statements we’ve seen in the last three weeks.

Now for the last two examples before we close out the Switch. The $_ variable is something we usually only see when we use ForEach-Object — an upcoming language construct. Even so, it has a purpose in the Switch construct, too. In the below example, it’s acting as the current element in the array. It’s ‘one,’ the first time we enter the Switch, it’s ‘two,’ the second time, etc. Take a look at the example and make sure you can determine why the results were returned the way they were. $PSItem was introduced in PowerShell 3.0, and it does the exact same thing as $_.

$Array = 'one','two','three','four','five'

Switch ($Array) {
    {$_ -eq 'one'} {'One found.'}
    {$PSItem  -eq 'three'} {'Three found.'}
    {$_ -eq 'six'} {'Six found.'}
}

One found.
Three found.

This final example is here to help indicate that we can use the $_, or $PSItem, in both the condition, as we saw above, and in the action, as we’ll see below.

$Servers = 'DC01','DC02','DC03','WEB01'

Switch ($Servers) {
    'DC01'{"Run command against server $_."}
    'DC02' {"Run command against server $_."}
    'WEB01' {"Run command against server $_."}
    {$_} {"Add computer to log file ($_)."}
}

Run command against server DC01.
Add computer to log file (DC01).
Run command against server DC02.
Add computer to log file (DC02).
Add computer to log file (DC03).
Run command against server WEB01.
Add computer to log file (WEB01).

In closing, I should remind everyone that I can’t cover everything about a topic, and so it’s important to finalize your learning, or reviewing, by reading the full about file. You can read about the Switch statement here: Get-Help -Name about_Switch -ShowWindow. Most of it will be a review.

The 1 to 100 Game, Updated

Notes: Download link at the bottom of this post.

My just turned, five-year-old daughter was introduced to my PowerShell 1 to 100 game around two years ago. As I watched her play, I always thought I should make some changes to the game. Well today, I have a newer version, that I’d like to briefly share, and discuss.

First off, you may need to know how to play the 1 to 100 game. It was common in my household as a child, but it’s possible it wasn’t in everyone’s. It works this way: The computer — the function, more or less — chooses a random number between 1 and 100 and you have to try and guess the number. If you choose a number lower than the computer’s number, it will tell you to choose a higher number. If you choose a number higher than the computer’s number, it will tell you to choose a lower number. You continue to do this until you guess the correct number.

What I always thought was necessary for this game was to make it possible to choose whether you even want to use 1 and 100. This 3.0 version of the function will allow you to choose the minimum and maximum numbers. That way, younger kids can play 1 to 10, or 1 to 20. Maybe your kiddo is learning their fifties: You could even play 50 to 59 if you desired. Maybe you have a little downtime while you’re waiting for a server restart; you can play it too. There’s some value here, but not perhaps the value you might typically expect with a PowerShell function. It does have an example of thrice nested Do-While loops. That’s how I pushed the previous version. Skip downloading this 2.0 version, and use the bottom link for version 3.0.

In the older version, it showed the aggregate totals by default. Now, you have to include the ShowTotals switch parameter, if you want to see that collected information. You probably do, if you’re going to play more than once or twice in a row. This information includes nuggets of information like how many games you’ve played, your total number of attempts to guess the right number across all games, and your average attempts per game. These totals have drastically improved, too. In fact, it’ll continue to show the previous totals, and the new totals, after each game. If this is confusing, then take a look at gameplay images further below, and try it out for yourself.

This first image is a game from 1 to 10 that doesn’t include the ShowTotals parameter.

This next image is from two back-to-back games from 1 to 3, that do include the ShowTotals parameter.

So it’s been said, the function defaults to 1 and 100 if you don’t supply minimum and maximum numbers. Try it out when you have a minute, and definitely show it to your kiddos, too. If my daughter is any indication, your kids will enjoy it, as well. I should mention, that she was pestering me to update this function after I first mentioned wanting to make some changes for her. A four-year-old pestering me to write PowerShell: I loved it.

On a final note, there is some redundant code in the function. Since this is just a game, and I have bigger projects, I’m leaving it as-is for now. Maybe I’ll come back around some time and clean it up… we’ll see.

You can download it from the PowerShell Gallery, or better yet, from your PowerShell host application using PowerShellGet and the Install-Script function: Install-Script -Name Start-1to100Game3.0.

PSMonday #33: December 12, 2016

Topic: Switch Statement III

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

In case you haven’t noticed, I really like the Switch statement. Let’s start today’s PSMonday with this first example. It’s dead simple, and really only here for two reasons. One, it indicates we can use the semi-colon between sets of conditions and actions, and two, because I want to indicate the importance of the break statement. After the Switch finds its match in the third condition, it’s going to continue to check the other 23 conditions.

Switch ('c') {
    'a' {'A'}; 'b' {'B'}; 'c' {'C'}; 'd' {'D'}; 'e' {'E'}
    'f' {'F'}; 'g' {'G'}; 'h' {'H'}; 'i' {'I'}; 'j' {'J'}
    'k' {'K'}; 'l' {'L'}; 'm' {'M'}; 'n' {'N'}; 'o' {'O'}
    'p' {'P'}; 'q' {'Q'}; 'r' {'R'}; 's' {'S'}; 't' {'T'}
    'u' {'U'}; 'v' {'V'}; 'w' {'W'}; 'x' {'X'}; 'y' {'Y'}
    'z' {'Z'}
}

C

Let’s avoid that unnecessary work. In this example, after it hits the correct condition, it’ll leave the Switch statement. While there’s not much time savings in this example, there could be, if the Switch was doing more actions than simply echoing a letter to the screen. That’s something to keep in mind as you’re putting these together and considering the completion time of your code.

Switch ('c') {
    'a' {'A'; break}; 'b' {'B'; break}; 'c' {'C'; break}
    'd' {'D'; break}; 'e' {'E'; break}; 'f' {'F'; break}
    'g' {'G'; break}; 'h' {'H'; break}; 'i' {'I'; break}
    'j' {'J'; break}; 'k' {'K'; break}; 'l' {'L'; break}
    'm' {'M'; break}; 'n' {'N'; break}; 'o' {'O'; break}
    'p' {'P'; break}; 'q' {'Q'; break}; 'r' {'R'; break}
    's' {'S'; break}; 't' {'T'; break}; 'u' {'U'; break}
    'v' {'V'; break}; 'w' {'W'; break}; 'x' {'X'; break}
    'y' {'Y'; break}; 'z' {'Z'}
}

C

Instead of putting the true test-value in the parenthesis, we’ll use a variable in the next example. Additionally, we’ll take a look at the Switch’s wildcard parameter. In this example, we’re looking to match multiple conditions. Read it over, and we’ll run through the logic just below the example.

$Building = 'A-Center'

Switch -Wildcard ($Building) {
    'A*' {'Building: A'}
    'B*' {'Building: B'}
    'C*' {'Building: C'}
    'D*' {'Building: D'}
    '*North' {'Location: North'}
    '*South' {'Location: South'}
    '*Center' {'Location: Center'}
    '*East' {'Location: East'}
}

Building: A
Location: Center

The first four conditions, A*, B*, C*, and D*, are in place to match the beginning of the string that was assigned to the Building variable. The first condition, A*, is a match. The last four conditions in the Switch are in place to match the end of the string. Of those, the ‘*Center’ condition is a match. Like it does in other places, the asterisk is a wildcard character; it stands in, for one or more characters.

Here’s the same example, except that we’re outputting the appropriate actions to a variable, instead of writing them to the host. See if you can follow it. Notice that += assignment operators used in the last four conditions. This appends the value to the already existing value assigned to the Location variable.

$Building = 'A-Center'

Switch -Wildcard ($Building) {
    'A*' {$Location = 'Building: A'}
    'B*' {$Location = 'Building: B'}
    'C*' {$Location = 'Building: C'}
    'D*' {$Location = 'Building: D'}
    '*North' {$Location += ', Location: North'}
    '*South' {$Location += ', Location: South'}
    '*Center' {$Location += ', Location: Center'}
    '*East' {$Location += ', Location: East'}
}

$Location

Building: A, Location: Center

There’s still more to cover. We’ll be back with a fourth installment of the Switch language construct next week.

PSMonday #32: December 5, 2016

Topic: Switch Statement II

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

Okay, we’re back with more information on the Switch language construct. We’ll start where we left off: getting the Switch to act more like the If statement. In our first example we’ll do just that, and we do it with the break statement.

Switch (3) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'; break}
    4 {'Four'}
    3 {'Three (again)'}
}

Three

With the inclusion of the break statement, we exit the Switch construct the moment our condition is matched and action is completed.

Typically, I’ll include several break statements in my Switch statements. This is because once my condition is matched and the action completed, I’m typically ready to move past my Switch. In the below example, we’ll exit the Switch the moment a match is made and the action complete.

Switch (3) {
    1 {'One'; break}
    2 {'Two'; break}
    3 {'Three'; break}
    4 {'Four'}
}

Notice that I didn’t use a break statement on the last condition. It doesn’t make sense to include it. If we make it down to the last possible condition, I can be certain it’s not going to check anymore conditions, as there aren’t any more to check.

The switch statement can check collections, too. In this example, we evaluate the test-value of 4, and then the test-value of 2.

Switch (4,2) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'}
    4 {'Four'}
    5 {'Five'}
}

Four
Two

It’s probably a good time to indicate that the break statement can break things, as well. It’s not always a good idea that it’s used. In this next example, 2 is never evaluated because we exit the Switch the moment the action for 4 is complete.

Switch (4,2) {
    1 {'One'; break}
    2 {'Two'; break}
    3 {'Three'; break}
    4 {'Four'; break}
    5 {'Five'}
}

Four

That’s it for today. We have at least one more PSMonday dedicated to the Switch. Maybe two. Okay, probably two.

Function Logging via Write-Verbose

It wasn’t but a couple weeks ago that I wrote a PowerShell function. That’s nothing new — I write them all the time — but I really liked this function. It was a rewrite on something that I rewrote three years ago. Yes, you read that correctly. Back then I was asked to add error checking and logging, which makes this post all that much more interesting.

So, I’m that guy that wants all my functions to produce objects. I don’t want anything different from my functions, your functions, or any I find anywhere else, either. The script I rewrote as a function, does just that, as they all do. It writes objects to the screen, that you can pipe to an output function, or cmdlet, such as Export-Csv. There’s no need to wrap something like Export-Csv inside a function. In fact, please don’t (unless you have a really solid reason for it, such as making things extremely easy for your not-as-skilled users). Instead, just create objects, and let them be piped. Let the user decided what to do with the objects your functions return.

At some point, it dawns on me: I don’t need my function to do logging now; these objects, whether in a CSV or not, tell me what happened. See, I’m actually collecting errors, and making those an object property, too (when they appear, and they haven’t yet). As of late, I’ve been adding a Notes property to my objects in which to store these errors.

I went along with this thought for a day, or so. I’ll never have to log again, right? I mentioned this to my coworker, and he mildly bursts my bubble, “I like to know what my function is doing.” He was right. Just because I was creating thorough objects didn’t guarantee my objects would completely point to a failure. I still needed a back end file that might aid in troubleshooting the function someday. Ugh, the cheer was gone.

I mentioned Write-Verbose to my coworker, and that’s why we’re here today. I’m not going to introduce you to Write-Verbose, as much as I’m going to show you what I’ve decided to do going forward (for now). My functions will still create objects, that I can export if I want to, but now I’m going to optionally log my Write-Verbose statements. They’re already there, why should I add logging, when I can instead choose to push those verbose statements out to a file? Sounds easy, right? No, it was a pain. Unless of course I’ve overlooked something simple, as that’s always a possibility.

In PowerShell, we have streams and redirection operators. Like, take my verbose stream and send it to a file. Nothing I tried, and it’s possible I missed something, allowed me to write the Verbose stream to the host and to my file, at the same time, until I wrote this function. I’m just going to dump this test of a function here, and walk you through it, in order to show you how I got this to work for me. This is it for me: my functions will continue to create objects and my Write-Verbose statements are going to be available for logging.

If you want to download this function inside of a .ps1 file, click below. I don’t typically make my functions available this way; however, it may be easier to follow if you have your own copy. The download includes both the 1.0 and 1.1 version. Follow along in the 1.1 version.

Function Logging via Write-Verbose Examples (3445 downloads )

This post has evolved into something newer, and better.

Function Logging via Write-Verbose

Function Write-VerboseToLogExample {
# Version: 1.1
# 1.0 : Basic example of Write-Verbose to Log file. It doesn't create objects, too, as I was getting this part working.
# 1.1 : Added objects, too, using Get-Service.
    [CmdletBinding()]
    Param (
    )

    DynamicParam {
        # Create dynamic, Log parameter.
        If ($PSBoundParameters.Verbose) {
            $SingleAttribute = New-Object System.Management.Automation.ParameterAttribute
            $SingleAttribute.Position = 1

            $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            $AttributeCollection.Add($SingleAttribute)

            $LogParameter = New-Object System.Management.Automation.RuntimeDefinedParameter('Log',[switch],$AttributeCollection)
            $LogParameter.Value = $true
 
            $ParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
            $ParamDictionary.Add('Log',$LogParameter)
            return $ParamDictionary
        } # End If.
    } # End DynamicParam.

    Begin {
        If ($PSBoundParameters.Verbose -and $PSBoundParameters.Log) {
            $Path = "$(Get-Date -Format 'DyyyyMMddThhmmsstt').txt"
            Function Write-Verbose {
                Param ($Message)
                Microsoft.PowerShell.Utility\Write-Verbose -Message "[$(Get-Date)]: $Message"
                Microsoft.PowerShell.Utility\Write-Verbose -Message "[$(Get-Date)]: $Message" 4>> $Path
            }
        }
        Write-Verbose -Message 'Entering the Begin block.'
    } # End Begin.

    Process {
        Write-Verbose -Message 'Entering the Process block.'
        $Services = Get-Service | Select-Object -First 3
        Foreach ($Service in $Services) {
            Write-Verbose -Message "Starting loop/object creation ($($Service.Name))."

            [PSCustomObject]@{
                Status = $Service.Status
                Name = $Service.Name
                DisplayName = $Service.DisplayName 
            }
        }
    } # End Process.

    End {
        Write-Verbose -Message 'Entering the End block.'
    } # End End.
} # End Function: Write-VerboseToLogExample.

# Write-VerboseToLogExample

# Write-VerboseToLogExample -Verbose

# Write-VerboseToLogExample -Log

# Write-VerboseToLogExample -Verbose -Log

Line 1: Declare (or create) the Write-VerboseToLogExample advanced function.

Line 2 – 4: Function info. Help wasn’t included, as this is a Proof of Concept function.

Line 5 – 7: CmdletBinding attribute and Parameter attribute.

Line 9 – 25: Dynamic, Log parameter. This parameter is only available, if the Verbose parameter is included when the function is invoked.

Line 27 – 37: Begin block: This block includes an If statement that results in True if both the Verbose and Log parameters are included when the function is invoked. Providing both are True, we create a $Path variable that holds the name of a text file that’s based on the current date and time. Next, we write a nested function to memory called Write-Verbose. This means that if Write-Verbose is used later in the function, it’ll use our newly defined function instead of the builtin Write-Verbose cmdlet. The function contains two calls to the original Write-Verbose cmdlet, by using its full path. One command writes the Write-Verbose message to the host and the other redirects to a file. This is the entire “magic” behind writing to both the host and a file at the same time. At the end of this Begin block we have a single Write-Verbose statement, that again, will use the new Write-Verbose function, if both parameters were included.

Line 39 – 51: Process block: This block has a opening Write-Verbose statement. Following this, we return the first three services using Get-Service. Then we use the results to create our own custom object from the results. This is simply for demonstration purposes. It’s proof we’re creating objects and writing our Write-Verbose message to two places.

Line 53 – 55: End block: This block has a single Write-Verbose command.

Line 56: Close function declaration from line 1.

The next several lines run the function in one of four ways. The first option runs the function in a standard fashion (no parameters). The second option includes the Verbose parameter which indicates that verbose statements will be written to the host. The third option include a Log parameter without the Verbose parameter. This fails, as the Log parameter is dynamic: It doesn’t exist unless the Verbose parameter is included. The final option includes both the Verbose and Log parameters. Because of our custom, nested function it’ll write verbose messages in our host and in a log file at nearly the same time.

Simple, yet powerful. Here’s the results of those four different function invocations.

PS > Write-VerboseToLogExample

 Status Name                      DisplayName                      
 ------ ----                      -----------                      
Running AdobeARMservice           Adobe Acrobat Update Service     
Stopped AdobeFlashPlayerUpdateSvc Adobe Flash Player Update Service
Stopped AeLookupSvc               Application Experience

PS > Write-VerboseToLogExample -Verbose

VERBOSE: Entering the Begin block.
VERBOSE: Entering the Process block.
VERBOSE: Starting loop/object creation (AdobeARMservice).

VERBOSE: Starting loop/object creation (AdobeFlashPlayerUpdateSvc).
VERBOSE: Starting loop/object creation (AeLookupSvc).
VERBOSE: Entering the End block.
 Status Name                      DisplayName                      
 ------ ----                      -----------                      
Running AdobeARMservice           Adobe Acrobat Update Service     
Stopped AdobeFlashPlayerUpdateSvc Adobe Flash Player Update Service
Stopped AeLookupSvc               Application Experience 

PS > Write-VerboseToLogExample -Log
Write-VerboseToLogExample : A parameter cannot be found that matches parameter name 'Log'.
At line:1 char:27
+ Write-VerboseToLogExample -Log
+                           ~~~~
    + CategoryInfo          : InvalidArgument: (:) [Write-VerboseToLogExample], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Write-VerboseToLogExample

PS > Write-VerboseToLogExample -Verbose -Log
VERBOSE: [11/23/2016 23:07:30]: Entering the Begin block.
VERBOSE: [11/23/2016 23:07:30]: Entering the Process block.
VERBOSE: [11/23/2016 23:07:30]: Starting loop/object creation (AdobeARMservice).

VERBOSE: [11/23/2016 23:07:30]: Starting loop/object creation (AdobeFlashPlayerUpdateSvc).
VERBOSE: [11/23/2016 23:07:30]: Starting loop/object creation (AeLookupSvc).
VERBOSE: [11/23/2016 23:07:30]: Entering the End block.
 Status Name                      DisplayName                      
 ------ ----                      -----------                      
Running AdobeARMservice           Adobe Acrobat Update Service     
Stopped AdobeFlashPlayerUpdateSvc Adobe Flash Player Update Service
Stopped AeLookupSvc               Application Experience

This final example also creates our log file in my current directory.

function-logging-via-write-verbose01

Update: I’ve made a few changes since I first wrote and shared this post. The only change from the above posted and linked version is removing “[$(Get-Date): ” from the first Write-Verbose command inside the nested Write-Verbose function (line 32). After giving it some time, and thought, I didn’t believe it was ever going to be necessary to include the date and time on the screen when Write-Verbose ran. It doesn’t happen when you don’t include the -Log parameter, and so it shouldn’t happen when you do. I left it as a part of the Write-Verbose commands that are written to file, because the date and time are more important there.

PSMonday #31: November 28, 2016

Topic: Switch Statement

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

The Switch language construct, also called the case statement in other languages, is a close relative to the If statement and its variations. As you work with If, be sure to consider Switch, as it can assist in a cleaner layout, and therefore, more easily read code. As mentioned previously, if your If statements are going past three levels, consider the Switch.

To start, here’s the basic, conceptual format. We consider a test-value in the parenthesis, determine the matching condition on the left, and then execute its corresponding action on the right.

Switch (<test-value>) {
    <condition> {<action>}
    <condition> {<action>}
    <condition> {<action>}
}

To begin, here’s a very basic example. We evaluate the test-value — it’s just a numeric 3 — and then find the matching condition. Once found (the 3 in our list of conditions), we’ll take the corresponding action, and write the word “Three” to the screen. Simple.

Switch (3) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'}
    4 {'Four'}
}

Three

Our test-value can also be an equation: 2 + 2 (= 4) and then down through the possible conditions, and take the appropriate action.

Switch (2 + 2) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'}
    4 {'Four'}
}

Four

There’s something we need to understand about the Switch construct, and that is that it is designed to look at all the conditions, no matter if it’s found one already, or not. Take a look at this example for clarification.

Switch (3) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'}
    4 {'Four'}
    3 {'Three (again).'}
    5 {'Five'}
}

Three
Three (again).

In the above example, we can easily see that although it found 3 in the list of conditions, it continued looking through the additional conditions, only to find another one that matched. What we should have done, is just included multiple commands inside the action, like the following two examples. Notice that in the first example, we use the semi-colon as a command separator, and in the second example, we use the line break (Enter).

Switch (3) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'; 'Three (again, but not really).'}
    4 {'Four'}
}

Three
Three (again, but not really).

Switch (3) {
    1 {'One'}
    2 {'Two'}
    3 {'Three'
       'Three (again, but not really).'
    }
    4 {'Four'}
}

Three
Three (again, but not really).

Make sure you fully understand these examples before next week. We’ll start that PSMonday in an effort to show how to get our Switch statements to act a bit more like the If statement, to exit when our condition is matched, and action taken.

PSMonday #30: November 21, 2016

Topic: If, If-Else, If-ElseIf III

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

I failed to mention something last week. While I wouldn’t recommend you do it, you can rewrite this:

If (-Not(<condition>)) {
    <action>
}

to be this:

If (!(<condition>)) {
    <action>
}

I’m not mentioning this because you should use ! over -Not (ever, honestly), but just in case you see it being used. As I believed we’ve mentioned before, we only use aliases in onetime use scenarios, such as when you’re entering commands in your ConsoleHost or the ISE and have no intention of saving what you’ve entered. The ! is not a true alias, but it’s close enough to consider it one. This is a PowerShell community best practice, and one I’ll continue to pound in, at every opportunity I have.

Okay, on with this week’s If wrap-up.

Let’s get away from these conceptual examples. In this first example, we’ll assign values to two variables: $y will hold the numeric value of 5, and $z will hold the numeric value of 3. When we enter the If statement, we check both values. If both — and that’s key — of their values match, we’ll echo the word “If.”

$y = 5; $z = 3

If ($y -eq 5 -and $z -eq 3) {
    Write-Output -InputObject 'If'
}

If

Had we used the -or comparison operator, it would’ve echoed “If,” as well. Or, means that only one of the conditions would have to result In True.

If ($y -eq 5 -or $z -eq 10) {
    Write-Output -InputObject 'If'
}

If

In the above example, only $y -eq 5 was True. As mentioned, since we used the -or operator, only one of those conditions needed to result in True for the condition to pass. The below example uses the -and comparison operator again; however, the end results is False, so the Else portion of the If-Else is executed.

$y = 5; $z = 3

If ($y -eq 5 -and $z -eq 2) {
    Write-Output -InputObject 'If'
} Else {
    Write-Output -InputObject 'Else'
}

Else

Pretty straightforward. Let’s modify the above examples and make our Else, and ElseIf. When this example executes, the If portion will be False ($z was not assigned a numeric value of 2), so the ElseIf condition will be checked. This will result in True, as $z was assigned a numeric value of 3.

$y = 5; $z = 3

If ($y -eq 5 -and $z -eq 2) {
    Write-Output -InputObject 'If'
} ElseIf ($y -eq 5 -and $z -eq 3) {
    Write-Output -InputObject 'ElseIf'
}

ElseIf

In our final example we’ll include two ElseIf conditions. Notice in this example, that once the first one results in True, we exit the construct. That final ElseIf, while it would have also resulted in True, isn’t even considered. While we won’t go into it for now, you can nest language constructs. This is to say, we could’ve added another If statement inside the action portion of the ElseIf, and tested for $z -eq 3.

$y = 5; $z = 3

If ($y -eq 5 -and $z -eq 2) {
    Write-Output -InputObject 'If'
} ElseIf ($y -eq 5) {
    Write-Output -InputObject 'ElseIf 1' # Exits If-ElseIf.
} ElseIf ($z -eq 3) {
    Write-Output -InputObject 'ElseIf 2'
}

ElseIf 1

We’re going to end here with the If language construct, and start fresh with the Switch statement next Monday. I encourage you to ask any questions you might have about the If statement, as it’s vital you have a good understanding of this introductory language command.

Keep in mind the examples could’ve been much different than just comparing numbers. We could have return services and taken action based on whether a service was located, or not, or running or stopped. We could have returned a specific Active Directory user and taken action based on whether we found the user, or not. The list goes on.

Get the AWS Noun Prefixes

One of the nice things about the Get-AWSPowerShellVersion cmdlet is the ListServiceVersionInfo switch parameter. It returns properties for the Service (as in the AWS Service offering name), the Noun Prefix, and API Version. Yes, there really are spaces in those last two property names; however, they’ve been fixed in my function. I had been hoping for an easier way to determine the prefixes used in the AWS cmdlets, and here we have it. I actually considered parsing cmdlet names myself, so a huge thanks to AWS, for making sure that wasn’t necessary.

It’s almost as though this should have been its own cmdlet—a get the version cmdlet and a get the noun prefixes cmdlet. Therefore, I’ve wrapped this command and its parameter in a quick and easy-to-use function for my user base. Copy, paste, and try it out; it’s all yours. Super simple.

Function Get-AWSNounPrefix {
<#
.SYNOPSIS
    The function returns the AWS PowerShell cmdlet noun prefixes, along with the corresponding AWS Service.

.DESCRIPTION
    The function returns the AWS PowerShell cmdlet noun prefixes, along with the corresponding AWS Service name. This function utilizes the AWSPowerShell module's Get-AWSPowerShellVersion function.

.EXAMPLE
    -------------------------- EXAMPLE 1 --------------------------
    PS > Get-AWSNounPrefix
    This examples returns all the noun prefixes and their corresponding AWS Service name.

.EXAMPLE
    -------------------------- EXAMPLE 2 --------------------------
    PS > Get-AWSNounPrefix | Where-Object NounPrefix -match 'cf'
    NounPrefix Service            APIVersion
    ---------- -------            ----------
    CF         Amazon CloudFront  2016-09-29
    CFG        AWS Config         2014-11-12
    CFN        AWS CloudFormation 2010-05-15

    This example uses the Where-Object cmdlet and the Match operator to filter the results by the NounPrefix.

.EXAMPLE
    -------------------------- EXAMPLE 3 --------------------------
    PS > Get-AWSNounPrefix | Where-Object Service -like '*formation*'
    NounPrefix Service            APIVersion
    ---------- -------            ----------
    CFN        AWS CloudFormation 2010-05-15

    This example uses the Where-Object cmdlet and the Like operator to filter the results by the service name.

.EXAMPLE
    -------------------------- EXAMPLE 4 --------------------------
    PS > Get-AWSNounPrefix | Where-Object -Property APIVersion -like '2016*' | Sort-Object -Property APIVersion -Descending
    NounPrefix Service                          APIVersion
    ---------- -------                          ----------
    SMS        Amazon Server Migration Service  2016-10-24
    BGT        AWS Budgets                      2016-10-20
    CF         Amazon CloudFront                2016-09-29
    EC2        Amazon Elastic Compute Cloud     2016-09-15
    SNOW       AWS Import/Export Snowball       2016-06-30
    CGIP       Amazon Cognito Identity Provider 2016-04-18
    INS        Amazon Inspector                 2016-02-16
    AAS        Application Auto Scaling         2016-02-06
    MM         AWS Marketplace Metering         2016-01-14
    DMS        AWS Database Migration Service   2016-01-01

    This example uses the Where-Object, and Sort-Object cmdlet, to find services updated in 2016 and sorts by the most recently added and updated.

.NOTES
    Name: Get-AWSNounPrefix
    Author: Tommy Maynard
    Comments: Current version of AWSPowerShell module at the first, last edit: 3.3.20.0.
    Last Edit: 11/18/2016
    Version 1.0
#>
    [CmdletBinding()]
    Param (
    )

    Begin {
        $AWSServices = Get-AWSPowerShellVersion -ListServiceVersionInfo | Sort-Object -Property 'Noun Prefix'
    } # End Begin.

    Process {
        Foreach ($AWSService in $AWSServices) {
            [PSCustomObject]@{
                NounPrefix = $AWSService.'Noun Prefix'
                Service = $AWSService.Service
                APIVersion = $AWSService.'API Version'
            }
        } # End Foreach.
    } # End Process.

    End {
    } # End End.
} # End Function: Get-AWSNounPrefix.

 

PSMonday #29: November 14, 2016

Topic: If, If-Else, If-ElseIf II

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

Let’s start by discussing the fact that we can reverse the way an If statement works. Last week, we discussed that we take a specific action(s) when conditions result in true, such as in the below, conceptual example.

If (<condition>) {
    <action>
}

This can be changed for the times it’s necessary. In the next example, we’ll complete the action if the condition is false — if it’s not true. The Not logical operator negates whatever follows it. Only use the Not operator when it’s absolutely necessary. If it’s not necessary, then there’s no reason to make your conditionals any more difficult to think through.

If (-Not(<condition>)) {
    <action>
}

The below examples help show how the Not logical operator changes the condition, and therefore, the action. In the first below example, the If statement will output the word “If,” because $true evaluates to True.

If ($true) {'If'} Else {'Else'}
If

In the next example, we negate $true, making it $false, so “Else” will be written to the screen.

If (-Not($true)) {'If'} Else {'Else'}
Else

In the next example, it’ll write “If” again. You can actually walk backwards through the conditions, saying it aloud: “True, becomes False, becomes True. It’ll write If.” See if you can do that with the last two examples. While these may be helpful for learning, there likely won’t ever be a time you’re negating a Not logical operator.

If (-Not(-Not($true))) {'If'} Else {'Else'}
If

If (-Not(-Not(-Not($true)))) {'If'} Else {'Else'}

If (-Not(-Not(-Not(-Not(-Not(-Not($true))))))) {'If'} Else {'Else'}

In closing, we’ll take a look at a final example. On the first line in the below example, we assign the variable x a value of 9. When we only put $x inside the If statement’s condition, it only evaluates whether or not the variable x exists. It pays no attention to the value that’s been assign to the variable x. In the If statement following that one, we evaluate the value assigned to the variable x. If that value is equal to 9, and it is, we’ll write the word  “If” to the screen.

$x = 9

If ($x) {
    Write-Output -InputObject 'If'
}
If

If ($x -eq 9) {
    Write-Output -InputObject 'If'
}
If

We’ll close up the If topic next week. Please let me know if there are any questions on today’s PSMonday.

PSMonday #28: November 7, 2016

Topic: If, If-Else, If-ElseIf

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

Time to start learning, or reviewing, those language constructs — those “language commands,” as is the term used in the If statement’s, about topic help file. This file can be read by using the below command.

Get-Help -Name about_If

The If statement is typically the introductory control structure that someone encounters when they begin with a programming, or scripting, language. It is also the one people likely think of first when they need to start checking conditions and taking appropriate actions.

Here’s the basic, PowerShell If structure. We check a condition, and if it’s true, then we take the included action, or actions.

If (<condition>) {
    <action>
}

There are several variations of the If statement: Here’s the If-Else. This is much like the If, except that if the condition results in false, it would complete action2 instead of exiting the construct and ultimately doing nothing. Had the condition been true, it would’ve completed action1, as we saw in the first example.

If (<condition>) {
    <action>
} Else {
    <action2>
}

Here’s the If-ElseIf. The way this works is if condition1 is false, it will try condition2. If that’s true, it’ll run action2, but if it’s false, it’ll exit and take no action.

If (<condition1>) {
     <action1>
} ElseIf (<condition2>) {
    <action2>
}

If-ElseIf-Else is just like the above example; however, if condition2 resulted in false, it would complete action3 as the default action.

If (<condition1>) {
    <action1>
} ElseIf (<condition2>) {
    <action2>
} Else {
    <action3>
}

There’s really no limit to how many ElseIfs you include. Just keep in mind that Else completes a default action, as there’s no condition to check, while ElseIf requires a condition be checked (and be true), before the listed action is completed.

On a final note, if you’re going past three levels in your If constructs, then you may want to use the Switch statement. We’ll get to that one once we’ve completely knocked out the If.