Converting WMI Date and Time

I’m currently trying to convert a date and time value returned from a WMI query to something more readable. I can accomplish this easily when one object is returned using [System.Management.ManagementDateTimeconverter]::ToDateTime. For example if my query returns just 20130807000004.000000+000 I can convert that. However, my current query returns multiple dates in that format. I want to convert them to a more readable format. I’m having trouble with this syntax. I’m thinking that I need a Foreach loop, but am stuck on that formatting as well. Any suggestions are appreciated.

You’ll have to loop them, but all WMI objects in PowerShell have a helper method, so you don’t necessarily need to use that class. Assuming $var contains a property MyDate:

foreach ($thing in $var) { $var.ConvertToDateTime($var.mydate) }

In v3+, you can also switch to using CIM - those tend to return a normal DateTime rather than the underlying WMI weirdo date.

It would help to see your starting code. Also, are you just trying to output the dates and times to the screen, or do you want to save the converted values in an object for later use?

Here’s a simple example that just writes to the screen, which might help get you started:

foreach ($object in $someCollection)
{
    $dateTime = [System.Management.ManagementDateTimeConverter]::ToDateTime($object.someWmiDateStringProperty)
    Write-Host $dateTime
}

@Don, I have v3, but the endpoints that I’m running this script against will most likely have v2. Can I still use CIM?

When I try running your example, it complains that it does not have a ConvertToDateTime method.

@Dave, Your code is close to what I was already trying. When I run your code I get an error saying Cannot find an overload for “ToDateTime” and the argument count: “0”.

I cannot give you the complete code because it’s a custom WMI class in the cimv2 namespace. I can give you an example, and the output I’m looking at:

(gwmi namespacegoeshere -ComputerName ‘test’).endtime

Returns:

20130821000106.000000+000
20130821000105.000000+000
20130821000103.000000+000
20130821000011.000000+000
20130821000008.000000+000
20130821000006.000000+000
20130821000004.000000+000
20130820000105.000000+000
20130820000104.000000+000
20130820000103.000000+000
20130820000015.000000+000

Again, if this just returned one entry I would be done already :slight_smile:

If I put my query into a variable and pipe the variable to get-member I have a TypeName: System.String. ToDateTime is a method that is available.

If the end points are v2 you can still use the CIM cmdlets but you have to create a DCOM based CIMsession to the endpoint

if you are staying with wmi cmdlets looks like your code will be something like

(gwmi namespacegoeshere -ComputerName ‘test’).endtime | foreach { [System.Management.ManagementDateTimeConverter]::ToDateTime($_) }

depends what else your class is returning as to whether you need to do anything else

Ah. Custom class. You didn’t mention that, and it’s important. The ConvertToDateTime method is dynamically added by PowerShell, but it wouldn’t know to do that to your custom class. So, yeah, in that case the class method would be the next choice. You technically ought not put custom classes into root/CIMV2 - the design intent is to create your own namespace. That’s a nit, though.

You can use the CIM commands against the WMI service directly. You have to create a CIMSession using DCOM as the protocol, and then target the CIM commands at that session. I don’t know if it’ll do any better of a job in terms of date/time that way, though.

Interestingly, you could still use ConvertToDateTime, I bet. Say $x has your custom class in it, with $x.endtime being your date/time property.

$os = Get-WmiObject Win32_OperatingSystem
foreach ($x in $collection) {
$os.ConvertToDateTime($x.endtime)
}

Might well work. ConvertToDateTime is added to all the inbuilt WMI classes. It’s just a shortcut to the .NET method you’re already using, though - it isn’t special.

[quote=9944]If the end points are v2 you can still use the CIM cmdlets but you have to create a DCOM based CIMsession to the endpoint
if you are staying with wmi cmdlets looks like your code will be something like
(gwmi namespacegoeshere -ComputerName ‘test’).endtime | foreach { [System.Management.ManagementDateTimeConverter]::ToDateTime($_) }
depends what else your class is returning as to whether you need to do anything else
[/quote]

This worked perfectly. I was doing exactly that but I was using $.endtime. I see you used just $ and it worked like a champ. Thank you.

[quote=9946]Ah. Custom class. You didn’t mention that, and it’s important. The ConvertToDateTime method is dynamically added by PowerShell, but it wouldn’t know to do that to your custom class. So, yeah, in that case the class method would be the next choice. You technically ought not put custom classes into root/CIMV2 – the design intent is to create your own namespace. That’s a nit, though.
You can use the CIM commands against the WMI service directly. You have to create a CIMSession using DCOM as the protocol, and then target the CIM commands at that session. I don’t know if it’ll do any better of a job in terms of date/time that way, though.
Interestingly, you could still use ConvertToDateTime, I bet. Say $x has your custom class in it, with $x.endtime being your date/time property.
$os = Get-WmiObject Win32_OperatingSystem<br> foreach ($x in $collection) {<br> $os.ConvertToDateTime($x.endtime)<br> }
Might well work. ConvertToDateTime is added to all the inbuilt WMI classes. It’s just a shortcut to the .NET method you’re already using, though – it isn’t special.
[/quote]

I seem live in a world of custom and never out of the box. I tend to forget that when asking for assistance.

I tried your code Don, even though I got it working with what Richard gave me. I get the following error:
Exception calling “ConvertToDateTime” with “1” argument(s): “Exception calling “ToDateTime” with “1” argument(s): “Specified argument was out of the range of valid values.Parameter name: dmtfDate””

So I modifed the code a little to this:

$os = gwmi namespacegoeshere -ComputerName ‘test’
foreach ($x in $os) {
$os.ConvertToDateTime($x.endtime)
}

When I ran it that way, I ended up in a never ending loop of darkness and despair. I will say though, it did convert the date. It just never ends and keeps running.

By the sound of it, you were using code like this:

(gwmi namespacegoeshere -ComputerName ‘test’).endtime |
ForEach-Object {
    [System.Management.ManagementDateTimeConverter]::ToDateTime($_.endtime)
}

You’re essentially trying to read the value of $object.endtime.endtime , in that code (which will always be null). One or the other of the instances of “.endtime” in the code would have to go; in this case, it doesn’t matter which one. In general, though, I would recommend keeping the one inside the loop (so you still have access to any other properties of the objects returned by Get-WmiObject):

gwmi namespacegoeshere -ComputerName ‘test’ |
ForEach-Object {
    [System.Management.ManagementDateTimeConverter]::ToDateTime($_.endtime)
}