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:
Having already researched what these fields are with this document:PS H:> cd HKCU:SoftwareMicrosoftOffice14.0ExcelFile MRUPS HKCU:SoftwareMicrosoftOffice14.0ExcelFile MRU> Get-ItemProperty . | select item 1Item 1------[F00000000][T01CD552EBC494F30][O00000000]*C:UsersWillDocumentsPowershellProjectsEncodingFormat Table.xlsx
Microsoft Office 2007, 2010 Registry ArtifactsWithin 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
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:"01CD552EBC494F30".length
Convert Hex value to Int64suggested the conversion was mindlessly easy:
Of key interest was the lineDim str As StringDim resultint64 As Int64str = TextBox1.Textresultint64 =Convert.ToInt64(str, 16)TextBox2.Text = resultint64
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:
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:129853623479390000
[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 bugAs noted in the case comments:
This is by design.When I rewrote my command it worked as expected to the second:
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.
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:[DateTime]::FromFileTime([Convert]::ToInt64("01CD552EBC494F30", 16))
$hexarray = "01","CD","55","2E","BC","49","4F","30"[DateTime]::FromFileTime([Convert]::ToInt64(($hexarray -join ),16)returns the same value:
So, as is outlined above, a little understanding can help transform seemingly useless data into useful information.Thursday, June 28, 2012 8:05:47 AM