Get email items from mailboxes through powershell - powershell

I need to retrieve email items from outlook from various mailboxes.
I found the below script that works fine for my inbox. But how do i define other mailbox name in the script.
I have many mailboxes and each hour i need to retrieve items from the mailboxes, hence looking out for automation which help save efforts.
Function Get-OutlookInBox
{
<#
.Synopsis
This function returns InBox items from default Outlook profile
.Description
This function returns InBox items from default Outlook profile. It
uses the Outlook interop assembly to use the olFolderInBox enumeration.
It creates a custom object consisting of Subject, ReceivedTime, Importance,
SenderName for each InBox item.
*** Important *** depending on the size of your InBox items this function
may take several minutes to gather your InBox items. If you anticipate
doing multiple analysis of the data, you should consider storing the
results into a variable, and using that.
.Example
Get-OutlookInbox |
where { $_.ReceivedTime -gt [datetime]"5/5/11" -AND $_.ReceivedTime -lt `
[datetime]"5/10/11" } | sort importance
Displays Subject, ReceivedTime, Importance, SenderName for all InBox items that
are in InBox between 5/5/11 and 5/10/11 and sorts by importance of the email.
.Example
Get-OutlookInbox | Group-Object -Property SenderName | sort-Object Count
Displays Count, SenderName and grouping information for all InBox items. The most
frequently used contacts appear at bottom of list.
.Example
$InBox = Get-OutlookInbox
Stores Outlook InBox items into the $InBox variable for further
"offline" processing.
.Example
($InBox | Measure-Object).count
Displays the number of messages in InBox Items
.Example
$InBox | where { $_.subject -match '2011 Scripting Games' } |
sort ReceivedTime -Descending | select subject, ReceivedTime -last 5
Uses $InBox variable (previously created) and searches subject field
for the string '2011 Scripting Games' it then sorts by the date InBox.
This sort is descending which puts the oldest messages at bottom of list.
The Select-Object cmdlet is then used to choose only the subject and ReceivedTime
properties and then only the last five messages are displayed. These last
five messages are the five oldest messages that meet the string.
.Notes
NAME: Get-OutlookInbox
AUTHOR: ed wilson, msft
LASTEDIT: 05/13/2011 08:36:42
KEYWORDS: Microsoft Outlook, Office
HSG: HSG-05-26-2011
.Link
Http://www.ScriptingGuys.com/blog
#Requires -Version 2.0
#>
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)
$folder.items |
Select-Object -Property Subject, ReceivedTime, Importance, SenderName
} #end function Get-OutlookInbox

you could try adding a param block to your script so you can run something like "Get-OutlookInbox -Mailbox ". It would look something like this:
param (
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
Position=1)]
[string[]]$Mailbox=$env::USERNAME
)
So just to break it down a little, the actual name of the parameter is "Mailbox" and it is set to a default value that returns the current user running the script. You can override it by specifying one when you run the function. This will also accept a value from pipeline, meaning you can have an array of strings called "$aliases" and then run it like this: $aliases | Get-OutlookInbox

Related

Get email addresses from all Folders of my mailbox through powershell

How to get Email Addresses from All Folders of my mailbox through PowerShell
Thanks to following URL, please find code for InBox
https://stackoverflow.com/questions/44068261/get-email-items-from-mailboxes-through-powershell
I change following line to include Email Address
Select-Object -Property Subject, ReceivedTime, Importance, SenderName, SenderEmailAddress
but need help to get All Folders
Function Get-OutlookInBox
{
<#
.Synopsis
This function returns InBox items from default Outlook profile
.Description
This function returns InBox items from default Outlook profile. It
uses the Outlook interop assembly to use the olFolderInBox enumeration.
It creates a custom object consisting of Subject, ReceivedTime, Importance,
SenderName for each InBox item.
*** Important *** depending on the size of your InBox items this function
may take several minutes to gather your InBox items. If you anticipate
doing multiple analysis of the data, you should consider storing the
results into a variable, and using that.
.Example
Get-OutlookInbox |
where { $_.ReceivedTime -gt [datetime]"5/5/11" -AND $_.ReceivedTime -lt `
[datetime]"5/10/11" } | sort importance
Displays Subject, ReceivedTime, Importance, SenderName for all InBox items that
are in InBox between 5/5/11 and 5/10/11 and sorts by importance of the email.
.Example
Get-OutlookInbox | Group-Object -Property SenderName | sort-Object Count
Displays Count, SenderName and grouping information for all InBox items. The most
frequently used contacts appear at bottom of list.
.Example
$InBox = Get-OutlookInbox
Stores Outlook InBox items into the $InBox variable for further
"offline" processing.
.Example
($InBox | Measure-Object).count
Displays the number of messages in InBox Items
.Example
$InBox | where { $_.subject -match '2011 Scripting Games' } |
sort ReceivedTime -Descending | select subject, ReceivedTime -last 5
Uses $InBox variable (previously created) and searches subject field
for the string '2011 Scripting Games' it then sorts by the date InBox.
This sort is descending which puts the oldest messages at bottom of list.
The Select-Object cmdlet is then used to choose only the subject and ReceivedTime
properties and then only the last five messages are displayed. These last
five messages are the five oldest messages that meet the string.
.Notes
NAME: Get-OutlookInbox
AUTHOR: ed wilson, msft
LASTEDIT: 05/13/2011 08:36:42
KEYWORDS: Microsoft Outlook, Office
HSG: HSG-05-26-2011
.Link
Http://www.ScriptingGuys.com/blog
#Requires -Version 2.0
#>
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)
$folder.items |
Select-Object -Property Subject, ReceivedTime, Importance, SenderName, SenderEmailAddress
} #end function Get-OutlookInbox
I got help on InBox but need help to get all folders
Syntax for Get-MailboxFolder follow This link for more abou
Get-MailboxFolder
[[-Identity] <MailboxFolderIdParameter>]
[-Recurse]
[-DomainController <Fqdn>]
[-MailFolderOnly]
[-ResultSize <Unlimited>]
[<CommonParameters>]
Try this code apply your fields.
$DomainSuffix = Read-Host "Type the domain name suffix that you look for"
# Creating folder structure and file names for the exported CSV files
$A20 = "C:\INFO\E-mail address\Exchange Online\E-mail address with Domain suffix - $Domainsuffix"
if (!(Test-Path -path $A20))
{New-Item $A20 -type directory}
# Exchange Online infrastructure
# Define the variable for the different type of Exchange Online recipients
$AllRecipients = Get-Recipient -ResultSize unlimited| Where {$_.EmailAddresses -like "*#$DomainSuffix"}
$SoftDeleted = Get-Mailbox -SoftDeletedMailbox | Where {$_.EmailAddresses -like "*#$DomainSuffix"}
$UnifiedGroups = Get-UnifiedGroup | Where {$_.EmailAddresses -like "*#$DomainSuffix"}
if ($SoftDeleted -eq $null)
{
write-host "There are no Soft Deleted Exchange Online mailboxes that have an E-mail address with the domain name suffix - $DomainSuffix"
}
else
{
$SoftDeleted | Select DisplayName,EmailAddresses,RecipientType,RecipientTypeDetails | Export-CSV $A20\"Exchange Online Soft Deleted mailboxes that their E-mail address include the domain name suffix $DomainSuffix.CSV" –NoTypeInformation -Encoding utf8
}
if ($UnifiedGroups -eq $null)
{
write-host "There are no Exchange Online unified groups that have an E-mail address with the domain name suffix - $DomainSuffix"
}
Else
{
$UnifiedGroups | Select DisplayName,EmailAddresses,RecipientType,RecipientTypeDetails | Export-CSV $A20\"Exchange Online unified groups that their E-mail address include the domain name suffix $DomainSuffix.CSV" –NoTypeInformation -Encoding utf8
}
if ($AllRecipients -eq $null)
{
write-host "There are no Exchange Online Recipients that have an E-mail address with the domain name suffix - $DomainSuffix"
}
Else
{
$AllRecipients | Select DisplayName,EmailAddresses,RecipientType,RecipientTypeDetails | Export-CSV $A20\"Exchange Online recipients that their E-mail address include the domain name suffix $DomainSuffix.CSV" –NoTypeInformation -Encoding utf8
}
for reference follow this Site

