Archiving email attachments

Posted by: hbr in scriptpowershelloutlookattachmentsarchive on Print 

I had a discussion last week with a colleague about archiving messages in outlook. I have a 7GB mailbox on the server because I never delete mail. That may seem overdone but it has served me well a couple of times in discussions we had. Besides, I see absolutely no point in archiving mail away from the mail server to another store on some fileserver that eventually lands on the same central storage.

But a lot of the older mail contains attachments that are outdated and no longer needed. The reason I keep older mail is because the text that's in there. All the old documents can go. A nice side effect of having less attachments in my older mail is that with a reinstall of my client, I need less data to download.

So I started looking for products that could remove attachments from a certain size and a certain age and store it somewhere so I can easily filter it for later reference. So far I haven't found one that does what I need. So I figured I'd write one myself.

Nowadays, everything that Microsoft products do can be controlled by Powershell so I choose to write the tool in the form of a script. The core of it was quickly written last night (I have done things like that before) apart from one tiny pitfall; if attachments are removed in a loop, the attachment list gets confused as to which is next and it skips every other attachment if one is deleted. It took me a while to figure out why and how to fix it. But with a little ugly hack and a for loop instead of a foreach, it works perfectly now.

This script will remove attachments of a given size and a given age and store them in a given directory, leaving a link inside the email. I choose to remove attachments with an age of over 1 year and with a size of 1MB and up. It sized my 7GB outlook.ost file down to 4GB (after using the 'compact' function in outlook and waiting 8 hours!). If I run it with a 180 day age and 500kB size, it goes down to less than 2GB.

Useful? Maybe not for everyone, but it was a fun night of scripting which beats the hell out of the reality soaps on TV :)

Here's the script. Save it as a .ps1 file, sign it or set-executionpolicy to unrestriced and have a go. Oh, and backup your mail first ;)

#
# CONFIG:
#
$daysold=365
$minsize=1024000
$attstorage="D:\attachments\"

###############################################
# No need to edit below this line:
#
#
[System.Reflection.Assembly]::LoadWithPartialName("System.web") | out-null

Add-Type -AssemblyName microsoft.office.interop.outlook

 

$olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type]

$outlook = new-object -comobject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$inbox = $namespace.getDefaultFolder("olFolderInbox")
$sentitems = $namespace.getDefaultFolder("olFolderSentMail")
$oldmail = (date).AddDays(-$daysold)
$logfile = ($attstorage + (date -uformat %Y-%m-%d) + ".log")
$global:total = 0

function log ($str) { write-output $str | out-file $logfile -append }
function good ($str) { write-host -foregroundcolor green $str }
function bad ($str) { write-host -foregroundcolor red $str }
function ok ($str) { write-host -foregroundcolor yellow $str }
function encode ($str) { return [system.web.httputility]::urlencode($str) }
function decode ($str) { return [system.web.httputility]::urldecode($str) }

function proc
{
    param($folder, $name)
    $list=$folder.items|?{$_.receivedTime -lt $oldmail}
    foreach ($mail in $list)
    {   
        $str=""
        $max=$mail.attachments.count
        for ($i = 1; $i -le $max; $i++ ) {
            $att = $mail.attachments.item($i)
            if ($att.size -gt $minsize) {
                $global:total = $global:total + $att.size
                $filename=encode($name + "-" + $att.filename)
                $att.SaveAsFile($attstorage + $filename)
                if (test-path($attstorage + $filename)) {
                    if ((get-item($attstorage + $filename)).length -eq 0) {
                        bad ("Error writing file '" + $filename + "' to " + $attstorage)
                        exit 1
                    }
                    good ("" + $attstorage + $filename + " saved succesfully." )
                    log ("From: " + $mail.sendername + " (" + $mail.senderemailaddress + "), Date: " + (date $mail.ReceivedTime -uformat "%Y-%m-%d %H:%M") + "; " + $attstorage + $filename + " (" + ([int](100*$att.size/1024/1024)/100) + " MB) saved succesfully." )
                    $str=$str + $crlf + 'Attachment removed and saved to ' + $filename + "

                    $att.delete()
                    $max--
                    $i--
                } else {
                    bad ("" + $attstorage + $filename + " not saved." )
                    exit 2
                }
            } 
        }
        if ($str -ne "") {
            $mail.htmlbody = $mail.htmlbody -ireplace "(]*>)", ("`$1" + $str)
            $mail.save()
        }
    }
}

function deeper
{
    param($folder, $name)
    ok ( "-  Processing: " + $name )
    proc $folder $name
    $folder.folders|%{deeper $_ ($name + "-" + $_.name)}
}

if (! (test-path $attstorage)) { mkdir $attstorage }
if (! (test-path $attstorage)) { throw "ERROR!! Can't create " + $attstorage  }
deeper $inbox "Inbox"
deeper $sentitems "Sent-Items"
"" + ([int](10*$global:total/1024/1024)/10) + " MB removed. "

 

Comments (0)Add Comment

Write comment
You must be logged in to post a comment. Please register if you do not have an account yet.

busy