How to Batch Extract Attachments from MSG Files using PowerShell

You can use a PowerShell script to batch extract attachments from MSG files provided you have Microsoft Outlook installed.

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

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

function Expand-MsgAttachment
{
    [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
    {
        # Load application
        Write-Verbose "Loading Microsoft Outlook..."
        $outlook = New-Object -ComObject Outlook.Application
    }

    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

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

            # Extract message body
            Write-Verbose "Extracting attachments from $_..."
            $msg = $outlook.CreateItemFromTemplate($msgFn)
            $msg.Attachments | % {
                # Work out attachment file name
                $attFn = $msgFn -replace '\.msg$', " - Attachment - $($_.FileName)"

                # Do not try to overwrite existing files
                if (Test-Path -literalPath $attFn) {
                    Write-Verbose "Skipping $($_.FileName) (file already exists)..."
                    return
                }

                # Save attachment
                Write-Verbose "Saving $($_.FileName)..."
                $_.SaveAsFile($attFn)

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

    End
    {
        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 extract attachments from all of the MSG files in the current directory, simply import the new module and run the Expand-MsgAttachment as follows:

Import-Module MsgUtility
Expand-MsgAttachment *

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

Expand-MsgAttachment "Email from * to me dated *.msg"
Get-ChildItem -Recurse | Expand-MsgAttachment

Tags: MSG, attachments, PowerShell