Tag Archives: Measure-Command

The Unzip Time Difference

As part of an upcoming deployment, I’ve been getting intimate with AWS OpsWorks and Chef. What I mean by Chef is, using the PowerShell resource in Chef. I was recently looking for a way to save some time on a deployment, when I considered removing the unzipping of files downloaded from S3. I wanted to know if there would be a time savings in getting the files to the EC2 Instance in their decompressed format.

This brought me over to my console to compare the newer Expand-Archive cmdlet and .NET. I’ve always considered that dropping down to .NET is a time savings.

In my Chef recipe I’m using .NET for decompression, as I’m deploying to Windows Server 2012 R2 and it includes PowerShell 4.0 by default. The Compress-Archive and Expand-Archive cmdlets were introduced in PowerShell 5.0. This isn’t to say I couldn’t get PowerShell 5.0 in place, but I needed to know if it would even be necessary.

I had a little testing to do. The below command measured the time it took to expand a 133MB zip file using .NET.

Measure-Command -Expression {
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    [System.IO.Compression.ZipFile]::ExtractToDirectory('C:\Users\tommymaynard\Desktop\HCM-920-UPD-018-WIN_1of10.zip','C:\Users\tommymaynard\Desktop\unzip\')
}

When the command was run five separate times, it resulted in following times: 9 seconds 393 milliseconds, 9 seconds 117 milliseconds, 9 seconds 455 milliseconds, 8 seconds 489 milliseconds, and 10 seconds 338 milliseconds. I wasn’t loosing any time by unzipping this file.

The below command does the same thing as the one above; however, it uses the Expand-Archive cmdlet introduced in PowerShell 5.0.

Measure-Command -Expression {
    Expand-Archive -Path 'C:\Users\tommymaynard\Desktop\HCM-920-UPD-018-WIN_1of10.zip' -OutputPath 'C:\Users\tommymaynard\Desktop\unzip\'
}

I executed the above command five times, too. The results were 2 minutes 11 seconds, 2 minutes 9 seconds, 2 minutes 10 seconds, 2 minutes 13 seconds, and 2 minutes 11 seconds.

This is a huge difference in time. Now, I do want to mention that I tested this on Windows 8.1 with PowerShell 5.1 (it’s in preview). The results may be better on different versions of Windows and with different versions of PowerShell. Let me know if you see different results with different configurations, and maybe I’ll do the same. The point is this, however: If you have a reason to speed up your project, you might consider .NET over a PowerShell cmdlet, or function. It seems I’m glad I did. Be sure you test different ways, to do the same thing.

Quick Learn – Proving PowerShell’s Usefulness to Newbies, Part I

Months ago, I started writing a list of ways to potentially impress PowerShell newbies for a presentation (I’ve yet to ever give). Since I’m not sure if I’ll be up in front of a crowd of PSNewbies any time soon, I figured I would share them here. Consider these when you need to impress the PowerShell non-believers.

Part I
The power in PowerShell has been said to be a number of different things, by a number of different people. In today’s topic, the power is speed and accuracy. We’re going to automate the creation of 10,000 directories (a.k.a. folders). That’s no small task if you’re doing it manually.

Beginning in the example below, we’ll start by creating a single directory to hold the other 10,000 directories, by running a New-Item command. Once that’s finished, which is practically instantaneous, we’ll run second command to create the 10,000 new folders. We’ll do this by using a range operator (..) and the numbers 1 and 10000, piping each of those numbers and the ones in between, to that second New-Item command.

Notice the $_ variable, as this has the tendency to cause some confusion. This variable holds the value of the current object that’s entered, or crossed, the pipeline — you pick your visual. In this case, it represents the current number from within our range of numbers. The first time this command runs, $_ will be set to 1, the second time this runs it will be set to 2, and the last time it runs, it will be set to 10000. I should note, that in PowerShell 3.0, the $PSItem variable was introduced. It can be used in place of $_ in version 3.0 and above.

PS> New-Item -Path C:\Testing -ItemType Directory

    Directory: C:\

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          1/6/2016   9:52 PM            Testing

PS> 1..10000 | ForEach-Object {New-Item -Path "C:\Testing\$_" -ItemType Directory}

    Directory: C:\Testing

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          1/6/2016   9:52 PM            1
d----          1/6/2016   9:52 PM            2
d----          1/6/2016   9:52 PM            3
d----          1/6/2016   9:52 PM            4
d----          1/6/2016   9:52 PM            5
d----          1/6/2016   9:52 PM            6
d----          1/6/2016   9:52 PM            7
d----          1/6/2016   9:52 PM            8
d----          1/6/2016   9:52 PM            9
d----          1/6/2016   9:52 PM            10
...

I haven’t included all 10,000 results, for good reason, but as you can see, the moment the command was entered into the PowerShell host, it began to create the new folders. This would be the time at which you retie your shoes. The example further below indicates the command takes about 10 seconds to complete. Depending on your sneakers, if you’re wearing those, you might actually take longer. If you don’t have laces, take a drink of something, or simply sit there in amazement at all the work you’re not really doing. It might actually be too fast, once you’ve realized how much time you just freed up.

A little note about Measure-Command used below: Typically this cmdlet will internally measure things and not really do much that you can actually see. In this case, it’s actually going to create the folders as part of the measurement. To me, it makes sense that it wouldn’t be able to measure this unless it really creates the folders. On that note, if you ran the command above, you’ll want to delete the existing folders, if you want to measure how long it takes to create the folders. The New-Item cmdlet can’t create folders that already exist. To remove the directories, run:  Remove-Item -Path ‘C:\Testing\*’ from your PowerShell console.

PS> Measure-Command -Expression {1..10000 | ForEach-Object {New-Item -Path "C:\Testing\$_" -ItemType Directory}}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 10
Milliseconds      : 293
Ticks             : 102939103
TotalDays         : 0.000119142480324074
TotalHours        : 0.00285941952777778
TotalMinutes      : 0.171565171666667
TotalSeconds      : 10.2939103
TotalMilliseconds : 10293.9103

PS> Remove-Item -Path C:\Testing\*

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 9
Milliseconds      : 793
Ticks             : 97934962
TotalDays         : 0.000113350650462963
TotalHours        : 0.00272041561111111
TotalMinutes      : 0.163224936666667
TotalSeconds      : 9.7934962
TotalMilliseconds : 9793.4962

In the second command above, we actually measured the time it took to remove the directories we created — you saw that command a moment ago. It came in at a faster time than it took to create them, although this won’t always be the case. It’s still quite quick for either operation.

This is a great example of the power in PowerShell, but before I wrap up, let’s see how much time I just saved. Let’s assume it takes me 4 seconds to manually create a folder. To create 10,000 folders, I would need a free 40,000 seconds. To put that into hours, I would need over 11 of them to do this task by hand. We only get one person’s salary, but we should probably get a few.

PS> $SecondsToCreateFolder = 4
PS> $NumberOfFolderToCreate = 10000
PS> $NumberOfFolderToCreate * $SecondsToCreateFolder
40000
PS> $SecondsInMinutes = $MinutesInHours = 60
PS> $SecondsInMinutes
60
PS> $MinutesInHours
60
PS> ($NumberOfFolderToCreate * $SecondsToCreateFolder) / $SecondsInMinutes / $MinutesInHours
11.1111111111111

Thanks for reading this post.

Script Sharing – An Improved Measure-Command: Multiple Commands, Multiple Repetitions, Calculated Averages, and Pauses Between Runs

Download the Measure-TMCommand function here: https://gallery.technet.microsoft.com/Measure-Command-with-52158178

In Windows PowerShell, there are often several ways to complete the same task. With that in mind, it makes sense that we might want to determine how long commands and scripts take to complete. Until now, Measure-Command has been the cmdlet we’ve used.

While Measure-Command has been helpful, I’ve often thought it should include some additional functionality. Therefore, I’ve written an advanced function, Measure-TMCommand, that adds all the benefits listed below:

– Continually measure the execution time of a single command and/or script, up to a user-defined number of repetitions.

– Continually measure the execution time of multiple commands and/or scripts, up to a user-defined number of repetitions.

– Calculate the average time a command(s), and/or a script(s)  takes to execute.

– Display limited hardware information about the computer where the command and/or script is being measured.

– Includes an option to display the output of the command and/or script, as well as the measurement results.

Updated 4/15/2015 (v1.2.1): Added a parameter -TimeInBetweenSeconds with a parameter alias of -Pause. This will pause the function between executions, allowing the ability to test at different times between a set time. For instance, let’s say you want to measure a command every 1/2 hour for six hours: 12 repetitions with 30 minute pauses. You would then run the command with the -Repetitions parameter with a value of 12 and the -TimeInBetweenSeconds (or -Pause) with a value of 1800 (as in 1800 seconds, or 30 minutes).

Here’s the function in action:

Measure-TMCommand1.2.1

In the example, above, we can easily determine that using the -Name parameter of the Get-Service cmdlet, is faster then piping the entire result set to the Where-Object cmdlet, and then filtering on the name. Notice that not all properties were returned — only the ones in which I was interested.

With the addition of the -TimeBetweenInSeconds, or -Pause, parameter I have considered that this function might be better served to also have an -AsJob parameter. I’ll look into it, but no promises. Thanks, and enjoy.

Download the Measure-TMCommand function here: https://gallery.technet.microsoft.com/Measure-Command-with-52158178

Quick Learn – Clear-Host, Without Clearing the Host

After you read this, read part 2 (and download the TMModule)

I use the Clear-Host cmdlet alias, cls, throughout the day to clear out whatever typing I have inside my Windows PowerShell console. It does its job well, but recently I’ve wanted it to work differently. I wanted it to appear that the console host has been cleared, but still allow me to scroll back up to see what was on the screen before it was cleared. I started playing around with the console class, [Console]. While not necessary, this can also be written using the namespace, System, such as [System.Console]. I like the idea of being as complete as possible and so you’ll see me use the namespace even though it’s not necessary.

Before I could write something reusable, such as a function, I had to figure out if what I wanted to accomplish, was even possible. I knew I was working with [System.Console] and so I piped that to Get-Member, but it returned the methods and properties of System.RuntimeType, seen below.

PS C:\> [System.Console] | Get-Member

    TypeName: System.RuntimeType

I struggled for a moment until I remembered an article I had read on using static classes. I found that page again, http://technet.microsoft.com/en-us/library/dd347632.aspx, and was quickly reminded that using the -Static parameter of the Get-Member cmdlet would get me the correct results.

PS C:\> [System.Console] | Get-Member -Static

    TypeName: System.Console

Running the command above produces the TypeName as shown, but it also produces all the methods and properties. I started looking over the properties and a couple about the cursor quickly caught my eye, especially the CursorTop property. After the Get-Member command from above, and based on the results of returning the CursorTop property, my cursor was positioned at line 59 inside my console, as can been seen in the example below on line 2. I cleared the screen, and beginning on line 4 below, I reran the command three more times. Each time, it gave me the location where the cursor was last positioned.

PS C:\> [System.Console]::CursorTop
59
PS C:\> cls
PS C:\> [System.Console]::CursorTop
1
PS C:\> [System.Console]::CursorTop
3
PS C:\> [System.Console]::CursorTop
5
PS C:\>

I decided I would assign the value, 0, to the CursorTop property and suddenly I was writing over the text on the top line. Take a close look at line 1 below.

PS C:\> blahblahConsole]::CursorTop
59
PS C:\> cls
PS C:\> [System.Console]::CursorTop
1
PS C:\> [System.Console]::CursorTop
3
PS C:\> [System.Console]::CursorTop
5
PS C:\> [System.Console]::CursorTop = 0

