Tag Archives: PSMonday

PSMonday #48: March 27, 2017

Topic: The (Online) End of PowerShell Monday

For those following along online, as opposed to those at my workplace, this is the end of the road for PowerShell Monday. The following five weeks of PSMondays are work only, as they describe an advanced function template I’ve written, for those writing PowerShell tools in the office. The reason I’ve decided to end here, is that the posts may be a bit more work specific, and that I’ve actually already offered up this function for public consumption.

At work, we always wanted a standard logging function. Instead of writing that, I incorporated the logging ability into a function template that’s usable for any PowerShell tool we write. This means, that there’s no separate logging function for our functions. It’s built in, if you need it. Before I decided this is something we really should use at work, I actually shared it here first. You can already learn about it, see it for yourself, download it, and use it all you want. The way I accomplished this logging, is by using Write-Verbose to write to the host program, and to a log file, too.

Thanks to those that read the PSMonday series, or any of my posts, really.
http://tommymaynard.com/function-logging-via-write-verbose-2016/

PSMonday #47: March 20, 2017

Topic: Reusable Code V

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 know, I know, I said this would be a four part series, but we’re adding a fifth installment; it’s going to be worth it.

Now that we have a function we want to use whenever it makes sense, we need a place to put it. While we could dot source our Process.ps1 file every time we want to add the function to our scope (like we did last week), there’s two better options. The first option is the profile script. This is a .ps1 file that runs every time you open a new PowerShell ConsoleHost. There’s actually one for the ISE, too.

The below example shows how to determine where the profile script should be located for the current host program (the ConsoleHost).

$PROFILE

C:\Users\tommymaynard\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

Now, just because we know the path and file, doesn’t mean the file actually exists. The next thing we should do is test the path to determine if the file exists, or not. Test-Path is a helpful cmdlet, in that it can determine if files and folders exist.

Test-Path -Path $PROFILE

False

If you received False when you run the above command, you don’t yet have a profile script. If you do have one, it’ll indicate True. For those with False, let’s quickly create a profile script and then open it.

New-Item -Path $PROFILE -ItemType File -Force

Once this command is run, it’ll indicate that it’s created the profile script file. It’s a simple text file, so it can be opened and edited a number of different ways. As of now, I tend to modify my profile script in the PowerShell ISE. To edit yours in the ISE, use the first below example. To use Notepad, use the second one. For those already using Visual Studio Code, you can open it there as well.

ise $PROFILE

notepad $PROFILE

With your profile script opened, you can add the function we finished with last Monday. It’s included below.

Function Get-TMService {
    Param (
        [Parameter(Mandatory=$true)]
        [string]$Service
    )
 
    try {
        Get-Process -Name $Service -ErrorAction Stop |
            Select-Object -Property @{N='Process Name';E={$_.Name}},
                Description,
                Company,
                @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
                @{N='Private Memory Size';
                    E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}
    } catch {
        Write-Warning -Message "Cannot locate the $Service process."
    }
}

Now, if you’re following along, enter the below command.

Get-TMService -Service powershell_ise

This command should fail, whether or not, the PowerShell ISE is running. It’s because you added the function to your profile script after the profile script was last run. Close the PowerShell ConsoleHost and then open a new one. Doing this will ensure the recently added function is available in your PowerShell session. At this point, the above Get-TMService command should run successfully.

The second option is to use a PowerShell module. Creating a module can get much more complex, as can most things, but there’s just a few steps to make it work at its simplest form. A module is typically created to hold several related functions; however, it can only hold one function, if that’s all you have for now.

First, copy the above function into a text file, giving it an appropriate name, and saving it as a .psm1 file. For instance, call the new file MyFunctions.psm1 and paste the function code inside of it. Now, create a folder with the same name as the module file (without the file extension). This means your folder would be called MyFunctions. The name of the file and the folder must be the same. Now, move the file into the folder.

Next, we need to relocate this folder to a location in the filesystem where PowerShell will look for modules automatically. You can see those locations using the below example.

$env:PSModulePath -split ';'

C:\Users\tommymaynard\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

You’re welcome to use “C:\Program Files\WindowsPowerShell\Modules\” if you want all users on the computer to use the module. If you’re happy with just you being able to use your module, then place it in your profile folder. The final above path, in System32, shouldn’t be bothered if you can help it.