Filter Get-MessageTrace log on EAC with Multiple Subjects

We use an Office365 email to send emails to multiple recipients. I was told to get the sent message logs and export them into a CSV format so our team can study which messages were delivered and which ones failed. Below I have put together a PowerShell script that connects to EAC and pulls the Sent Message logs for a particular account for the past 2 days. The script is working great however, I wanted to know if there is a way to only get emails with particular subjects. For example, I could use the code below to get the logs but it only filters the list for one subject. How can I filter this using multiple subjects such subject 1, 2, and 3.
$Subject = "Thank you for your business"
$Messages = $null
$Page = 1
do
{
Write-Host "Collecting Messages - Page $Page..."
$Messages = Get-MessageTrace -SenderAddress "no_reply#myCompany.com" -StartDate (Get-Date).AddDays(-2) -EndDate (Get-Date) -PageSize 5000 -Page $Page| Select Received,SenderAddress,RecipientAddress,Subject,Status
if ($myMessages -ne $null)
{
$myMessages | Where {$_.Subject -like $Subject} |Select-Object -Property Received, SenderAddress, RecipientAddress, Subject, Status | Export-Csv C:\Logs\Logs-$PAGE.csv -NoTypeInformation
}
$Page++
$Messages += $myMessages
}
until ($myMessages -eq $null)
Add the multiple subjects into your $subject variable to create a string array.
$Subject = #("Thank you for your business","hello","123","etc")
You can then use the Contains method of the array in the Where block like so.
Where {$Subject.Contains($_.Subject)}
This will filter the emails to only those match the subject exactly.

