Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, July 20, 2011 8:17 AM
Hey Guys, Hoping for someone with good knowledge in powershell to explain how i should go about using the outlook comobject to either: A) Convert a specific PST i.e. "c:\mail\test.pst" to XML or i'll even settle for CSV B) Read the full PST and display the Raw Data I'm just getting familiar with the following: $ol = new-object -comobject "Outlook.Application" so any help would be appreciated. Cheers To
All replies (11)
Thursday, August 11, 2011 3:31 PM âś…Answered | 2 votes
I definitely spent way too much time on this, but hey I found it interesting :) So here you go:
How to open a PST file:
# This is how you open a PST file and access its contents using the Outlook object model
[string]$pstPath = "P:\Config\Outlook\Archives\Projects\Projects.pst"
# Outlook needs to be running already to attach to it
$oProc = ( Get-Process | where { $_.Name -eq "OUTLOOK" } )
if ( $oProc -eq $null ) { Start-Process outlook -WindowStyle "Minimized"; Start-Sleep -Seconds 5 }
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$namespace.AddStoreEx($pstPath, "olStoreDefault")
$pstStore = ( $nameSpace.Stores | where { $_.FilePath -eq $pstPath } )
$pstRootFolder = $pstStore.GetRootFolder()
A function that serializes a mail message. It produces an XML element called mailitem that contains metadata about the mail item as well as a serialized image of an .msg file. The folder and store object just supply additional metadata to add to the XML for the mail item.
function Serialize-MailItem()
{
param( [System.__ComObject]$Store,
[System.__ComObject]$Folder,
[System.__ComObject]$MailItem,
[string]$Format = "olMSG" )
$xDocTemp = New-Object xml
$xItem = $xDocTemp.CreateElement("mailItem")
$xStoreName = $xDocTemp.CreateElement("storeName")
$xStorePath = $xDocTemp.CreateElement("storePath")
$xFolderPath = $xDocTemp.CreateElement("folderPath")
$xFormat = $xDocTemp.CreateElement("fileFormat")
$xContent = $xDocTemp.CreateElement("serializedContent")
$xStoreName.InnerText = $Store.DisplayName
$xStorePath.InnerText = $Store.FilePath
$xFolderPath.InnerText = $Folder.FolderPath
$xFormat.InnerText = $Format
$tempFileName = [System.IO.Path]::GetTempPath() + "tempmessage.msg"
$formatEnumValue = [Microsoft.Office.Interop.Outlook.OlSaveAsType]$Format
$MailItem.SaveAs($tempFileName, $formatEnumValue)
[int]$fLength = (New-Object System.IO.FileInfo( $tempFileName )).Length
[byte[]]$byteStream = New-Object byte[] $fLength
$fs = New-Object System.IO.FileStream( $tempFileName, "Open" )
[void]$fs.Read($byteStream, 0, $fLength)
$fs.Close()
[string]$serializedStream = [Convert]::ToBase64String($byteStream)
$xContent.InnerText = $serializedStream
Remove-Item $tempFileName
[void]$xItem.AppendChild($xStoreName)
[void]$xItem.AppendChild($xStorePath)
[void]$xItem.AppendChild($xFolderPath)
[void]$xItem.AppendChild($xFormat)
[void]$xItem.AppendChild($xContent)
return $xItem
}
A function that deserializes a mail message. It imports it to the mail folder specified. It will also return the message itself, because the MailItem.Move() method returns an object representing the moved mail item. If you don't want to get the mail item, add "[void]" in front of the line "$MailItem.Move( $Folder )" or just pipe the output to Out-Null.
function Deserialize-MailItem()
{
param( [Xml.XmlElement]$SerializedMailItem,
[System.__ComObject]$Folder )
$xContent = $SerializedMailItem.SelectSingleNode("serializedContent")
$xFormat = $SerializedMailItem.SelectSingleNode("fileFormat")
[string]$serializedStream = $xContent.InnerText
[byte[]]$byteStream = [Convert]::FromBase64String($serializedStream)
[int]$fLength = $byteStream.Length
$tempFileName = [System.IO.Path]::GetTempPath() + "tempmessage.msg"
$fs = New-Object System.IO.FileStream( $tempFileName, "Create" )
[void]$fs.Write($byteStream, 0, $fLength)
$fs.Close()
$MailItem = $NameSpace.OpenSharedItem($tempFileName)
$MailItem.Move( $Folder )
Remove-Item $tempFileName
}
I didn't use any of the store or folder metadata in my deserialization function, but you could add stuff if you wanted to, for example to reconstruct the PST file and folder structure in the session that receives the serialized messages.
By the way, to get all the mail items in a PST file you have to recurse through the folder structure. A simple function to do this:
function Get-AllMAPIFolders( [Object]$RootFolder )
{
$folderList = New-Object 'System.Collections.Generic.List[Object]'
$folderList.Add($RootFolder)
foreach( $subFolder in $RootFolder.Folders ) {
if ( $subFolder.Folders.Count -gt 0 ) {
$folderList.AddRange((Get-AllMAPIFolders $subFolder))
} else {
$folderList.Add($subFolder)
}
}
return $folderList
}
Finally, here's an example of actually loading a PST file and serializing all the mail items in it. Consider this immediately following the first code sample in this post (you've already loaded the PST file and retrieved the root folder).
$allFolders = Get-AllMAPIFolders $pstRootFolder
$allMailItems = @()
foreach( $folder in $allFolders )
{
foreach ( $item in $folder.Items )
{
$serializedItem = Serialize-MailItem -Store $pstStore -Folder $folder -MailItem $item
# Do stuff with the serialized item XML element
}
}
jmh
Tuesday, August 9, 2011 4:30 PM | 1 vote
An import prerequisite question is: what part of the PST file do you want to convert? Needless to say a PST file is a complicated proprietary binary format, as are the folders and individual mail items within it. Are you trying to serialize the binary data for transfer via XML? Or do you really want the readable content? I'm assuming the latter, because obviously you can't put an attachment or a calendar item in a CSV file. Even for the content though, further questions are: Do you want to preserve HTML or rich text formatting for messages saved in those formats? Do you want to save internet headers? ... The answer of how to do this from PowerShell depends on the answers to the above questions.
jmh
Wednesday, August 10, 2011 8:05 AM
Hi jmh_gr, When you say, what part of the PST file would i like to convert.. i presume you're speaking in reference to the preliminary Mail, Calendars, Task, Contacts etc, in which case its the Mail Folder > inbox & Contacts which i'm mainly interested in, you are correct in assuming I wish serialize binary data for transfer via XML.. preserving the HTML isn't needed, rich text will suffice and although I didn't before think about this, saving the internet headers would be perfect. Kind Regards
Wednesday, August 10, 2011 4:42 PM
...So you need to extract and serialize individual mail items?jmh
Thursday, August 11, 2011 7:57 AM
Correct
Friday, August 12, 2011 8:24 AM
Son Of A B**ch I Didn't want you do it for me, it was a practice mission to improve my PS! Just a point in the right direction, would have been great.. lmfao Regardless, It's Really Appreciated and Works Great.. I can learn loads from looking at your Powershell project, Thanks.. P.S - (Any Java, C# or C Problems, IOU1)
Friday, August 12, 2011 11:14 AM
:D No problemo. Once I get stuck something I have a very hard time putting it down until I've figured it out. Anyway I enjoy it -- way more fun than sudoku :). I will keep that in mind about Java, too, as I may be venturing in that direction soon...
jmh
Monday, January 9, 2012 6:25 PM
Much obliged sir! So grateful that I found this. Have you thought about uploading this to powershell.com? It's your code, so I wouldn't do that on my own...
Monday, January 9, 2012 6:25 PM
Much obliged sir! So grateful that I found this. Have you thought about uploading this to powershell.com? It's your code, so I wouldn't do that on my own...
Monday, July 16, 2012 12:45 PM
Wow, this is the answer to a PITA project that I have been working on for months. Thanks for this.
Monday, December 16, 2013 8:17 PM
Joshua,
script looks great! How would you modify it to only export calendar items into xml? I am new to powershell so not sure does your script all go into one file or is it separated and stored in one folder?
I need this for a small project in the new year so hopefully you can help me out :)
Look forward to your reply
Thanks,
Bill