With this completed, the next time you open the PowerShell ConsoleHost you’re module, and that contained function, will be available. If you write some more functions, you can always add them to this same module file, just like you could your profile script.

PSMonday #46: March 13, 2017

Topic: Reusable Code 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.

The below example is the same one we ended on last Monday. What I need you to imagine is that this code now exists in a file called Process.ps1, on the desktop of your own computer. You can even put it there if you want to follow along.

$Service = Read-Host -Prompt 'Enter a Process Name'

try {
    Get-Process -Name $Service -ErrorAction Stop |
        Select-Object -Property @{N='Process Name';E={$_.Name}},
            Description,
            Company,
           @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
           @{N='Private Memory Size';
               E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}
} catch {
    Write-Warning -Message "Cannot locate the $Service process."
}

In the next example, we’ll begin by changing directories to the desktop. Once there, we’ll run our Process.ps1 file that contains the code we’ve been constructing over the last few weeks. As you’re likely aware, changing directories — the first below command — isn’t necessary, had we simply supplied the full path to the Process.ps1 file in the second command.

PS > Set-Location -Path C:\Users\tommymaynard\Desktop

PS > .\Process.ps1
Enter a Process Name: powershell_ise

Process Name : powershell_ise
Description : Windows PowerShell ISE
Company : Microsoft Corporation
Shared Memory : 181 MB
Private Memory Size : 159 MB

PS > # FYI: Notepad is not currently running.
PS > .\Process.ps1
Enter a Process Name: notepad
WARNING: Cannot locate the notepad process.

After instructing the .ps1 to execute, it immediately prompts us to enter a process name just as we’ve seen in the past. If we enter something that’s running, it returns our modified information according to the command we’ve written. If it’s not running, it displays the Write-Warning message as opposed to throwing the red, and sometimes intimidating, error message we saw last week. What an easy way to return only what you want, and without the need to rewrite the code each time.

Here’s the thing: People love the Read-Host cmdlet, but there’s a better way. Let’s use a Param block instead. This next example does just that. As you move into writing functions, you’ll quickly begin to understand why parameters are better. So you can continue to picture this, we’re saving the below modification over what we had in the Process.ps1 file on the desktop. Watch how we run it now!

Param (
    [string]$Service
)
 
try {
    Get-Process -Name $Service -ErrorAction Stop |
        Select-Object -Property @{N='Process Name';E={$_.Name}},
            Description,
            Company,
            @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
            @{N='Private Memory Size';
                E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}
} catch {
    Write-Warning -Message "Cannot locate the $Service process."
}
 
PS > .\Process.ps1 -Service notepad
WARNING: Cannot locate the notepad process.
 
PS > .\Process.ps1 -Service powershell_ise
 
 
Process Name        : powershell_ise
Description         : Windows PowerShell ISE
Company             : Microsoft Corporation
Shared Memory       : 178 MB
Private Memory Size : 147 MB

Now, instead of the code using Read-Host to prompt us for input, we have a -Service parameter we can use. When the code was invoked, it took the parameter value we supplied and used it to set the $Service variable. There’s one problem here, however. If we don’t enter the Service parameter, the function will still try and check for a service that wasn’t even included. Let’s make the Service parameter mandatory; we can do that with one quick addition to our code.

Param (
    [Parameter(Mandatory=$true)]
    [string]$Service
)
 
try {
    Get-Process -Name $Service -ErrorAction Stop |
        Select-Object -Property @{N='Process Name';E={$_.Name}},
            Description,
            Company,
            @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
            @{N='Private Memory Size';
                E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}
} catch {
    Write-Warning -Message "Cannot locate the $Service process."
}

Now, if we forget the Service parameter value, it’ll prompt us to enter it. I had to manually enter “powershell_ise” when it prompted me on the fourth line down, where it says “Service:”.

PS > .\Process.ps1
cmdlet Process.ps1 at command pipeline position 1
Supply values for the following parameters:
Service: powershell_ise
 
 
Process Name        : powershell_ise
Description         : Windows PowerShell ISE
Company             : Microsoft Corporation
Shared Memory       : 188 MB
Private Memory Size : 156 MB

The ultimate goal of someone that really wants to learn PowerShell well, is to lose the whole I-write-scripts mentality, and embrace an I-write-functions mentality. Let’s take our code and make it a function; there’s literally two changes.

