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
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?
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?
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
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
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.
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