Search emails by subject using powershell - powershell

All,
I'm stuck at the following. I get list of emails in my inbox, and I need to search emails that contain specific string in subject (and then parse body of that email). I'm stuck at getting right syntax for filtering emails by subject.
I have this:
$Outlook = New-Object -comObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$emails = $inbox.items
$subjectComparisonExpression = "Meeting topic is: "
But then none of these work:
#1
$inbox.items | Where-Object {$_.Subject -like $subjectComparisonExpression} | Write-Host($_.Subject)
#2
$myemails = $inbox.items | Where-Object {$_.Subject -like $subjectComparisonExpression}
Write-Host($myemails.count)
#3
$myemails = $emails | Where {$_.Subject -like $subjectComparisonExpression}
Write-Host($myemails.count)
How do I get list of emails where subject contains $subjectComparisonExpression?

Use the Find/FindNext or Restrict methods of the Items class to find items that correspond to your conditions. The Restrict method is an alternative to using the Find method or FindNext method to iterate over specific items within a collection. The Find or FindNext methods are faster than filtering if there are a small number of items. The Restrict method is significantly faster if there is a large number of items in the collection, especially if only a few items in a large collection are expected to be found. You can read more about them in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder

Problem was with '-like' keyword. Replaced it with '-match' and it works.

Related

Powershell - How to filter an attachment before download