We add a new first line that uses the Function keyword. Following that, we give our function a name and add an open, curly brace. Remember as you create functions, to use approved verbs (see Get-Verb for the approved list), a dash, and a singular noun, or singular nouns. You might also add a prefix to the noun, too, such as I’ve done by adding “TM.” This ensures my function won’t take precedence over the Microsoft written and included Get-Service cmdlet (that we actually use inside the Get-TMService function).

Function Get-TMService {
    Param (
        [Parameter(Mandatory=$true)]
        [string]$Service
    )
 
    try {
        Get-Process -Name $Service -ErrorAction Stop |
            Select-Object -Property @{N='Process Name';E={$_.Name}},
                Description,
                Company,
                @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
                @{N='Private Memory Size';
                    E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}
    } catch {
        Write-Warning -Message "Cannot locate the $Service process."
    }
}

So it’s been said, we’ve again taken the above code and saved it over what we had in Process.ps1. Here’s the trick with using functions that are saved in .ps1 files. To add the Get-TMService function to our PowerShell session, we need to dot source the file. This will make the function available for use. The second below command has a dot and a space before the path and the file name (. .\Process.ps1). That dot is vital, so don’t overlook it. Let’s start by ensuring the function doesn’t yet exist.

PS > Get-Command -Name Get-TMService
Get-Command : The term 'Get-TMService' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again...
 
PS > . .\Process.ps1
 
PS > Get-Command -Name Get-TMService
 
CommandType     Name             Version    Source     
-----------     ----             -------    ------     
Function        Get-TMService
 
 
PS > Get-TMService -Service powershell_ise
 
 
Process Name        : powershell_ise
Description         : Windows PowerShell ISE
Company             : Microsoft Corporation
Shared Memory       : 198 MB
Private Memory Size : 174 MB

Had you read this and the previous three lessons, you’ve seen how we started with a simple command and turned it into a tool that we can use whenever it’s needed. If you give PowerShell some time now, you’re going to get your time back in the future. Until next week.

PSMonday #45: March 6, 2017

Topic: Reusable Code 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.

Back again.

We’ve made two new changes to the below code. One, we replaced powershell_ise, inside of our Get-Process command, with $Service. Two, we added a new, first line to our code. This command will prompt the user to enter a value. Read-Host will then assign that value to the $Service variable. That value will be used in the remainder of the PowerShell code every place $Service is found (there’s only the one). Now, the code is no longer only good for checking for the powershell_ise process; it’ll check for whatever process is entered.

$Service = Read-Host -Prompt 'Enter a Process Name'
    Get-Process -Name $Service |
        Select-Object -Property @{N='Process Name';E={$_.Name}},
        Description,
        Company,
        @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
        @{N='Private Memory Size';
            E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}

If you were to open notepad, you could use this code to return its process information. So let’s do that; let’s say we have notepad open and we run our code.

Enter a Process Name:

Enter a Process Name: notepad

Process Name        : notepad
Description         : Notepad
Company             : Microsoft Corporation
Shared Memory       : 9 MB
Private Memory Size : 1 MB

Our few lines of code just became useable against any running process on the computer. To be as thorough as possible, we need to consider what happens when we enter a process that isn’t actually running — what’s it going to do? Let’s close notepad and find out.

Enter a Process Name: notepad

