Processing .EML files with Select-String and SetCreationTime()

Processing .EML files with Select-String and SetCreationTime()

  • Comments 3

In our newsgroup Microsoft.Public.Windows.PowerShell, Steve Foster asked whether PowerShell could help him with a bunch of emails in .EML format.  Here was his query:

Got a bunch of emails (.EML) that have been copied around various places
with the result that their file timestamps bear no resemblance to the
dates in the emails.

It would be really helpful to extract the date from the headers in the
emails, and update the timestamps on the files accordingly.

It strikes me that this would be the sort of thing PowerShell ought to be
really good at - but could it do the job? And if so, how?

Remember that old TV game show where the participants would guess how many notes it took to Name That Tune?  Well:

I can code that script in 2 lines!

foreach ($record in Select-String ^Date: *.eml) {
  [System.IO.File]::SetCreationTime($Record.Path, [datetime]($record.line.substring(6)))
}

Ok so I didn't count the trailing "}" as a line - sue me!  :-)

 

 

There are 2 lessons to draw here:

1) Select-String is NOT grep.  Here is an example to drive home that point:

PS> Select-String ^Date: *.eml |Get-Member -MemberType Property


   TypeName: Microsoft.PowerShell.Commands.MatchInfo

Name       MemberType Definition
----       ---------- ----------
Filename   Property   System.String Filename {get;}
IgnoreCase Property   System.Boolean IgnoreCase {get;set;}
Line       Property   System.String Line {get;set;}
LineNumber Property   System.Int32 LineNumber {get;set;}
Path       Property   System.String Path {get;set;}
Pattern    Property   System.String Pattern {get;set;}


PS> Select-String ^Date: *.eml |format-list *


IgnoreCase : True
LineNumber : 4
Line       : Date: Tue, 21 Nov 2006 09:30:19 -0800
Filename   : t1.eml
Path       : D:\Temp\t1.eml
Pattern    : ^Date:

IgnoreCase : True
LineNumber : 4
Line       : Date: Sat, 09 July 2005 09:30:19 -0800
Filename   : t3.eml
Path       : D:\Temp\t3.eml
Pattern    : ^Date:

2) .NET ROCKS.  Ok so we didn't get around to shipping a cmdlet to change the times on a filename.  .NET provides this so the fact that we can access .NET means that you are not stuck waiting for us.  In this example we are using a static method on PATH.  Here is how you find out what other statics are available on that class:

PS> [System.IO.File] |Get-Member -Static


   TypeName: System.IO.File

Name                 MemberType Definition
----                 ---------- ----------
AppendAllText        Method     static System.Void AppendAllText(String ..
AppendText           Method     static System.IO.StreamWriter AppendText..
Copy                 Method     static System.Void Copy(String sourceFil..
Create               Method     static System.IO.FileStream Create(Strin..
CreateText           Method     static System.IO.StreamWriter CreateText..
Decrypt              Method     static System.Void Decrypt(String path)
Delete               Method     static System.Void Delete(String path)
Encrypt              Method     static System.Void Encrypt(String path)
Equals               Method     static System.Boolean Equals(Object objA..
Exists               Method     static System.Boolean Exists(String path)
GetAccessControl     Method     static System.Security.AccessControl.Fil..
GetAttributes        Method     static System.IO.FileAttributes GetAttri..
GetCreationTime      Method     static System.DateTime GetCreationTime(S..
GetCreationTimeUtc   Method     static System.DateTime GetCreationTimeUt..
GetLastAccessTime    Method     static System.DateTime GetLastAccessTime..
GetLastAccessTimeUtc Method     static System.DateTime GetLastAccessTime..
GetLastWriteTime     Method     static System.DateTime GetLastWriteTime(..
GetLastWriteTimeUtc  Method     static System.DateTime GetLastWriteTimeU..
Move                 Method     static System.Void Move(String sourceFil..
Open                 Method     static System.IO.FileStream Open(String ..
OpenRead             Method     static System.IO.FileStream OpenRead(Str..
OpenText             Method     static System.IO.StreamReader OpenText(S..
OpenWrite            Method     static System.IO.FileStream OpenWrite(St..
ReadAllBytes         Method     static System.Byte[] ReadAllBytes(String..
ReadAllLines         Method     static System.String[] ReadAllLines(Stri..
ReadAllText          Method     static System.String ReadAllText(String ..
ReferenceEquals      Method     static System.Boolean ReferenceEquals(Ob..
Replace              Method     static System.Void Replace(String source..
SetAccessControl     Method     static System.Void SetAccessControl(Stri..
SetAttributes        Method     static System.Void SetAttributes(String ..
SetCreationTime      Method     static System.Void SetCreationTime(Strin..
SetCreationTimeUtc   Method     static System.Void SetCreationTimeUtc(St..
SetLastAccessTime    Method     static System.Void SetLastAccessTime(Str..
SetLastAccessTimeUtc Method     static System.Void SetLastAccessTimeUtc(..
SetLastWriteTime     Method     static System.Void SetLastWriteTime(Stri..
SetLastWriteTimeUtc  Method     static System.Void SetLastWriteTimeUtc(S..
WriteAllBytes        Method     static System.Void WriteAllBytes(String ..
WriteAllLines        Method     static System.Void WriteAllLines(String ..
WriteAllText         Method     static System.Void WriteAllText(String p..

Enjoy!

Jeffrey Snover [MSFT]
Windows PowerShell/MMC Architect
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Comment
  • Please add 8 and 1 and type the answer here:
  • Post
  • In my blog post Processing .EML files using Select-String and SetCreationTIme ( ) ( http://blogs.msdn.com/powershell/archive/2006/11/23/processing-eml-files-with-select-string-and-setcreationtime.aspx

  • The next drop of PowerShell Community Extensions (http://www.codeplex.com/powershellcx) will have a Set-FileTime cmdlet.  The current drop has a Set-FileDate cmdlet that is pretty much the same but I decided the cmdlet name should be Set-FileTime.

  • Came upon this when searching for a way to fix Courier email dates imported to Kerio mailserver.  The following small modification worked fine.  The header was slightly different to what was expected, was picking up <EST> which caused the script to fail.  So just stop the Kerio mail server run the scripts in each #msgs directory you need to fix and then delete the associated index.fld in the parent directory.  Restart Kerio and you are done.  Many thanks Jeffrey Snover for your script, made life a hell of a lot easier.

    //to set modified date

    foreach ($record in Select-String ^Delivery-date: *.eml) {

     [System.IO.File]::SetLastWriteTime($Record.Path, [datetime]($record.line.substring(15)))

    }

    //to set create date

    foreach ($record in Select-String ^Delivery-date: *.eml) {

     [System.IO.File]::SetCreationTime($Record.Path, [datetime]($record.line.substring(15)))

    }

Page 1 of 1 (3 items)