PowerShell/VBScript - Extract Outlook Mails Based on Condition

Is there a way to obtain list of all sent & received emails having suffix not equal to #gmail.com via PowerShell or VBScript and possibly store it in seperate text files.
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.getDefaultFolder($olFolders::olFolderSentMail)
$folder.items | Select-Object -Property Subject, SentOn, To
I was using the above PS to obtain sent mail, but not sure where to apply the condition.
Secondly, the subject is not appearing completely, it becomes ..... is there any way to obtain the full subject as well ?
I'm assuming you're running on a client computer not a server. If you've access to the exchange server there's powershell commandlets that are easy to use (New-MailboxExport).
$folder is a COM-Object
$folder.items property contains a collection of COM-Objects representing messages.
Since they're objects, you can use the object commands (Get-Help Object) to use their properties. You just need to dig a little more to apply your filter. Specifically one more level, to the properties of the items in $folder.items. Pipe $folder.items to Get-Member to get the full list of properties. $folder.items | gm. To, From, SentOn and Subject are all there.
$NonGmailMessages = $folder.items |
where-object { { $_.to -notcontains "gmail.com" } -and
{ $_.from -notcontains "gmail.com" } }
One way of handling collections like this is to do one massive filter like I just did. Or you can filter by stages.
$NonGmailMessages = $folder.items
$NonGmailMessages = $NonGmailMessages | where-object { { $_.to -notcontains "gmail.com" }
$NonGmailMessages = $NonGmailMessages | where-object { { $_.from -notcontains "gmail.com" }
Add further lines to further narrow your collection.
You can export this collection complete with all properties intact to a CSV:
$NonGmailMessages | Export-CSV -NoTypeInformation c:\temp\nonGmailMessages.csv
Or you can narrow the number of properties exported
$NonGmailMessages | Select-Object -Property From, To, SentOn, Subject | Export-CSV -NoTypeInformation c:\temp\nonGmailMessages.csv
-NoTypeInformation prevents the object type information from being listed at the start of the file. This will make it a more 'pure' CSV for use in PS or Excel or whatever. Plus the CSV IS a text based file format, as you wished.

Script to count number of emails for multiple users

I am needing a little help with my script. I have this working if I use just a single email address. I need to add a list of 8 emails addresses for this to scan. How would I modify this to send 1 email for all 8 users?
I have seen scripts that make a html file that displays everything in a nice table but those are ran against all users in exchange and I only needs this for a group of 8 users.
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
#Powershell blah blah blah
$nl = [Environment]::NewLine
#Mailbox to gather stats on
$mailboxs=$mailbox= 'user1#domain.com','user2#domain.com'
#Get todays
$startDate=Get-Date
$endDate=Get-Date
#Subtract 1 day from todays date (report ending day) and 1 day from todays date (report starting day)
$startDateFormatted=$startDate.AddDays(-1).ToShortDateString()
$endDateFormatted=$endDate.AddDays(-1).ToShortDateString()
foreach ($mailbox in $mailboxs)
{
# Sent e-mails
$sendCount = Get-TransportService | Get-MessageTrackingLog -Start "$startDateFormatted 00:00:00" -End "$endDateFormatted 23:59:59" -Sender $mailbox -resultsize unlimited | select-object -unique MessageId
# Received e-mails - This works but not on generic accounts
$receiveCount = Get-TransportService | Get-MessageTrackingLog -Start "$startDateFormatted 00:00:00" -End "$endDateFormatted 23:59:59" -Recipients $mailbox -resultsize unlimited | select-object -unique MessageId
$sendCountString = $sendCount.count
$receiveCountString = $receiveCount.count
}
$Output =
$Mailbox |
foreach {
$ResultHash =
#{
Address = $_
Sent = $Sendcountstring
Received = $Receivecountstring
}
New-Object -TypeName PSObject -Property $ResultHash |
Select Address,Sent,Received
}
#Who to send the e-mail report to.
#Multiple e-mail addresses should be in this format "<email1#domain.com>, <email2#domain.com>"
$MailParams = #{
From = "ISSReports#domain.com"
To = "user3#domain.com"
subject = "Daily e-mail report for ISS for $startDateFormatted"
BodyAsHTML = $true
smtpServer = "mail.domain.com"
}
$header =
#"
"Mailbox Stats
Report date range: $startDateFormatted 00:00:00 - $endDateFormatted 23:59:59
"#
$body = $Output | ConvertTo-Html -As Table -Head $header | out-string
Send-MailMessage #MailParams -Body $body
I put this together from your script and some pieces borrowed from a couple of my own. For this kind of reporting, you only need to read through the logs once, and you can eliminate the need to de-dupe by messageid by only returning the Deliver events. There will be one deliver event per email sent, containing both the sender and recipients.
#Mailboxs to gather stats on
$mailbox= 'user1#domain.com','user2#domain.com'
#Get todays date twice
$startDate=Get-Date
$endDate=Get-Date
#Hash tables for send and receive counts
$Sent = #{}
$Received = #{}
#Subtract 1 day from todays date (report ending day) and 1 days from todays date (report starting day)
$startDateFormatted=$startDate.AddDays(-1).ToShortDateString()
$endDateFormatted=$endDate.AddDays(-1).ToShortDateString()
$TransportServers = Get-ExchangeServer |
Where {$_.serverrole -match "hubtransport"} |
Select -ExpandProperty Name
foreach ($TransportServer in $TransportServers)
{
Get-MessageTrackingLog -Start "$startDateFormatted 00:00:00" -End "$endDateFormatted 23:59:59" -EventID Deliver -Server $TransportServer -ResultSize Unlimited |
foreach {
if ($mailbox -contains $_.sender )
{ $Sent[$_.Sender]++ }
foreach ($Recipient in $_.Recipients)
{
if ($mailbox -contains $Recipient )
{ $Received[$Recipient]++ }
}
}
}
$Output =
$Mailbox |
foreach {
$ResultHash =
#{
Address = $_
Sent = $Sent[$_]
Received = $Received[$_]
}
New-Object -TypeName PSObject -Property $ResultHash |
Select Address,Sent,Received
}
#Who to send the e-mail report to.
#Multiple e-mail addresses should be in this format "<email1#domain.com>, <email2#domain.com>"
$MailParams = #{
From = "ISSReports#domain.com"
To = "user3#domain.com"
subject = "Weekly e-mail report for $mailbox for $startDateFormatted - $endDateFormatted"
BodyAsHTML = $true
smtpServer = "mail.domain.com"
}
$header =
#"
"Mailbox Stats
Report date range: $startDateFormatted 00:00:00 - $endDateFormatted 23:59:59
"#
$body = $Output | ConvertTo-Html -As Table -Head $header | out-string
Send-MailMessage #MailParams -Body $body
For these 8 mailboxes you need a count of messages sent by that mailbox? This calls for 3 advanced functions:
count the mail
create a report
send the report
So, I see it like this (mostly pseudo-code):
Function Count-SentFromMbx {
#paramter $mailbox
#parameter $startdate
#parameter $enddate
# function counts sent mail per your working single user script
# or better yet, per mjolinor's script leveraging `-contains`
# build custom object with mailbox and count as properties
# or better yet, enough information to build a digest.
# return object/collection
}
# Create a function to format the results email
# Create a function to send the results email
# Define collection of mailboxes
$mailboxes = "blah#blah.com","blah2#blah.com",etc.
# define or get the dates
$startdate = whatever
$enddate = whatever
# initialize array for results
$results = #{}
# set other variables for storage of the report
# and for recipient list
# and anything else needed 'globally'
# Pull data from the logs:
$results += Count-SentFromMbx -mailbox $mailbox -startdate $startdate -enddate $enddate
# if you end up with a collection of collections, you may need to change to
# $results = ... and add a line like `$results | $reportData += $_`
# build report using report function
# send report using send function
The main idea I am suggesting is to use advanced functions (Get-Help about_advanced_functions) for each modular task involved in the process. Then you can leverage the power of objects to make gathering the data easy. You can tailor your reports for your audience by tweaking the reports function.
Having your function return an object, try $results | ConvertTo-Html. Bare minimum, if you have to build your own report, the collection of objects, $results, gives you an organized data source, easily passed through a foreach loop. Using objects you could even expand the collection to return message digests instead of just the number of messages sent. Instead of counting messages, create a custom object with subject, recipient and the sender. (Easy way to create object is to pipe objects to select with a customized property list). Return that collection and add it to the results collection. Then reporting could include message digests AND totals. The ability of objects to carry information gives you great flexibility.
One of the key things that mjolinor did was to put your 8 addresses in a collection. When looping through, you can compare if ($collection -contains $suspect) { do stuff}. This executes the block if the $suspect is in the $collection. This allows you to loop through the logs once.