Get-Process : Cannot find a process with the name "notepad". Verify the process name and call the cmdlet again.
At line:3 char:1
+ Get-Process -Name $Service |
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (notepad:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand

Get-Process doesn’t handle this gracefully, so let’s make a few more changes. We’ll first add a try-catch. The try portion will wrap the Get-Process and Select-Object commands. While it isn’t always necessary, we need to add the ErrorAction parameter name, with the Stop parameter value to Get-Process. This is required in order to prevent this error from being displayed. Forcing a terminating error isn’t always required, so don’t add it to commands when it’s not necessary. You try it without -ErrorAction. If it doesn’t work, you try -ErrorAction SilentlyContinue, and if that doesn’t work, you use -ErrorAction Stop, as we’ve done here.

The catch portion of our try-catch wraps a newly added, Write-Warning command that will gracefully indicate when a process isn’t running, or perhaps, just wasn’t spelled correctly.

$Service = Read-Host -Prompt 'Enter a Process Name'

try {
    Get-Process -Name $Service -ErrorAction Stop |
        Select-Object -Property @{N='Process Name';E={$_.Name}},
            Description,
            Company,
            @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
            @{N='Private Memory Size';
                E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}
} catch {
    Write-Warning -Message "Cannot locate the $Service process."
}


Here’s what happens now, when you enter a process that isn’t running, or doesn’t even exist.

[powershell]
Enter a Process Name: notepad
WARNING: Cannot locate the notepad process.

Enter a Process Name: asdf
WARNING: Cannot locate the asdf process.

That’s it for this Monday. Keep paying attention; it’s about to get good.

PSMonday #44: February 27, 2017

Topic: Reusable Code 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.

In today’s PSMonday, we’ll jump right back into calculated properties, as we continue to create some reusable code. Last week our final addition was to use a calculated property to modify the name of a property, as can be seen below. We took its default value of “Name,” and changed it to “Process Name.”

Get-Process -Name powershell_ise |
    Select-Object -Property @{Name='Process Name';Expression={$_.Name}},Description,Company,WorkingSet,PrivateMemorySize

Today we’ll add two more calculated properties, but before we do, let’s reformat this code a bit, so it fits better. First, we’re going to use “N” instead of Name and “E” instead of Expression, for the keys in our calculated property hash table. Second, we’ll take advantage of the commas between our  properties which allows each of them to sit on their own line. We could have put a space after each comma and left them on the same line as the first property, and it would have wrapped them for us; however, we’re about to add those other calculated properties.

Get-Process -Name powershell_ise |
    Select-Object -Property @{N='Process Name';E={$_.Name}},
        Description,
        Company,
        WorkingSet,
        PrivateMemorySize

The WorkingSet and PrivateMemorySize values are being reported in bytes. Let’s modify that, beginning with the WorkingSet property. Take a look at the newest changes, and we’ll discuss them after the example and its results.

Get-Process -Name powershell_ise |
    Select-Object -Property @{N='Process Name';E={$_.Name}},
        Description,
         Company,
        @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
        PrivateMemorySize

Process Name      : powershell_ise
Description       : Windows PowerShell ISE
Company           : Microsoft Corporation
Shared Memory     : 420 MB
PrivateMemorySize : 405536768

As you can see in the above example, we first changed the term “WorkingSet” to “Shared Memory.” This time, however, we also modify the value it displays using the Expression key-value pair. We won’t go into this too deep, other than to say we first, divided our Working Set value by 1 MB, as we wanted to report our values in megabytes. Second, we directly accessed .NET to round our value using a Round method, and finally, we added the string “MB” to the end of the value to make it clear what measurement we’re using.

Next, we’ll add a third calculated property, but this time to the PrivateMemorySize property. This will allow it to function just like the modified WorkingSet property. As you can likely tell, I’ve used more lines than is necessary, in order that this best fits.

Get-Process -Name powershell_ise |
    Select-Object -Property @{N='Process Name';E={$_.Name}},
        Description,
        Company,
        @{N='Shared Memory';E={"$([Math]::Round($_.WorkingSet / 1MB)) MB"}},
        @{N='Private Memory Size';
            E={"$([Math]::Round($_.PrivateMemorySize / 1MB)) MB"}}

Process Name        : powershell_ise
Description         : Windows PowerShell ISE
Company             : Microsoft Corporation
Shared Memory       : 420 MB
Private Memory Size : 387 MB

Okay, let’s stop here and pick up from this point next Monday.

PSMonday #43: February 20, 2017

Topic: Reusable Code I

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.

After I type the same thing a few times, and suspect I’ll need, or want, to continue to do that, I’ll typically write a function for it, so that I never have to type it again. That’s the purpose of a function. It’s a container for a series of commands that I can run, or invoke, simply by entering its name. Today we’ll start a four-part PSMonday on how to reuse code from beginning to end. As we close up PSMonday, these last several are going to be the ones in which to really pay attention.

Let’s start by entering a simple, Get-Process command, in order to determine whether or not the PowerShell ISE — the PowerShell Integrated Scripting Environment — is currently running.

Get-Process -Name powershell_ise | Select-Object -Property ProcessName,Id

ProcessName      Id
-----------      --
powershell_ise 5732

In the above example, we used Select-Object to filter the properties that are returned by Get-Process. The ISE is running, otherwise we would’ve received an error, indicating that the process could not be found.

Next, let’s pipe the results of an unfiltered, Get-Process command to a mildly modified Get-Member command, and take a look at all the properties of the returned object.

Get-Process -Name powershell_ise | Get-Member -MemberType Property

Here’s another filtered Get-Process command, that only includes the properties that hold information in which I am interested.

Get-Process -Name powershell_ise |
    Select-Object -Property Name,Description,Company,WorkingSet,PrivateMemorySize

Name              : powershell_ise
Description       : Windows PowerShell ISE
Company           : Microsoft Corporation
WorkingSet        : 162627584
PrivateMemorySize : 153522176

Let’s make a change to the Name property using what’s called a calculated property. Among other things, a calculated property allows us to rename a property’s default name to something else.

Get-Process -Name powershell_ise |
    Select-Object -Property @{Name='Process Name';Expression={$_.Name}},Description,Company,WorkingSet,PrivateMemorySize

Process Name      : powershell_ise
Description       : Windows PowerShell ISE
Company           : Microsoft Corporation
WorkingSet        : 162324480
PrivateMemorySize : 153812992

The calculated property looks like this, when it’s all by itself.

@{Name='Process Name';Expression={$_.Name}}

Notice in the above results that Name property is now named, Process Name. The calculated property consists of a hash table, as signified by @{}, that contains two, key-value pairs. One pair includes the Name key, and the second key-value pair includes an Expression key. We’ll continue next week with some additional examples of calculated properties, as we continue to learn about creating reusable code.

PSMonday #42: February 13, 2017

Topic: While

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 last language construct we’re going to discuss is the While loop — yes, another looping construct. Let’s start with the help file in the first below command, followed by two ways to write the conceptual structure of the While loop.

Get-Help -Name about_While -ShowWindow

While (<condition>){<statement list>}

While (<condition>) {
     <statement list>
}

Our first below example of the While loop, well, it does absolutely nothing. We begin by setting our $Value variable to the numeric value of 1, and then we (attempt) to enter the While loop. The biggest difference between the While loop and the Do loop is that our conditions come before the statement lists. This should be reminiscent of the If, and Switch statement variations, where the evaluations come first.

$Value = 1

While ($Value -eq 5) {
    $Value
    $Value = $Value + 1
}

In the next example, we’ll make one simple change and the code will run. Our condition will evaluate the $Value variable such that it’s $true when $Value is less than or equal to 5. Remember from the For loop, that $Value++ is the same as writing $Value = $Value + 1.

$Value = 1

While ($Value -le 5) {
    $Value
    $Value++
}

1
2
3
4
5

Our final example for the While loop, gives the user an opportunity to try and guess a number between one and five. Before we potentially, enter the While construct, we’ll set the $MagicNumber variable to the random number and the $Continue variable to $true. We enter the While providing that $Continue is equal to $true, and we know it will be, as it was just assigned that value.

Inside the statement list, we (1) request the user enter a number between one and five, and (2) use and If-Else to see if the $MagicNumber matches the guess entered by the user, as stored in $Guess. If it matches, we indicate that, and then set $Continue to $false. This means that the next time the While begins, the condition won’t match and we won’t enter the While. The loop will be over. If $Guess and $MagicNumber don’t match, the While will execute again, and we’ll ask for another number.

$MagicNumber = Get-Random -Minimum 1 -Maximum 5
$Continue = $true

While ($Continue -eq $true) {
    $Guess = Read-Host "Enter the magic number"
    If ($Guess -eq $MagicNumber) {
        "You guessed it: $Guess <--> $MagicNumber"
        $Continue = $false

    } Else {
        Write-Output -InputObject 'Try again.'
    }
}

Enter the magic number: 5
Try again.
Enter the magic number: 4
Try again.
Enter the magic number: 2
Try again.
Enter the magic number: 3
You guessed it: 3 <--> 3

And, that’s it. We’ve seen and learned everything from If to Switch and For to While. As it was stated previously, knowing which language construct to use should be left to your intuition, and a full understanding of a language’s conditional options is the only way that’s going to happen. Next week we’ll start discussing reusable code.

PSMonday #41: February 6, 2017

Topic: Do-Until

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 said I would say it this week too, so let’s get it out of the way: The Do-While and Do-Until loops ensure that the statement list is run at least once. Your code is going to execute at least one time using a Do construct. This is because the condition, that determines whether or not we loop again, isn’t evaluated until the statement list has run once. If you need to ensure your code executes at least one time, then the Do-While and Do-Until variations of the Do loop, may be the language construct you need.

Here’s the conceptual examples of the Do-Until.

Do {<statement list>} Until (<condition>)

Do {
    <statement list>

} Until (<condition>)

Our first below example should look somewhat familiar. We saw it first last week in the Do-While examples. We assign 1 to the $Number variable and then enter the Do loop. We output a string statement and then increment the $Number variable. Then, we check the condition. The condition indicates that we’ll continue to loop until $Number is less than 10. Well, 1 is always less than 10, so we exit the construct. This is a clear example that we always run the statement list at least once in a Do loop, before we check the condition.

$Number = 1

Do {
    Write-Output -InputObject "In the Do loop ($Number)."
    $Number++

} Until ($Number -lt 10)

In the Do loop (1).

Let’s modify this example. We’ll reinitialize the $Number variable back to 1 and start again. This time our condition states that we’ll continue to loop until $Number is greater than 10. As $Number is lower, you can likely guess that we’re going to run through this loop several times. Ten times, to be exact.

$Number = 1

Do {
    Write-Output -InputObject "In the Do loop ($Number)."
    $Number++

} Until ($Number -gt 10)

In the Do loop (1).
In the Do loop (2).
In the Do loop (3).
In the Do loop (4).
In the Do loop (5).
In the Do loop (6).
In the Do loop (7).
In the Do loop (8).
In the Do loop (9).
In the Do loop (10).

In closing out the Do variations, we’ll add a final example. Much like last week, we’ll transition from using numeric values to date times. In this example, we’ll add 10 seconds to the current time. Then, we’ll output a string value and sleep (pause) for a second. Eventually, the current time will be greater than the time when we began; therefore, the condition will be $true and we’ll exit the looping construct.

$Time = (Get-Date).AddSeconds(10)

Do {
    Write-Output -InputObject 'Waiting for time to pass...'
    Start-Sleep -Seconds 1

} Until ((Get-Date) -ge $Time)

Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...
Waiting for time to pass...

Next week is our final language construct — the While loop. By then, you’ll have a full and complete understanding of the various control structures we can use to respond to conditions in PowerShell. In case you hadn’t considered it, learning these concepts — even if it’s with PowerShell — is going to make learning other scripting, and even programming languages, easier to do.

PSMonday #40: January 30, 2017

Topic: Do-While

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.

Next up on our language construct journey, is part one of the Do loop: the Do-While. Once you’ve read this week’s, and next week’s PSMonday, be sure to read the full about help topic using the below command.

Get-Help -Name about_Do -ShowWindow

Here’s a couple conceptual examples of the Do-While loop. Of the two, you’ll see me use the second example, in order that my code is easier to read.

Do {<statement list>} While (<condition>)

Do {
    <statement list>

} While (<condition>)

For our first example, we’ll start looping based on the value of a variable. We begin by assigning the numeric value of 1 to the $Number variable. This assignment is done outside of the looping construct. Once set, we begin the loop. On the first pass, we indicate that we’re in the loop, as well as the current value of the $Number variable, we then increase the value of the $Number, and then we check if it is less than (-lt) the numeric value of 10. While this condition is true, we’ll continue to loop, incrementing the value in $Number each time, until the value in $Number variable is no longer less than 10.

$Number = 1

Do {
    Write-Output -InputObject "In the Do loop ($Number)."
    $Number++

} While ($Number -lt 10)

In the Do loop (1).
In the Do loop (2).
In the Do loop (3).
In the Do loop (4).
In the Do loop (5).
In the Do loop (6).
In the Do loop (7).
In the Do loop (8).
In the Do loop (9).

Instead of using a numeric value condition, this time, we’ll use a datetime object instead. Take a look at this next example, and then follow the further below description of each task within the example.

"Current Time: $((Get-Date).ToString())"

$Time = (Get-Date).AddSeconds(10)

"Future Time : $($Time.ToString())"

Do {
    Write-Output -InputObject '--> Waiting for time to pass.'
    (Get-Date).ToString()
    Start-Sleep -Seconds 1

} While ((Get-Date) -lt $Time)

"Current Time: $((Get-Date).ToString())"

Current Time: 1/29/2017 1:46:20 PM
Future Time : 1/29/2017 1:46:30 PM
--> Waiting for time to pass.
1/29/2017 1:46:20 PM
--> Waiting for time to pass.
1/29/2017 1:46:21 PM
--> Waiting for time to pass.
1/29/2017 1:46:22 PM
--> Waiting for time to pass.
1/29/2017 1:46:23 PM
--> Waiting for time to pass.
1/29/2017 1:46:24 PM
--> Waiting for time to pass.
1/29/2017 1:46:25 PM
--> Waiting for time to pass.
1/29/2017 1:46:26 PM
--> Waiting for time to pass.
1/29/2017 1:46:27 PM
--> Waiting for time to pass.
1/29/2017 1:46:28 PM
--> Waiting for time to pass.
1/29/2017 1:46:29 PM
Current Time: 1/29/2017 1:46:30 PM

We began the above example by echoing the current date and time. Then we created the $Time variable and made use of the AddSeconds() method to store the date and time 10 seconds into the future. So we know that time, we echoed it to the screen, as well.

Next, we entered the Do-While construct. Our statement list included writing a string to indicate that we we’re waiting for time to pass, writing the current date and time, and then sleeping for one second. Once these commands were completed, we checked the current date and time as a part of the Do-While’s condition. If the current time was still less than (-lt) ten seconds in the future from when we started ($Time), then we looped again. When that condition was eventually met — when the current time was no longer less than that future time — we exited the Do-While statement and echoed the current time.

We’ll cover the Do-Until next week — a language construct variation that you should probably already be able to figure out based on today’s PSMonday. I’ll say it today and next Monday, as well: The Do loops — both Do-While and Do-Until — ensure that we’ll go through the statement list at least one time. This is to say, that the condition is not evaluated until your code has been executed at least once.

PSMonday #39: January 23, 2017

Topic: For

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.

This week we’ll discuss the For loop. The first of the two below commands can be used to open the For help file. Inside the file you’ll find the command layout, as we’ve seen with the other language constructs, and cmdlets. The way I write the For language construct, has been included below.

Get-Help -Name about_For -ShowWindow

For (<init>; <condition>; <repeat>) {
    <statement list>
}

The For loop begins with the For keyword and a set of parenthesis. Inside the parenthesis is an initialization (listed as init above), followed by a semi-colon. Following the initialization, we include a condition. By now, you undoubtedly realize there will always be some sort of required condition within our language constructs. Foll­owing the second semi-colon, we have a way to increment our initialization variable, as an assurance we’ll loop through the For loop as many times as is indicated by our condition. This may make more sense, very shortly.

We’re only going to look at a single example for the For loop, but we’ll be sure to highlight all the key features, as well as fully walk through the example. Take a look at the below example, and then we’ll discuss it thoroughly.

For ($i = 1; $i -le 10; $i++) {
    "The value of the `$i variable is $i."
    Start-Sleep -Seconds 1
}

We begin our For statement by entering the For keyword, followed by a set of parenthesis. To initialize the For construct, we’ll set a variable, $i, to the numeric value of 1, as $i = 1. We could have used a different number, however, it would require some changes in the areas we’ll discuss next. We could’ve use a different variable, too, had we opted to do so.

Our condition, $i -le 10, indicates to continue to loop through this For construct, so long as $i is less than, or equal to, 10. The final value in the parenthesis, $i++, increments the value in $i by 1, for each loop iteration. It’s shorthand for $i = $i + 1. Inside the curly brackets is where we enter our statement(s); this is where we do our work. In our example, we’ll echo a string that includes the value of the $i variable, and then sleep, or pause, for one second. Here’s the results of our example.

The value of the $i variable is 1.
The value of the $i variable is 2.
The value of the $i variable is 3.
The value of the $i variable is 4.
The value of the $i variable is 5.
The value of the $i variable is 6.
The value of the $i variable is 7.
The value of the $i variable is 8.
The value of the $i variable is 9.
The value of the $i variable is 10.

There’s some confusion about when to use a foreach variation (foreach and ForEach-Object), and the For construct. I use For when I know how many times I need to loop, as this is a requirement. If you know this piece of information, then you might consider the For loop over the other two looping constructs we’ve discussed thus far. Think back to foreach and ForEach-Object: the number of times we were going to loop, was never a consideration before we began.

We’ll be back next Monday where we’ll cover another looping construct: the Do-While loop.