Some time back I attended a presentation where the presenter’s PowerShell console displayed their last command’s execution time in the prompt. At the time of thought it was a bit of a geeky novelty thing. Though recently I’ve had a slight change of opinion. It’s become a great way to easily see the efficiency of my code.
To make a pretty crude quote. There are many ways to skin a cat. PowerShell is extremely flexible in that it allows you to perform the same task many different ways. But not all ways are equal right?!? In the two examples below a perform a fairly basic count from 1 to 10 million.
$x = 0
ForEach ( $i in 1..10000000 ) {
$x = $x + 1
}
$x
In the above example the code runs in “around” 9834 milliseconds (9.8 seconds).
class MyClass
{
static[int] CountUp()
{
$x = 0
ForEach ( $i in 1..10000000 ) {
$x = $x + 1
}
return $x
}
}
[MyClass]::CountUp()
In this second example the code runs in 552 milliseconds (~0.5 seconds). A huge difference.
Being able to quickly and easily see execution time in the prompt can be quite helpful in determining if you’re coding as efficiently as you could be. It’s led me to trying things multiple ways before I settle. Now the actual code to display execution time is also quite easy to add into your PowerShell startup profile or to just run in your current session.
PowerShell comes with a built in prompt function which you can override with your own. In the below example I have created a new prompt function which I can execute by typing Prompt after running the code in my current session.
function Prompt {
$executionTime = ((Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime).Totalmilliseconds
$time = [math]::Round($executionTime,2)
$promptString = ("$time ms | " + $(Get-Location) + ">")
Write-Host $promptString -NoNewline -ForegroundColor cyan
return " "
}
The execution time of commands is retrieved from the StartExecutionTime and EndExecutionTime properties of Get-History. I get the time of the previous command, round to two decimal places, and write that to the prompt.
You can also take the function and place it in your PowerShell default startup profile file which will execute each time you open a new PowerShell session. It does require a slight modification to the above function which I’ll discuss later below. I’ve written a few posts on how to find and modify your default profile. But if your using Windows PowerShell you can find or add it in C:\Users\{Username}\Documents\WindowsPowerShell\profile.ps1. If your using PowerShell Core you can find or add it in C:\Users\{Username}\Documents\PowerShell\profile.ps1.
function Prompt {
if ((Get-History).count -ge 1) {
$executionTime = ((Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime).Totalmilliseconds
$time = [math]::Round($executionTime,2)
$promptString = ("$time ms | " + $(Get-Location) + ">")
Write-Host $promptString -NoNewline -ForegroundColor cyan
return " "
} else {
$promptString = ("0 ms | " + $(Get-Location) + ">")
Write-Host $promptString -NoNewline -ForegroundColor cyan
return " "
}
}
In the code above I’ve rapped it in an If / Else statement block. The logic here is that we use Get-History to get the execution time, but when a PowerShell session is first run there is nothing in Get-History, which will cause the function to fail and not run correctly generating a default vanilla prompt. Not ideal. So we create an else block and generate our own default prompt when no history of previous commands exist when initially opening a new PowerShell session.
So while many of you may also just find this a geeky novelty thing. It can also be a good reminder for you to try and keep your code and scripting as efficient as possible. Hey and at the very least you can impress your friends with a cool PowerShell prompt.
Hello. I have a (unrelated?) question: about the two codes to count from 1 to 10 million, why the first one took more time to run then the second one?
Thanks for sharing and I don’t mean this to be snarky… But if you’re concerned about efficiency, probably not the best to call Get-History 3 times to generate a prompt everytime. š
No one’s perfect š
But on a serious note. I’m open to better ways to do it. This was just the most obvious way.
Not that Get-History takes a lot of processing power, but only need to execute it once.
if ($H=Get-History) {
$executionTime = ($H[-1].EndExecutionTime - $H[-1].StartExecutionTime).Totalmilliseconds
Note that (at least on PowerShell Core) Get-History already includes a Duration property, so no need to calculate it yourself:
(Get-History)[-1].Duration