18
votes

How would I go about using powershell to return the text and headers of the last 5 messages received to my exchange email account? Is there a simple way/library to do this?

This is related to my question about not using outlook on superuser. Except that having not found any good alternatives I figure I might as well write my own simple powershell client.

2
Where do you need to check this on a local computer that has the Oulook client installed or on the Exchange server (that likely doesn't have the client)? Does it have to be a free solution?Marco Shaw
I want an alternative to having to open outlook just to get a link out of an email. So let's assume outlook is not installed and yes, I would like it to be free since I'd like to put it up on PoshCode. I've been doing some digging and really Pop3 would probably work just fine.George Mauer

2 Answers

18
votes

You'll need to have the EWS API installed, and you'll need to check the path to the DLL in the Reflection Assembly load portion.

This should get you to the point where you're able to work with the $inbox.FindItems(5) statement and filter the results you want out of that.

[Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\1.0\Microsoft.Exchange.WebServices.dll")
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = New-Object Net.NetworkCredential('user', 'pass', 'domain')
$s.AutodiscoverUrl("[email protected]")

$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$inbox.FindItems(5)
23
votes

Firstly, apologies that this reply is nearly two years after the question, but I also wanted to check email using Powershell and found this question. Hopefully my code will serve as a reference/starting point for someone else looking to mine outlook from Powershell. I plan to enhance this myself to make it more usable.

I'm pretty new to Powershell, so my scripts are predominantly Frankenstein-ed from various articles, blog posts and StackOverflow Q&A's of course, the script below being no exception!

Following on from Chris' response, I did a little further digging around the internet and cobbled together a few snippets of Powershell to allow me to display a few key pieces of information from emails.

It's sadly lacking in any 'proper' style and I'm sure that any Powershell gurus will cringe at this. But what this code does do is

  • show how to use EWS & Powershell to read emails
  • address George's last question re: the body being blank - the FindItems method doesn't return the full mail item, you have to make another round-trip to get the extra information you need.
  • remove the requirement for you to use username/password/domain by using your current credentials
  • remove the requirement to 'install' EWS, simply extract the MSI and reference the dll

To use...

Download the EWS from here then extract somewhere, e.g.

msiexec /a C:\Path\To\Downloads\EwsManagedApi.msi /qb TARGETDIR=C:\Progs\EwsManagedApi

then call this script using dot-source, e.g.

. C:\Path\To\Script\Outlook_ReadInbox.ps1

which allows you to reference the objects/variables from the script after it has executed.

The code has a limited comments throughout, as well as a few links at the end, which I referenced when cobbling the script together.

Here's my alpha draft of code to read in the first 5 emails, display whether read/unread and show the first 100 characters of the email body on one line with white-space removed.

# work with exchange server to retrieve messages
# see this SO answer: http://stackoverflow.com/a/4866894

# call this script using dot-source (see http://technet.microsoft.com/en-us/library/ee176949.aspx)
# to allow continued use of the objects, specifically, reading our inbox
# e.g...
# . C:\Path\To\Script\Outlook_ReadInbox.ps1

# replace with your email address
$email    = "[email protected]"

# only need to populate these if you're impersonating...
$username = "YOUR_USER_NAME"
$password = "YOUR_LAN_PASSWORD"
$domain   = "YOUR_DOMAIN"

# to allow us to write multi-coloured lines
# see http://stackoverflow.com/a/2688572
# usage: Write-Color -Text Red,White,Blue -Color Red,White,Blue
# usage: Write-Color Red,White,Blue Red,White,Blue
function Write-Color([String[]]$Text, [ConsoleColor[]]$Color) {
    for ($i = 0; $i -lt $Text.Length; $i++) {
        Write-Host $Text[$i] -Foreground $Color[$i] -NoNewLine
    }
    Write-Host
}

# load the assembly
[void] [Reflection.Assembly]::LoadFile("C:\Progs\EwsManagedApi\Microsoft.Exchange.WebServices.dll")

# set ref to exchange, first references 2007, 2nd is 2010 (default)
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
#$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService

# use first option if you want to impersonate, otherwise, grab your own credentials
#$s.Credentials = New-Object Net.NetworkCredential($username, $password, $domain)
#$s.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$s.UseDefaultCredentials = $true

# discover the url from your email address
$s.AutodiscoverUrl($email)

# get a handle to the inbox
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)

#create a property set (to let us access the body & other details not available from the FindItems call)
$psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;

$items = $inbox.FindItems(5)

#set colours for Write-Color output
$colorsread = "Yellow","White"
$colorsunread = "Red","White"

# output unread count
Write-Color -Text "Unread count: ",$inbox.UnreadCount -Color $colorsread

foreach ($item in $items.Items)
{
  # load the property set to allow us to get to the body
  $item.load($psPropertySet)

  # colour our output
  If ($item.IsRead) { $colors = $colorsread } Else { $colors = $colorsunread }

  #format our body
  #replace any whitespace with a single space then get the 1st 100 chars
  $bod = $item.Body.Text -replace '\s+', ' '
  $bodCutOff = (100,$bod.Length | Measure-Object -Minimum).Minimum
  $bod = $bod.Substring(0,$bodCutOff)
  $bod = "$bod..."

  # output the results - first of all the From, Subject, References and Message ID
  write-host "====================================================================" -foregroundcolor White
  Write-Color "From:    ",$($item.From.Name) $colors
  Write-Color "Subject: ",$($item.Subject)   $colors
  Write-Color "Body:    ",$($bod)            $colors
  write-host "====================================================================" -foregroundcolor White
  ""
}


# display the newest 5 items
#$inbox.FindItems(5)
# display the unread items from the newest 5
#$inbox.FindItems(5) | ?{$_.IsRead -eq $False} | Select Subject, Sender, DateTimeSent | Format-Table -auto

# returns the number of unread items
# $inbox.UnreadCount


#see these URLs for more info
# EWS
# folder members: https://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.folder_members%28v=exchg.80%29.aspx
# exporting headers: http://www.stevieg.org/tag/how-to/
# read emails with EWS: https://social.technet.microsoft.com/Forums/en-US/3fbf8348-2945-43aa-a0bc-f3b1d34da27c/read-emails-with-ews?forum=exchangesvrdevelopment
# Powershell
# multi-color lines: http://stackoverflow.com/a/2688572



# download the Exchange Web Services Managed API 1.2.1 from
# http://www.microsoft.com/en-us/download/details.aspx?id=30141
# extract somewhere, e.g. ...
# msiexec /a C:\Users\YourUsername\Downloads\EwsManagedApi.msi /qb TARGETDIR=C:\Progs\EwsManagedApi