I could move my cursor, great, but this wasn’t exactly what I wanted. What I wanted was to push that scroll bar down so that anything that was already on the screen was pushed off the top of my console, and all that was left was my PowerShell prompt. I still believed there was a way to do this and so I spent a little more time looking over the properties. I found four that began with Window – WindowHeight, WindowLeft, WindowTop, and WindowWidth – and began to experiment with them. I didn’t suspect I’d be doing anything with the height and width but I thought I would check out their values anyway – 50 and 120, respectively.

PS C:\> [System.Console]::WindowHeight
50
PS C:\> [System.Console]::WindowWidth
120
PS C:\>

WindowLeft didn’t seem to be that important, because no matter how much was typed before I entered [System.Console]::WindowLeft, the property value was still set to 0. Then I entered in [System.Console]::WindowTop and it was also 0 every time. Then it dawned on me, what if I changed its value like I did with CursorTop. I tried it and my scroll bar started jumping all over. I’m getting close!

PS C:\> [System.Console]::WindowTop = 10
PS C:\> [System.Console]::WindowTop = 200
PS C:\> [System.Console]::WindowTop = 2000
PS C:\> [System.Console]::WindowTop = 0

We know the CursorTop value changes, so what would happen if we set the value of WindowTop to CursorTop? I tried it, and it worked!