How to create subset of data based on multiple matching field values in Powershell?

I have a powershell script that pulls emails using EWS managed API, reads their subject, from address, to address, and internetmessageheaders. Within the email read loop it loads all this information into a datatable.
I need to grab all the above information for each message and populate an array or datatable based on the from address. Then I'll check for relay information and send the whole list based on from address to a target address.
I can't seem to wrap my head around how to build the from address lists. I've tried turning the datatable data into a hashtable and then using a sort|get-unique to get a list of the unique from addresses but have not been able to use this information to correctly build the from address array. I've tried looping through using a select-string $_ -allmatches but haven't gotten anywhere.
Here is part of my code, It creates the datatable and populates it using information from each email.
$msgTable = New-Object system.Data.DataTable “Messages”
$col1 = New-Object system.Data.DataColumn Subject,([string])
$col2 = New-Object system.Data.DataColumn From,([string])
$col3 = New-Object system.Data.DataColumn To,([string])
$col4 = New-Object system.Data.DataColumn Relay,([string])
$msgTable.columns.add($col1)
$msgTable.columns.add($col2)
$msgTable.columns.add($col3)
$msgTable.columns.add($col4)
$frItemResult = $PublicFolder.FindItems($sfCollection,$view)
# Loop through view results and mark read
$frItemResult | ForEach-object{
if($_.HasAttachments ) {
$_.Load()
"Report Subject: $($_.Subject)"
# Loop through attachments, extract info
$_.Attachments | ForEach-object {
if($_.Name -notmatch "ATT00001"){
$_.Load($attPropset)
$row = $msgTable.NewRow();$row.Subject = $($_.item.Subject); $row.From = ($_.item.From.address); $row.To = $($_.item.ToRecipients.address); $row.Relay = "$($_.Item.InternetMessageHeaders | Where-Object {$_.name -like "*received*"})";$msgTable.Rows.Add($row)
Here is what $msgTable looks like after data is populated.
Subject From To Relay
------- ---- -- -----
Message1 user1#company.com recipient1#yahoo.com Received-SPF=pass (domain of ...
Message2 user2#company.com recipient2#comcast.net Received=from imta27.mailguys...
Message2 user2#company.com recipient3#yahoo.com Received-SPF=pass (domain of ...
Message3 user3#company.com recipient4#sbcglobal.net Received-SPF=pass (domain of ...
I need to be able to grep out all the information for user2#company.com to another variable and do the same for any number of other repeating or non-repeating from addresses.
I'll then take each of the from address variables and send it to the target recipient.
Any help is greatly appreciated.
Try using Group-Object, you can then run a foreach loop against each grouping:
$Grouping = $msgTable | Group-Object -Property From
foreach ($Group in $Grouping)
{
Write-Host $Group.Name -ForegroundColor "Green"
$Group.Group | ft -Auto
}
Cool exercise! This is how I would approach it...
...I need to be able to grep out all the information for
user2#company.com to another variable
$patternMatches = $msgTable | select-string -pattern 'user2#company.com'
...and do the same for any number of other repeating or non-repeating
from addresses.
$uniqueEmails = $msgTable | Select-Object From -Unique
foreach ($email in $uniqueEmails) {
$patternMatches = $msgTable | Select-Object -property * | select-string -pattern $email
}
I know this isn't exactly right, but it should push you into the right direction.