7

Querying a WMi object on the

$colItems = Get-WmiObject Win32_NetworkLoginProfile -Namespace "root\CIMV2" 
                  | Where-Object {$_.name -match "Name"} | Select-Object name,PasswordAge

according to MSDN

PasswordAge

Data type: datetime
Access type: Read-only
Length of time a password has been in effect. This value is measured from the number of seconds elapsed since the password was last changed.
Example: 00001201000230.000000 000

I am getting

00000068235223.000000:000

So I have tried casting this to TimeSpanand DateTime no luck. what does the colon represent how to get number hours it represent.


Thanks Adding the WMI class name to title for the next poor soul that get confused by documentation wording.


here is what works

That worked perfectly $str = "00000068235223.000000:000" $ts = [System.Management.ManagementDateTimeConverter]::ToTimeSpan($str)

Days : 68 Hours : 23 Minutes : 52 Seconds : 23 Milliseconds : 0 Ticks : 59611430000000 TotalDays : 68.9947106481481 TotalHours : 1655.87305555556 TotalMinutes : 99352.3833333333 TotalSeconds : 5961143 TotalMilliseconds : 5961143000

Community
  • 1
  • 1
user1088352
  • 401
  • 3
  • 5
  • 11
  • possible duplicate of [How to convert a long datetime string to days in C#](http://stackoverflow.com/questions/22352308/how-to-convert-a-long-datetime-string-to-days-in-c-sharp) – Black Frog Jul 07 '15 at 15:21
  • The actual format of `PasswordAge` is `"ddddddddHHmmss.ffffff:000"` that is, 8 digits of days, then 2 digits of hours, then minutes, then seconds, then fractions. They say use `[TimeSpan]::ParseExact($string,"ddddddddHHmmss.ffffff:000",$null)` but I can't make it work in my PS4/Win7. Really weird. – Vesper Jul 07 '15 at 15:51
  • @Vesper: see my comment below. – PaulF Jul 07 '15 at 16:23

3 Answers3

5

This is the DMTF time interval format which is documented here. Basically it is string that encodes a time span in the form ddddddddHHMMSS.mmmmmm:000. Note that for time intervals, the ending is always :000.

From the docs:

The following example shows the format of a date-time interval. ddddddddHHMMSS.mmmmmm:000
The following table lists the fields of the date-time interval.
Field Description
dddddddd Eight digits that represent a number of days (00000000 through 99999999).
HH Two-digit hour of the day that uses the 24-hour clock (00 through 23).
MM Two-digit minute in the hour (00 through 59).
SS Two-digit number of seconds in the minute (00 through 59).
mmmmmm Six-digit number of microseconds in the second (000000 through 999999).

I believe the documentation is somewhat misleading for this field, since it is implying the whole numbers are full seconds, but in fact it is a string format representing days, hours, minutes, seconds, etc.

You should use [System.Management.ManagementDateTimeConverter]::ToTimeSpan to convert this string to a .NET Timespan, however, for whatever reason I actually received an array instead of a string for PasswordAge, so I had to use this:

$p = gwmi Win32_NetworkLoginProfile
[System.Management.ManagementDateTimeConverter]::ToTimeSpan($p.PasswordAge[1])
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • I think it is just poorly worded - saying it is _measured from the number of seconds_ not that it is the number of seconds. It is misleading about the datetime format rather than time interval. – PaulF Jul 07 '15 at 15:45
  • The main trouble that `[TimeSpan]::ParseExact($string,"ddddddddHHmmss.ffffff:000",$null)` does not produce a valid timespan with any of the supplied strings, while the docs say it should. – Vesper Jul 07 '15 at 15:55
  • 1
    @Vesper : See http://stackoverflow.com/questions/11719055/why-does-timespan-parseexact-not-work. The correct format string should be @"ddddddddhhmmss\.ffffff\:\0\0\0" (note hh not HH & escaping of ALL values that are not defined specifiers for time interval) – PaulF Jul 07 '15 at 16:17
4

To add to all the previous answers, the proper routine to make something out of this type of strings is call [System.Management.ManagementDateTimeConverter]::ToTimeSpan($string). This will produce a [System.TimeSpan] object, which you can then parse in a better way.

Credit for class to do conversion goes to this answer.

Community
  • 1
  • 1
Vesper
  • 18,599
  • 6
  • 39
  • 61
  • I would have mentioned this in my answer, however my attempts always received an error saying that the value "out of range of valid values". – Mike Zboray Jul 07 '15 at 16:06
  • That worked perfectly $str = "00000068235223.000000:000" $ts = [System.Management.ManagementDateTimeConverter]::ToTimeSpan($str) $ts 12 Days : 68 Hours : 23 Minutes : 52 Seconds : 23 Milliseconds : 0 Ticks : 59611430000000 TotalDays : 68.9947106481481 TotalHours : 1655.87305555556 TotalMinutes : 99352.3833333333 TotalSeconds : 5961143 TotalMilliseconds : 5961143000 – user1088352 Jul 07 '15 at 16:06
  • Ok for some reason `PasswordAge` is an array for me, not sure why, but this works. – Mike Zboray Jul 07 '15 at 16:18
1

Those are CIM_DATETIME values or Interval values. The format is defined by the CIM standard that WMI is built upon.

With normal datetime values, the WMI object provides a converter function. For example:

$_.ConvertToDateTime($_.PasswordExpires);

But that doesn't work for intervals, which is what PasswordAge is.

The MS doc you point to says the value is the number of seconds, but I believe that means the precision is to the second, not that the value is literally in seconds. My current password says it's 43 years old if that were the case, for example, and that's not possible. So it must use the Interval format.

I would do this:

$PasswordAge = New-TimeSpan -Days $_.PasswordAge.Substring(0,8) `
    -Hours $_.PasswordAge.Substring(8,2) `
    -Minutes $_.PasswordAge.Substring(10,2) `
    -Seconds $_.PasswordAge.Substring(12,2);

Remember to use $PasswordAge.TotalHours and not just $PasswordAge.Hours if you want the actual age value expressed in hours and not just the hour value of the timespan.

Edit: @Vesper is right. You can just use:

[System.Management.ManagementDateTimeConverter]::ToTimeSpan($_.PasswordAge);
Bacon Bits
  • 30,782
  • 5
  • 59
  • 66