1

I am currently working on a powershell script where I need to measure the duration between the start and the end of the script execution. After searching for a while I decided to use this approach to do so: https://stackoverflow.com/a/61432373/11425760 I have one Get-Date call to get the start time at the beginning of the script execution and another Get-Date call right before the script execution is about to end:

$StartTime = Get-Date

# Script logic...

$EndTime = Get-Date
$Duration = New-TimeSpan -Start $StartTime -End $EndTime

$Day = switch ($Duration.Days)
{
    0 { $null; break }
    1 { "{0} day," -f $Duration.Days; break }
    Default {"{0} days," -f $Duration.Days}
}

$Hour = switch ($Duration.Hours)
{
    #0 { $null; break }
    1 { "{0} hour," -f $Duration.Hours; break }
    Default { "{0} hours," -f $Duration.Hours }
}

$Minute = switch ($Duration.Minutes)
{
    #0 { $null; break }
    1 { "{0} minute," -f $Duration.Minutes; break }
    Default { "{0} minutes," -f $Duration.Minutes }
}

$Second = switch ($Duration.Seconds)
{
    #0 { $null; break }
    1 { "{0} second" -f $Duration.Seconds; break }
    Default { "{0} seconds" -f $Duration.Seconds }
}

Write-Host "The script execution took: $Day $Hour $Minute $Second"
Write-Host "Script execution ended"

While this seemed to work fine when I implemented it, I suddenly started running into a problem where for some reason I get a "ParameterBindingException" when calling New-TimeSpan, telling me that the value for the "End" argument (e.g. "08/19/2020 08:54:51") cannot be converted into the type System.DateTime. When I then look at the start and end time I provided, they are both printed in different formats despite them both coming from a Get-Date call. For example, the end time gets printed as

"08/19/2020 08:54:51"

and the start time as

"Mittwoch, 19. August 2020 08:54:08"

(german format). This only seems to happen when I run the script for the first time because as soon as I run it again, the error no longer occurs. What I don't understand is: After checking both the start and the end time, the start time was (as expected) a DateTime object but the end time was just a string, despite both values coming from a Get-Date call. Why does this even happen to begin with and how can I avoid running into this problem (or similar problems)?

Chris
  • 1,417
  • 4
  • 21
  • 53
  • Did you try to create a culture object with a defined format and use it all along? Like this: `$en = New-Object system.globalization.cultureinfo(“en-US”)` So you can run this to get the date from this culture `Get-Date -Format ($en.DateTimeFormat.FullDateTimePattern)` – Kluk Aug 19 '20 at 07:45
  • @Kluk No, I didn't but I am also not changing anything regarding the culture during the script execution, so it makes no sense to me why I suddenly get something different when calling Get-Date. I also just noticed that when the problem occurs, the start time is a DateTime object while the end time is actually just a string, despite them both coming from a Get-Date call. – Chris Aug 19 '20 at 07:49
  • and are you sure that these Get-Date are executed on the same system? Not on a remote server or into an `Invoke-Command` or anything like this? If you run `Get-Culture`, do you get only one format? Maybe you can show us the bit of code which causes this issue. – Kluk Aug 19 '20 at 07:54
  • @Kluk Yes, I am not doing anything like that in my script and I executed it locally on my system. When I run `Get-Culture` I only get the culture "de-DE". I will add the code in my question. – Chris Aug 19 '20 at 07:56
  • It works perfectly on my side. But maybe you can try to cast your variables as datetime: `[datetime]$StartTime = Get-Date` – Kluk Aug 19 '20 at 08:08
  • 1
    The above works perfectly for me, Could you please also confirm if the above is the complete entirety of your script?, I assume you have some additional logic where `# Script logic...` is? Is it possible you are using very similarly named variables? (possibly one is being converted to a string type using `.tostring()` method etc?) – CraftyB Aug 19 '20 at 08:14
  • @CraftyB Yes, I noticed that I already use the $EndTime variable for something else in the script, but shouldn't this make no difference considering that I just assign the result of the Get-Date call to it afterwards? Or does it matter for some reason what value was assigned to the variable before that? I just renamed the $StartTime and $EndTime variables to something that isn't used anywhere else and now it seems to work fine. – Chris Aug 19 '20 at 08:21
  • you can force the format in the start and in the end... using `ToString("dd/MM/yyyy HH:mm)` for example, then convert it back... this way the format will always be the same – Avshalom Aug 19 '20 at 08:29
  • You are correct with regards to how variables do get stored and the reassigning it should wipe over the value regardless of their content or type. However I have just tested something, are you casting the initial value of `$EndTime` e.g. `[string]$EndTime = "BLAH"`, as when testing this seems to make the variable persist as a string type even when using `get-date` to assign the value I am getting the same result as you that the format of the value is a string. – CraftyB Aug 19 '20 at 08:31
  • 1
    I don't think you can reassign a different type into a variable like this. It's probably better to clear it or delete it before. You can use `Clear-Variable` to remove the data within the variable or `Remove-Variable` which will remove the data and the variable itself. Example: `Remove-Variable -Name 'EndTime'` (no $ symbol) – Kluk Aug 19 '20 at 09:35
  • But regarding this: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_variables?view=powershell-7 you shouldn't have to do anything before changing the type. But I already had this case into functions and I had to clear it before re-using it. Is this part of code written into a function? – Kluk Aug 19 '20 at 09:46
  • @Kluk No, it isn't written inside a function. – Chris Aug 19 '20 at 09:57
  • A simple solution is when you are re declaring the variable declare them like this: `[DateTime]$StartTime = Get-Date` & `[DateTime]$EndTime = Get-Date` this will force them to a DateTime data type and should work as you expect. – CraftyB Aug 19 '20 at 10:20
  • @CraftyB I already advised this and I'm still waiting for a feedback. I also think it should work. – Kluk Aug 19 '20 at 11:37
  • As I said, it already works after renaming the variables so I cannot test if the suggestion to cast the variables as datetime helps or not. – Chris Aug 19 '20 at 11:43

1 Answers1

1

I recommend ditching the approach and use the StopWatch instead.

Just create and start a stopwatch in the begining of the exection and at the end stop it and you have the object with the time to look at.

$stopwatch =  [system.diagnostics.stopwatch]::StartNew()

$stopwatch.Stop()

$stopwatch

This will output:

IsRunning Elapsed ElapsedMilliseconds ElapsedTicks


False 00:00:00.0009000                   0         9000

Or you can get this:

$stopwatch.Elapsed





Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 1
Ticks             : 16324
TotalDays         : 1,88935185185185E-08
TotalHours        : 4,53444444444444E-07
TotalMinutes      : 2,72066666666667E-05
TotalSeconds      : 0,0016324
TotalMilliseconds : 1,6324

But you can format it in any way you want too.

Daniel Björk
  • 2,475
  • 1
  • 19
  • 26