John
John

Reputation: 5532

DateTime parsing in PowerShell

I'm trying to write a PowerShell script that will generate a table of information with two columns: a name, and a date (which will be retrieved from a third-party application - in this case svn.exe).

The overall script works well, but I'm struggling to get the date that the server sends back into the DataTable. Here's a simplified version of my script:

# Set up a DataTable and initialise columns
$table = New-Object system.Data.DataTable “Test Table”
$col1 = New-Object system.Data.DataColumn Name,([string])
$col2 = New-Object system.Data.DataColumn DateFromServer,([DateTime])
$table.columns.add($col1)
$table.columns.add($col2)

# Create a new row and add the data
$row = $table.NewRow()
$row.Name = "Test"
$lastCommit = GetDateFromExternalApp
$lastCommit.GetType() # this returns DateTime as I would expect
$row.DateFromServer = $lastCommit # this throws up an error
$table.Rows.Add($row)

# Output the table
$table | Format-Table -AutoSize

# This function simulates what the actual function does
# (the real one goes to SVN and pulls down data, but it
# ends up with the same resulting date)
Function GetDateFromExternalApp
{   
    $externalAppDate = "2012-09-17T16:33:57.177516Z"

    return [DateTime]($externalAppDate)
}

The problem (noted in comments in the script above) is that while the function seems to be happily returning a DateTime instance, when I try to add this into the table row's DateFromServer column it's throwing up an error:

Exception setting "DateFromServer": "Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.IConvertible'.Couldn't store <18/09/2012 2:33:57 AM> in DateFromServer  Column.  Expected type is DateTime." At line:13 char:6
+ $row. <<<< DateFromServer = $lastCommit
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

However, the call to $lastCommit.GetType() shows that this is indeed a DateTime - and in fact if I add this line somewhere in the script:

$lastCommit

then I can see a nicely formatted datetime, suggesting that it is indeed parsing it and converting it correctly:

Date        : 18/09/2012 12:00:00 AM
Day         : 18
DayOfWeek   : Tuesday
DayOfYear   : 262
Hour        : 2
Kind        : Local
Millisecond : 177
Minute      : 33
Month       : 9
Second      : 57
Ticks       : 634835324371775160
TimeOfDay   : 02:33:57.1775160
Year        : 2012
DateTime    : Tuesday, 18 September 2012 2:33:57 AM

As such I'm quite puzzled as to why I'm getting the exception above. I realise that PowerShell does function return values differently than C#, but it looks to me like the function is returning the right type!

Upvotes: 2

Views: 9442

Answers (3)

Emperor XLII
Emperor XLII

Reputation: 13432

The issue here is due to a bug in PowerShell's type adaptation system (I would recommend reporting this to Microsoft if you have not already done so).

When you work with objects in PowerShell, you are actually working with a PSObject wrapper. Most calls (like GetType) are forwarded to the underlying object, though you can add additional members that do not interact with the object itself:

PS> Get-Date | Add-Member NoteProperty Yowza 'for example' -PassThru | Format-List y*
Yowza : for example
Year  : 2012


Normally this is not an issue, as PowerShell has extensive type coercion capabilities. In the case of DataRow however, there appears to be a bug with the DataRowAdapter type used to support the property access syntax. If you use the indexer directly, $row['DateFromServer'] = $lastCommit instead of $row.DateFromServer, the value is correctly unwrapped before it is sent to the .NET type.

You can also get around this by unwrapping the value yourself, either using a cast (as vonPryz already showed: [DateTime]$lastCommit), or by retrieving the BaseObject ($lastCommit.PSObject.BaseObject).

Upvotes: 4

Thomas Lee
Thomas Lee

Reputation: 1168

I suspect the reason is as stated in the error message:

"Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.IConvertible'...Expected type is DateTime." At line:13 char:6

What that is saying is that PowerShell tried to convert $lastCommit into a date and time but failed. The best way is, as vonPryz suggests - cast it to [datetime]

To see the issue more clearly, try looking at the both: $lastcommit.gettype() and $row.DateFromServer.gettype()

I don't have the GetDateFromExternalApp to check

Upvotes: 0

vonPryz
vonPryz

Reputation: 24071

I'd like to know the reason for this behaviour too.

Anyway, you can work around the problem by casting the date variable as DateTime or by explicitly declaring it to be one. Like so,

...
$row.DateFromServer = [DateTime]$lastCommit # Doesn't throw exception
...

Or

...
[DateTime]$lastCommit = GetDateFromExternalApp
$row.DateFromServer = $lastCommit # Doesn't throw exception
...

Upvotes: 3

Related Questions