How to automate saving attachments from Outlook with PowerShell?

I had an annoying task that I had to do every week. It was tedious and repetitive. It basically entailed saving a bunch of attachments from different emails to my local drive. After a few weeks, I thought, I wonder if I can automate saving attachments from Outlook with PowerShell?

I even considered hiring a VA but in the end, decided to do the automation myself. Mainly because I didn’t expect the task to expire any time soon – this is usually an indication that You should figure out an automated solution for it.

What is PowerShell?

For those who don’t know and are more “beginner” types in automation here’s a brief description of PowerShell.

PowerShell is a task automation and configuration management framework from Microsoft, consisting of a command-line shell and associated scripting language built on the .NET framework. It can be used to automate various tasks including data processing, system administration, and even communication with external applications like Microsoft Outlook.

I’ve personally used it a lot at my current job administrating O365 or automating different tasks backend. Copying files from one server to another – or even for the users onto a shared Network drive.

The PowerShell script that I used

Sometimes You have to try a couple of things before it truly works in IT.

I went through a couple of reiterations of the script I ended up using but here it is. I will go through it line by line in the later paragraphs.

$Outlook = New-Object -ComObject Outlook.Application
$NS = $Outlook.GetNameSpace("MAPI")
$Inbox = $NS.Folders.Item("[email protected]").Folders.Item("Inbox")
$Items = $Inbox.Items

$AttachmentsPath = "C:\OutlookAttachments\"
if (!(Test-Path -Path $AttachmentsPath)) {
  New-Item -ItemType Directory -Path $AttachmentsPath
}

foreach ($Message in $Items)
{
    if ($Message.SenderEmailAddress -eq "[email protected]")
    {
        foreach ($Attachment in $Message.Attachments)
        {
            if ($Attachment.FileName -like "*.jpg")
            {
                $AttachmentIndex = 1
                $AttachmentFileName = $AttachmentsPath + $Attachment.FileName
                while(Test-Path -Path $AttachmentFileName){
                    $AttachmentFileName = $AttachmentsPath + "("+$AttachmentIndex+")" + $Attachment.FileName
                    $AttachmentIndex++
                }
                $Attachment.SaveAsFile($AttachmentFileName)
            }
        }
    }
}

What does the script exactly do?

I always like to know what the code or script does before I implement it in production environments.

The script starts with a reference to the Outlook Application object, which allows us to access the Outlook application running on the machine and access its properties and methods. This is done using the New-Object cmdlet and the -ComObject parameter. The code block below initializes the Outlook Application object:

$Outlook = New-Object -ComObject Outlook.Application

Next, we access the MAPI namespace in Outlook, which is the Messaging Application Programming Interface that provides a common set of functions to access various mail systems. This is done using the GetNameSpace method of the Outlook Application object, as shown below:

$NS = $Outlook.GetNameSpace("MAPI")

What else is there?

Just pressing the buttons isn’t always enough!

Now that we have access to the MAPI namespace, we can access the folders within the namespace, in this case, the Inbox folder of a specific email account. The following code block retrieves the Inbox folder of the email account [email protected]:

$Inbox = $NS.Folders.Item("[email protected]").Folders.Item("Inbox")

Once we have access to the Inbox folder, we retrieve all the items in the folder using the Items property. The items could be emails, appointments, contacts, and others, but in our case, we are only interested in emails with attachments. The following code block retrieves all the items in the Inbox folder:

$Items = $Inbox.Items

Saving the files with PowerShell

This is what files used to look like. Now they are all up in a “cloud” somewhere…

Next, we create a folder in the local drive to save our attachments. In this case, the folder is called OutlookAttachments and is created in the root directory of the C: drive. The script checks if the folder already exists and creates it only if it does not exist, as shown below:

$AttachmentsPath = "C:\OutlookAttachments\"
if (!(Test-Path -Path $AttachmentsPath)) {
  New-Item -ItemType Directory -Path $AttachmentsPath
}

But wait, which files?

Now that we have set up the environment, we can start iterating through the items in the Inbox folder and processing each item. We use a foreach loop to iterate through each item in the $Items collection. Within the loop, we use an if statement to filter the items by sender email address (but You can do this with different criteria that suit Your specific needs), in this case, [email protected]. The following code block shows the complete foreach loop:

foreach ($Message in $Items)
{
    if ($Message.SenderEmailAddress -eq "[email protected]")
    {
        # Processing the attachments in the message
    }
}

Within the if statement, we process the attachments in the message. For each attachment in the message, we use another foreach loop and if statement to filter what types of attachments we want to save:

foreach ($Attachment in $Message.Attachments)
        {
            if ($Attachment.FileName -like "*.jpg")
            {

Naming the files and saving all of them with PowerShell

Let’s keep it organized!

We now know from where to save the files and which types of files. But how can we make sure we save all of them and we also need to name them.

For each attachment, it checks if the file name ends with .jpg using the -like operator. If it does, the script sets a variable called $AttachmentIndex to 1 and creates a new variable called $AttachmentFileName using a combination of the file path stored in $AttachmentsPath and the file name of the attachment.

        foreach ($Attachment in $Message.Attachments)
        {
            if ($Attachment.FileName -like "*.jpg")
            {
                $AttachmentIndex = 1
                $AttachmentFileName = $AttachmentsPath + $Attachment.FileName

What about duplicate names?

The script then uses the Test-Path cmdlet to check if a file with the same name already exists in the specified path. If it does, the script increments the $AttachmentIndex variable and appends it to the file name, creating a new unique file name.

 $AttachmentFileName = $AttachmentsPath + $Attachment.FileName
                while(Test-Path -Path $AttachmentFileName){
                    $AttachmentFileName = $AttachmentsPath + "("+$AttachmentIndex+")" + $Attachment.FileName
                    $AttachmentIndex++
                }

Finally, the script saves the attachment to the specified path using the SaveAsFile method of the attachment object, passing in the unique file name created earlier.

                $Attachment.SaveAsFile($AttachmentFileName)

That’s it, this is how You automate saving attachments from Outlook with PowerShell.

Ship it!

It can seem quite daunting at first but with some knowledge of PowerShell, You can already start automating repetitive daily or weekly tasks. Just refer to the PowerShell manual for Your personal needs.

I’ve already saved a bunch of time with this little code snippet! Hope it helps You as well!

Ian Altosaar

Leave a Comment