PowerShell v2 Convert Hex encoded String to DateTime


In the process of researching an article I stumbled onto a challenge I had not faced yet. The specific information I was working with involved registry values for Micrsoft Excel MRU (Most Recently Used) items. In Windows 7/Office 2010 files opened by Excel get cached in MRU keys as a form of persistence. Without getting too far into the details, I had some values I wanted to know more about, so, I cracked open PowerShell and drilled into the key with this command:
PS H:> cd HKCU:SoftwareMicrosoftOffice14.0ExcelFile MRU
PS HKCU:SoftwareMicrosoftOffice14.0ExcelFile MRU> Get-ItemProperty . | select item 1

Item 1
------
[F00000000][T01CD552EBC494F30][O00000000]*C:UsersWillDocumentsPowershellProjectsEncodingFormat Table.xlsx
Having already researched what these fields are with this document:
Microsoft Office 2007, 2010 – Registry Artifacts
Within Hurlbuts analysis is this tidbit regarding the values located in this key,
In Office 2008, Microsoft added a new feature to MRUs for Excel, PowerPoint, and Word. There is now a header that precedes the path statement in the value.
The header is defined by a bracketed [F00000000]. Following this is a second bracketed data set starting with a "T". The numbers following the T appear to be a date/time stamp of when the document was last opened by the user.
...
This information is saved in a non-standard 64-bit Windows date and time stamp. The typical format in the registry is to store the data in hexadecimal little endian format.
Hmm, I thought, this could be of value, but, I have to port the value to a [DateTime] for it to be of use in PowerShell. In the data listed above, I knew I was interested in the timestamp field: [T01CD552EBC494F30]. I assumed T was meaningless, so, my focus was this: 01CD552EBC494F30.
Checking it out with some simple properties
"01CD552EBC494F30".length
verified it was Hex encoded for starters since it must have at least an even number of characters. The fact that it was 16 characters long (8-bytes) was good as well. So, I began digging around. One particular search result:
Convert Hex value to Int64
suggested the conversion was mindlessly easy:
Dim str As String
Dim resultint64 As Int64
str = TextBox1.Text
resultint64 =Convert.ToInt64(str, 16)
TextBox2.Text = resultint64
Of key interest was the line
resultint64 = Convert.ToInt64(str, 16)
Going with the theory that I could just use PowerShells static method was confirmed when I ran this:
[Convert]::ToInt64("01CD552EBC494F30", 16)
and it returned this:
129853623479390000
Well, that looks right, but, the only way to be sure is to see if I can get a [DateTime] from this somehow. Wondering, on a sheer hunch, if a conversion would handle it via .NET also proved to be a stroke of luck:

[DateTime][Convert]::ToInt64("01CD552EBC494F30", 16)
 Thursday, June 28, 0412 1:05:47 PM

The only weird this is that the year is off. Way off and the hours were not right. I knew the 1600 thing was a Microsoft specific issue, but, could not put my finger on it. A little more digging led me to find this Connect case pointing out it was not only known, but, by design:
datetime 1600 year bug
As noted in the case comments:
This is by design.
You should use the static FromFileTime method to get back your datetime object.
PS C:WindowsSystem32> [datetime]::FromFileTime($ntDate)
Wednesday, May 14, 2008 7:12:30 PM
Casting with [DateTime] will interpret the int64 as ticks.
When I rewrote my command it worked as expected to the second:
[DateTime]::FromFileTime([Convert]::ToInt64("01CD552EBC494F30", 16))
To be more exhaustive on how you can do this from an array, a simple join command can take an 8-character byte array and turn it into a string:
$hexarray = "01","CD","55","2E","BC","49","4F","30"[DateTime]::FromFileTime([Convert]::ToInt64(($hexarray -join ),16)
returns the same value:
Thursday, June 28, 2012 8:05:47 AM
So, as is outlined above, a little understanding can help transform seemingly useless data into useful information.

Related Posts by Categories

0 comments:

Post a Comment