I am using a PowerShell script to download attachment from an email which has multiple attachment.
If I use below statement it will download all the attachments.
# Find Unread mail messages
$UnreadMessages = $Inbox.Items | where-object {$_.Unread -and $_.SenderEmailAddress -imatch "usa"}
I want to download only a specific attachment using below statement but it gives nothing.
# Find Unread mail messages
$UnreadMessages = $Inbox.Items | where-object {$_.Unread -and $_.SenderEmailAddress -imatch "usa" -and $_.Attachments -imatch "Backlog"}
Please help me correct this statement
Firstly, your code will cause all Inbox messages to be downloaded and processed by your script. This is like a SELECT statement in SQL without a WHERE clause - as bad as it gets performance wise.
Use Items.Find/FindNext or Items.Restrict (see https://learn.microsoft.com/en-us/office/vba/api/outlook.items.find) - let the server/message store do the work. For your first query, use
#SQL=("urn:schemas:httpmail:read" = 0) AND ("http://schemas.microsoft.com/mapi/proptag/0x0065001F" like '%usa%')
For the second query, OOM won't let you search on the attachment name even though Extended MAPI (C++ or Delphi only) exposes that functionality (create RES_SUBRESTRICTION on PR_MESSAGE_ATTACHMENTS and specify PR_ATTACH_LONG_FILENAME as the search property). You can of course use only your first query and loop over the query matches, for each entry looping through each Attachment object in the MailItem.Attachments collection - far from ideal, but still better than no restriction at all.
If using Redemption (I am its author - it is an Extended MAPI wrapper and can be used from any language) is an option, it allows to use Attachments in queries. Something like the following (off the top of my head, VBA):
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Folder = Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
set restrItems = Folder.Items.Restrict(" (UnRead = 'true') AND (""http://schemas.microsoft.com/mapi/proptag/0x0065001F"" like '%usa%') AND (Attachments LIKE '%Backlog%')")
for each item in restrItems
Debug.Print item.Subject
next

Export-Csv MIM FIM PowerShell Issue

I was asked to retrieve a .csv list with all users that registered to the FIM portal. I did some searching until I stumbled accross this script:
set-variable -name URI -value "http://localhost:5725/resourcemanagementservice' " -option constant
set-variable -name CSV -value "RegistredResetPassUsers.csv" -option constant
clear
If(#(Get-PSSnapin | Where-Object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {Add-PSSnapin FIMAutomation}
$WFDFilter = "/WorkflowDefinition[DisplayName='Password Reset AuthN Workflow']"
$curObjectWFD = export-fimconfig -uri $URI –onlyBaseResources -customconfig ($WFDFilter) -ErrorVariable Err -ErrorAction SilentlyContinue
$WFDObjectID = (($curObjectWFD.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "ObjectID"}).value).split(":")[2]
$Filter = "/Person[AuthNWFRegistered = '$WFDObjectID']"
$curObject = export-fimconfig -uri $URI –onlyBaseResources -customconfig ($Filter) -ErrorVariable Err -ErrorAction SilentlyContinue
[array]$users = $null
foreach($Object in $curObject)
{
$ResetPass = New-Object PSObject
$UserDisplayName = (($Object.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "DisplayName"}).Value)
$ResetPass | Add-Member NoteProperty "DisplayName" $UserDisplayName
$Users += $ResetPass
}
$users | export-csv -path $CSV
The script works without errors except that the actual list that it exports only contains my display name. I've been trying to figure out why its not exporting the complete list of all users and only shows my name, but I haven't been able to figure it out so I was wondering if any one could help me shed some light into this issue.
Thanks again for any help you guys can provide!
No experience with this snapin/product, but seeing as the code fundamentally works (it returns your object) this could be a permissions issue. You may not be able to read the other user objects, so they're not being exposed to you.
If you can view them in a UI console of some kind, then check for separate permissions related to API actions, and ensure you have access that way.
Another course of action may be to run the code line by line and see what results you receive from each line, to make sure you get what you're expecting.
Try replacing:
[array]$users = $null
With:
$users = #()
This is likely due to permission setup.
By default you have a permissions to see your own attributes.
There is likely some Management Policy Rule setup so user accounts in a specific Set can read AuthNWFRegistered attribute of other users to support for troubleshooting and customer support.
You will need to use one of the options:
Add the account used for this script into the Set that delegates out this Read permission already
or
Create a separate MPR for this particular reporting (this is what I would recommend) that Grants permissions for a specific user account to read AuthNWFRegistered attribute.
Also make sure there is really only one Workflow that is associated with user registration. If there are multiple, you'd want to target Set with all register Workflows in your XPath filter instead of particular Workflow name.
On a separate note - while FIMAutomation is sometimes necessary snapin to use with standard tooling, for your custom work I strongly suggest to use Lithnet's LithnetRMA PowerShell module (https://github.com/lithnet/resourcemanagement-powershell).
You will be much more productive with it and most of the operations will be without boilerplate code FIMAutomation needs. This will be your code using LithnetRMA.
Set-ResourceManagementClient -BaseAddress 'http://localhost:5725/resourcemanagementservice'
$scope = Search-Resources -XPath "/Person[AuthNWFRegistered = /WorkflowDefinition[DisplayName='Password Reset AuthN Workflow']]" -ExpectedObjectType Person
$scope | select DisplayName | Export-Csv 'RegistredResetPassUsers.csv' -Encoding Unicode

EWS Category search

i've a script on powershell to manage mailbox using EWS, however i'm not able to user the current filters and filter certain categories.
I would like filter categories that start by _ or * and apply to my current filters
$sfRead = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::IsRead, $True)
$WIPSubject = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject, "Assigned")
$sfNot = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+Not($WIPSubject)
$sfCollection = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$sfCollection.add($sfRead)
$sfCollection.add($sfNot)
If you want to do a wildcard search on the Subject then I would suggest that you use AQS for queries instead https://msdn.microsoft.com/en-us/library/office/dn579420(v=exchg.150).aspx . SearchFilters don't support wildcards you have the ContainsSubString filter which will find partial string matches https://msdn.microsoft.com/en-us/library/office/dd633645(v=exchg.80).aspx which is the closest.

Modify the array text condition in an Outlook rule with PowerShell?