PS C:\> [System.Console]::WindowTop = [System.Console]::CursorTop
PS C:\>

I thought I was done when I took another moment and scanned over the methods. I found one called SetWindowPosition. Instead of simply assigning a new value to the property WindowTop, I decided I would use the method to do the work for me. I eventually ran both of these options through the Measure-Command cmdlet and determined that there was no gain in speed by using one option over the other.

So, once I knew what to do, I opened my profile ($PROFILE) and created an empty function. For whatever reason, I called it clx thinking that this would be a good option for me. Turns out that while clx has little meaning, I was able to quickly remember it and start using it right away. Now, every time I want it to appear that I’ve cleared my host, but didn’t really, I type clx and press Enter.

Function clx {
    [System.Console]::SetWindowPosition(0,[System.Console]::CursorTop)
}

I added one additional feature to this function as is seen in the example below. This option allowed me to run the clx function and leave the last n number of rows on the screen. Try it out by ensuring your have some output in your console and then entering clx 2. This will “clear” the console screen but still allow you to view the last two rows without scrolling back up. Try it and it may make more sense.

Function clx($SaveRows) {
    If ($SaveRows) {
        [System.Console]::SetWindowPosition(0,[System.Console]::CursorTop-($SaveRows+1))
    } Else {
        [System.Console]::SetWindowPosition(0,[System.Console]::CursorTop)
   }
}

Here’s a video of the function in action. The first thing we do is return 5 processes and then 5 services. Then we use cls and notice that we cannot scroll back up to see what was cleared. This is the typical behavior. When we add the processes and services back, and then use the clx function, we can see that we have the option to scroll back up and see what was on the screen, before we “cleared” it.