1

This is supposed to be a query for a virtual machine in Amazon EC2, it lists the instances by it's instanceID and LaunchTime (when it was turned up) - and I want to calculate another column that is it's LaunchTime - Current Date/Time to get a "uptime" statistic called HoursSinceBoot.

#get instances
$instances = foreach($i in (get-ec2instance)) {$i.RunningInstance | Select-Object InstanceId,LaunchTime}
$instances | Add-Member -type NoteProperty -name HoursSinceBoot -value (Foreach-object -inputobject     $instances {New-TimeSpan -End (get-date) -Start $_.LaunchTime} | select -expandproperty hours)
$instances

This is the error I get the error below, which seems to indicate Launchtime is not a datetime type, which sure enough when I run a get-member it sure as crap is. Now I know if I run $[0].LaunchTime this code will work, but for some reason using simply the $ variable it all goes to hell. I've tried a few date time conversion techniques like [datetime] but they have similar error "can't convert to type datetime" consequences.

New-TimeSpan : Cannot convert 'System.Object[]' to the type 'System.DateTime' required by parameter 'Start'. Specified method is not supported.
At C:\xxx\powershell\aws-watchdog.ps1:3 char:149
+ ... t-date) -Start $_.LaunchTime} | select -expandproperty hours)
+                    ~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [New-TimeSpan], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.NewTimeSpanCommand
Anthony Neace
  • 25,013
  • 7
  • 114
  • 129
Brink
  • 67
  • 1
  • 5
  • Do not trust get-member unless you use the form "get-member -inputObject $objectName". If you have a collection of DateTimes and pipe this to get-member (ie $colDateTimes | get-member), it will report DateTimes. Fact that error mentions 'System.Object[]' suggests you are dealing with an array/collection here. – andyb Jul 25 '14 at 03:32
  • 2
    When calculating differences between two datetimes I generally use the form "($EndTime - $StartTime).TotalHours", which is simpler then declaring new TimeSpan objects. – andyb Jul 25 '14 at 03:34

1 Answers1

1

You may be better off calculating the new HoursSinceBoot property as part of your select.

Here's an example:

PS C:\> $launchData = Get-EC2Instance | `
                      % { $_.RunningInstance } | `
                      Select-Object InstanceId, LaunchTime, @{Name='HoursSinceBoot'; Expression={ ((Get-Date)-$_.LaunchTime).TotalHours } }
PS C:\> $launchData | Format-Table -AutoSize

InstanceId LaunchTime              HoursSinceBoot
---------- ----------              --------------
i-abcd1234 6/11/2014 11:14:39 AM 1061.46170712353
i-efgh5678 7/11/2014 11:02:24 AM 341.665873790194

What's happening here:

  • Get-EC2Instance is piped into Foreach-Object (aliased by the percent symbol), which pulls the RunningInstance property off of each EC2 reservation object.
  • We pipe each RunningInstance to Select-Object to select InstanceId and LaunchTime, and then generate a new property called HoursSinceBoot.
  • There are parenthesis inside the expression as a matter of order-of-operations. It allows us to evaluate the current date before subtracting from LaunchTime, and the subtracted value before attempting to extract the TotalHours property from the generated DateTime.
  • I incorporated @andyb's suggestion for calculating DateTime difference.

Also, for trivia's sake... you can double-check that value on the AWS console by checking under the Description tab of an EC2 instance:

An image of a snippet of the AWS console, describing the launch time of one of my EC2 instances.

Anthony Neace
  • 25,013
  • 7
  • 114
  • 129