I work on a team, who manage a few hundred servers. We each take primary responsibility for about 100 servers. I am the new person on the team, so I have a rule "MyServers" in outlook that makes a special sound and moves emails in to the folder "MyServers", when an email comes in with the name of one of my servers in the subject or body. Servers come and go, and the responsible person changes occasionally. I can use the GUI to modify the list, but what I want to do is use PowerShell to modify the list of servers based on a data set from a SQL query on our table of whom belongs to what. (also would be helpful when covering for someone else.)
Per PowerShell - Managing an Outlook Mailbox with PowerShell, By Joe Leibowitz, March 2013 it is possible in theory. That article and the post Hey, Scripting Guy! How Can I Tell Which Outlook Rules I Have Created? December 15, 2009 by ScriptingGuy1 have taught me how to get outlook files into PowerShell to read and or write. The post Multiple Actions for one Outlook rule in Powershell has also been helpful.
I can find several examples of creating rules, mostly around email addresses. As I did more research (below) it seems like the I want to modify 'TextRuleCondition.Text' but I am not finding any example code that gets in to reading OR modifying rule conditions for a single existing rule.
Specifying Rule Conditions
TextRuleCondition Object (Outlook)
TextRuleCondition.Text Property (Outlook)
Optimally: I would like to go to the "MyServers" rule and change the array, from what it is to a new array that I will build with PowerShell, after getting the list from a SQL table.
##source https://blogs.technet.microsoft.com/heyscriptingguy/2009/12/15/hey-scripting-guy-how-can-i-tell-which-outlook-rules-i-have-created/
## Gets outlook rules on PC
#Requires -version 2.0
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”)
$folder = $namespace.getDefaultFolder($olFolders::olFolderInbox)
$rules = $outlook.session.DefaultStore.<Some code here gets TextRuleCondition.Text for just MyServers>
$rules ## this displays the current value
##More code inserts the array that I built earlier (not actually built, yet as I don't know what it should look like)
$rules.Save() ## this saves the changes.
Everything I have found so far programmatically creates an entire new rule from PowerShell. Nothing indicates if it is, or is not possible to modify an existing rule. My Plan "B" would be to read the existing "MyServers" rule, modify the array, and overwrite the old rule with a new one. This is problematic as it limits options, only some conditions and actions can be created programmatically.
#setup
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”)
#get all of the rules
$rules = $outlook.Session.DefaultStore.GetRules()
#get just the rule I care about
$myRule = $rules | ? { $_.Name -eq 'My Awesome Rule' }
#build my new array of text conditions
$textValues = #('ServerA', 'NewServerB')
#replace the existing value on my rule (this is assuming you are using BodyOrSubject, you can substitute Body, Subject, etc)
$myRule.Conditions.BodyOrSubject.Text = $textValues
#save all the rules
$rules.save()

Unable to set Outlook email UnRead property to false via MAPI with Powershell

I don't appear to be able to write changes to Outlook via MAPI, the .UnRead variable is being set correctly to false within the script if you Write-Output it, but the variables don't appear to manipulate the actual .PST file. The select produces the correct emails, so read access to the .PST is fine.
Here is the code I am using to retrieve a list of unread emails from a PST folder, and set one of them to read:
$Outlook = new-object -comobject "Outlook.Application";
$Mapi = $Outlook.getnamespace("mapi");
$Pst = $Mapi.Folders.Item("Personal Folders")
$Folder = $Pst.Folders.Item("Test")
$Emails = $Folder.Items | Select UnRead, SenderEmailAddress, Subject, ReceivedTime, Body | Where {$_.Unread -eq "True"}
$Emails[1].UnRead = $false
Most examples I have seen say to place the variable in brackets, e.g.
$($Emails)[1].UnRead = $false
But this has made no difference for me.
Interestingly I get a 'method not found' error when I try to use the .delete() as well, hence I think I must be missing something.
Many thanks in advance for any advice.
Call MailItem.Save.
Do not loop through all items in a folder, use Items.Find/FindNext or Items.Restrict.
You've change property of your own object, but not on mail server