How to Convert MSG Files to DOC Files using PowerShell

You can use a PowerShell script to batch convert emails in MSG format to DOC files provided you have Microsoft Word and Microsoft Outlook installed.

There are a number of utilities, many of them quite pricey, that let you convert email messages stored in MSG format to other file formats. But if you want a quick and easy (and free) way to convert MSG files to DOC files, you can try the PowerShell cmdlet below.

Since there are a larger number of apps that deal with DOC files, once the emails are in DOC format, it is a relatively simple task to convert them to other file formats. For example, you could use Adobe Acrobat or other PDF software to convert the HTML files to PDFs.

The only catch is that you must have Microsoft Word and Microsoft Outlook installed. I’ve tested this with Microsoft Office 2010, but it should work fine with Microsoft Office 2007 and 2013 too.

function ConvertFrom-MsgToDoc
{
    [CmdletBinding()]

    Param
    (
        [Parameter(ParameterSetName="Path", Position=0, Mandatory=$True)]
        [String]$Path,

        [Parameter(ParameterSetName="LiteralPath", Mandatory=$True)]
        [String]$LiteralPath,

        [Parameter(ParameterSetName="FileInfo", Mandatory=$True, ValueFromPipeline=$True)]
        [System.IO.FileInfo]$Item
    )

    Begin
    {
        # OlSaveAsType constants
        $olTXT = 0
        $olRTF = 1
        $olTemplate = 2
        $olMSG = 3
        $olDoc = 4

        # WdPaperSize constants
        $wdPaper10x14 = 0
        $wdPaper11x17 = 1
        $wdPaperLetter = 2
        $wdPaperLetterSmall = 3
        $wdPaperLegal = 4
        $wdPaperExecutive = 5
        $wdPaperA3 = 6
        $wdPaperA4 = 7
        $wdPaperA4Small = 8
        $wdPaperA5 = 9
        $wdPaperB4 = 10
        $wdPaperB5 = 11
        $wdPaperCSheet = 12
        $wdPaperDSheet = 13
        $wdPaperESheet = 14
        $wdPaperFanfoldLegalGerman = 15
        $wdPaperFanfoldStdGerman = 16
        $wdPaperFanfoldUS = 17
        $wdPaperFolio = 18
        $wdPaperLedger = 19
        $wdPaperNote = 20
        $wdPaperQuarto = 21
        $wdPaperStatement = 22
        $wdPaperTabloid = 23
        $wdPaperEnvelope9 = 24
        $wdPaperEnvelope10 = 25
        $wdPaperEnvelope11 = 26
        $wdPaperEnvelope12 = 27
        $wdPaperEnvelope14 = 28
        $wdPaperEnvelopeB4 = 29
        $wdPaperEnvelopeB5 = 30
        $wdPaperEnvelopeB6 = 31
        $wdPaperEnvelopeC3 = 32
        $wdPaperEnvelopeC4 = 33
        $wdPaperEnvelopeC5 = 34
        $wdPaperEnvelopeC6 = 35
        $wdPaperEnvelopeC65 = 36
        $wdPaperEnvelopeDL = 37
        $wdPaperEnvelopeItaly = 38
        $wdPaperEnvelopeMonarch = 39
        $wdPaperEnvelopePersonal = 40
        $wdPaperCustom = 41

        # Load applications
        Write-Verbose "Loading Microsoft Outlook..."
        $outlook = New-Object -ComObject Outlook.Application

        Write-Verbose "Loading Microsoft Word..."
        $word = New-Object -ComObject Word.Application

        # Disable signature
        $signaturesPath = Join-Path $env:APPDATA "Microsoft\Signatures"
        Get-ChildItem $signaturesPath | % {
            Rename-Item $_.FullName ("_" + $_.Name)
        }
    }

    Process
    {
        switch ($PSCmdlet.ParameterSetName)
        {
            "Path"        { $files = Get-ChildItem -Path $Path }
            "LiteralPath" { $files = Get-ChildItem -LiteralPath $LiteralPath }
            "FileInfo"    { $files = $Item }
        }

        $files | % {
            # Work out file names
            $msgFn = $_.FullName
            $docFn = $msgFn -replace '\.msg$', '.doc'

            # Skip non-.msg files
            if ($msgFn -notlike "*.msg") {
                Write-Verbose "Skipping $_ (not an .msg file)..."
                return
            }

            # Do not try to overwrite existing files
            if (Test-Path -LiteralPath $docFn) {
                Write-Verbose "Skipping $_ (.doc already exists)..."
                return
            }

            # Extract message body
            Write-Verbose "Extracting message body from $_..."
            $msg = $outlook.CreateItemFromTemplate($msgFn)
            $msg.SaveAs($docFn, $olDoc)

            # Convert to A4
            Write-Verbose "Converting file size to A4..."
            $doc = $word.Documents.Add($docFn)
            $doc.PageSetup.PaperSize = $wdPaperA4
            $doc.SaveAs([ref]$docFn)
            $doc.Close()

            # Output to pipeline
            Get-ChildItem -LiteralPath $docFn
        }
    }

    End
    {
        # Enable signatures
        Get-ChildItem $signaturesPath | % {
            Rename-Item $_.FullName $_.Name.Substring(1)
        }

        Write-Verbose "Done."
    }
}

Installation

Save the code to a file called MsgUtility.psm1, and put it in its own folder called MsgUtility in your PowerShell modules folder.

On Windows Vista and newer, the PowerShell modules folder is typically found here:

C:\Users\__your_username__\Documents\WindowsPowerShell\Modules

On Windows XP, the PowerShell modules folder is typically found here:

C:\Documents and Settings\__your_username__\Documents\WindowsPowerShell\Modules

If the PowerShell modules folder doesn’t exist, create it.

Usage

To use the cmdlet to convert all the MSG files in the current directory, simply import the new module and run the ConvertFrom-MsgToDoc as follows:

Import-Module MsgUtility
ConvertFrom-MsgToDoc *

And of course you can pipe input files or specify a single file or a wildcard pattern as you can with other PowerShell cmdlets:

ConvertFrom-MsgToDoc "Email from * to me dated *.msg"
Get-ChildItem -Recurse | ConvertFrom-MsgToDoc

Tags: MSG, DOC, PowerShell