Notice: The following post was originally published on another website. As the post is no longer accessible, it is being republished here on tommymaynard.com. The post was originally published on April 3, 2019.
I don’t know about you, but I have like five or six open tabs in my PowerShell editor at all times. Each was used to briefly prove something worked, or that it didn’t. Occasionally, these will become articles, but much more often, they just sit there for what feels like forever. I can’t seem to close some of these tabs, or even bring myself to save the sample code. If I can’t get to it now — or this week or month — what makes me think I’ll save it off and then get back to it? I probably won’t.
But today, I’m going to close a tab. This, right after I’ve written about it here. I’m not sure if it was supposed to become an article, but it’s going to regardless.
This tab’s single function is called Get-Date
. It probably sounds familiar, and it should. Here’s the idea. I want a user to be able to invoke my function and return the date, just like the Get-Date
cmdlet will do for them. Now, before we go any further, it’s important to understand that using Get-Date
— the function — will absolutely remove any ability to use Get-Date — the cmdlet — in any one of the other 500 different ways it can be used. That’s okay. Remember, this came out of a tab with an unknown future. This isn’t fully thought out or tested, production-ready code. It’s an artist’s sketchbook or a student’s rough draft. I didn’t even have to use Get-Date
. It could have been Get-ADUser
or Set-Content
. As you’ll see, the date portion of this function is inconsequential. It’s just what I chose when I needed something with which to test.
In addition to returning the standard Get-Date
result, I also wanted to build in a way to measure the length of time it takes for my command to complete. This was the whole experiment; this was the purpose behind the tab. To do this, requires a user include the Measure
switch parameter at the time of the function’s invocation. This measurement value isn’t displayed by default, but instead, it’s written to yes, a global variable, the user can inspect if they so desire. It still produces the Get-Date
cmdlet’s default output, but now there’s more output waiting in the wings if it’s wanted.
In the first example, our Get-Date
function executes as though we’ve run the default, Get-Date
cmdlet. We have in fact. Without the Measure parameter, all we do is run the Get-Date
cmdlet. When you look over the function’s code momentarily, you’ll see the fully-qualified, Get-Date
command. A fully-qualified PowerShell command includes the module name. This is a requirement because we’ve named our function the same name as the cmdlet. Command precedence order indicates that functions execute before cmdlets if both commands have the same name.
In the second example, we’ll include the Measure
switch parameter, and then return the value stored in the global, $Measurement
variable. What I wanted to work, did. I built in a way to run the command and measure its time to complete if I want that information. As it’s just Get-Date
, it doesn’t take long at all.
PS> Get-Date Monday, April 2, 2019 10:24:06 PM PS> PS> Get-Date -Measure Monday, April 2, 2019 10:24:07 PM PS> PS> $Measurement Days : 0 Hours : 0 Minutes : 0 Seconds : 0 Milliseconds : 1 Ticks : 10231 TotalDays : 1.18414351851852E-08 TotalHours : 2.84194444444444E-07 TotalMinutes : 1.70516666666667E-05 TotalSeconds : 0.0010231 TotalMilliseconds : 1.0231
Again, if this command is run with the Measure
parameter, the length of time it took to complete is written to a global variable named $Measurement
. As you’d expect, that variable will maintain its value until the variable name is reused for something else in the global scope, it’s overwritten by this function, it’s specifically removed, or the current PowerShell session has ended.
As can be seen in the below function, if the Measure
parameter isn’t included, we run the fully-qualified, built-in Get-Date
cmdlet. If it is included, we run Measure-Command
against the fully-qualified, built-in Get-Date
cmdlet. We use the OutVariable
common parameter twice. We use it once with the Get-Date
command, placing the current date and time into $CommandResult
, and once with Measure-Command
, placing the time to complete in our global $Measurement
variable. We display $CommandResults
and leave $Measurement
in memory in case, the user opts to view the measurement results.
Function Get-Date { [CmdletBinding()] Param ( [Parameter()] [switch]$Measure ) If ($Measure) { Measure-Command -Expression { Microsoft.PowerShell.Utility\Get-Date -OutVariable CommandResult } -OutVariable Global:Measurement | Out-Null $CommandResult } Else { Microsoft.PowerShell.Utility\Get-Date } # If-Else. } # End Function: Get-Date.
Before we wrap up, let’s look at a slightly modified version of the Get-Date
function. This has been named Get-DateWithPause
and hopefully, this will help indicate that the function is taking proper measurements. In this function, we’ve added two Start-Sleep
commands where we pause for two seconds. Beneath this function, we’ll rerun our previous examples and spot those expected differences.
Function Get-DateWithPause { [CmdletBinding()] Param ( [Parameter()] [switch]$Measure ) If ($Measure) { Measure-Command -Expression { Start-Sleep -Seconds 2 Microsoft.PowerShell.Utility\Get-Date -OutVariable CommandResult } -OutVariable Global:Measurement | Out-Null $CommandResult } Else { Start-Sleep -Seconds 2 Microsoft.PowerShell.Utility\Get-Date } # If-Else. } # End Function: Get-Date.
PS> Get-DateWithPause Monday, April 2, 2019 10:33:44 PM PS> PS> Get-DateWithPause -Measure Monday, April 2, 2019 10:33:50 PM PS> PS> $Measurement Days : 0 Hours : 0 Minutes : 0 Seconds : 2 Milliseconds : 2 Ticks : 20020567 TotalDays : 2.31719525462963E-05 TotalHours : 0.000556126861111111 TotalMinutes : 0.0333676116666667 TotalSeconds : 2.0020567
I’ve got a few more tabs with random pieces of PowerShell code. I’ll take a look through those, too. Just maybe I can close a few more tabs by giving their content a purpose here, even if they’re barely worthy. That said, I think this turned out alright. Someday maybe, I’ll get a measurement option builtin to all the functions I author.
Edit: In republishing this post here on tommymaynard.com, I decided to update the function a small bit. This version includes a second switch parameter (MeasureAndShow
) that will both measure the command’s duration and display it at the same time, too. With more time, I might have implemented this differently, but this works.
Function Get-Date { [CmdletBinding()] Param ( [Parameter()] [switch]$Measure, [Parameter()] [switch]$MeasureAndShow ) If ($Measure -or $MeasureAndShow) { Measure-Command -Expression { Microsoft.PowerShell.Utility\Get-Date -OutVariable CommandResult } -OutVariable Global:Measurement | Out-Null $CommandResult if ($MeasureAndShow) { $Global:Measurement } } Else { Microsoft.PowerShell.Utility\Get-Date } # If-Else. } # End Function: Get-Date.
[PS7.2.1][C:\] Get-Date Sunday, February 13, 2022 8:17:48 AM [PS7.2.1][C:\] Get-Date -Measure Sunday, February 13, 2022 8:17:52 AM [PS7.2.1][C:\] $Measurement Days : 0 Hours : 0 Minutes : 0 Seconds : 0 Milliseconds : 2 Ticks : 25986 TotalDays : 3.00763888888889E-08 TotalHours : 7.21833333333333E-07 TotalMinutes : 4.331E-05 TotalSeconds : 0.0025986 TotalMilliseconds : 2.5986 [PS7.2.1][C:\] Get-Date -MeasureAndShow Sunday, February 13, 2022 8:18:01 AM Ticks : 1781 Days : 0 Hours : 0 Milliseconds : 0 Minutes : 0 Seconds : 0 TotalDays : 2.06134259259259E-09 TotalHours : 4.94722222222222E-08 TotalMilliseconds : 0.1781 TotalMinutes : 2.96833333333333E-06 TotalSeconds : 0.0001781