functions/User/Get-HawkUserHiddenRule.ps1
Function Get-HawkUserHiddenRule { <# .SYNOPSIS Pulls inbox rules for the specified user using EWS. .DESCRIPTION Pulls inbox rules for the specified user using EWS. Searches the resulting rules looking for "hidden" rules. Requires impersonation: https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-configure-impersonation Since the rules are hidden we have to pull it as a message instead of a rule. That means that the only information we can get back is the ID and Priority of the rule. Once a mailbox has been identified as having a hidden rule please use MFCMapi to review and remove the rule as needed. https://blogs.msdn.microsoft.com/hkong/2015/02/27/how-to-delete-corrupted-hidden-inbox-rules-from-a-mailbox-using-mfcmapi/ .PARAMETER UserPrincipalName Single UPN of a user, comma separated list of UPNs, or array of objects that contain UPNs. .PARAMETER EWSCredential Credentials of a user that can impersonate the target user/users. Gather using (get-credential) Does NOT work with MFA protected accounts at this time. .OUTPUTS File: _Investigate.txt Path: \ Description: Adds any hidden rules found here to be investigated File: EWS_Inbox_rule.csv Path: \<User> Description: Inbox rules that were found with EWS .EXAMPLE Get-HawkUserHiddenRule -UserPrincipalName user@contoso.com -EWSCredential (get-credential) Searches user@contoso.com looking for hidden inbox rules using the provided credentials .EXAMPLE Get-HawkUserHiddenRule -UserPrincipalName (get-mailbox -Filter {Customattribute1 -eq "C-level"}) Looks for hidden inbox rules for all users who have "C-Level" set in CustomAttribute1 #> param ( [Parameter(Mandatory = $true)] [array]$UserPrincipalName, [System.Management.Automation.PSCredential]$EWSCredential ) Test-EXOConnection Send-AIEvent -Event "CmdRun" # Verify our UPN input [array]$UserArray = Test-UserObject -ToTest $UserPrincipalName # Process each object received foreach ($Object in $UserArray) { # Push the UPN into $user for ease of use $user = $Object.UserPrincipalName # Determine if the email address is null or empty [string]$EmailAddress = (Get-EXOMailbox $user).PrimarySmtpAddress if ([string]::IsNullOrEmpty($EmailAddress)) { Write-Warning "No SMTP Address found. Skipping." return $null } # If we don't have a credential object, ask for credentials if ($null -eq $EWSCredential) { Out-LogFile "Please provide credentials that have impersonation rights to the mailbox you are looking to check" -Information $EWSCredential = Get-Credential } # Import the EWS Managed API if (Test-Path 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll') { Out-LogFile "EWS Managed API Found" -Information } else { Write-Error "Please install EWS Managed API 2.2 `nhttp://www.microsoft.com/en-us/download/details.aspx?id=42951" -ErrorAction Stop } # Import the EWS Managed API DLL Import-Module 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll' # Set up the EWS Connection Write-Information ("Setting up connection for " + $EmailAddress) $exchService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_Sp1) $exchService.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($EWSCredential.Username, $EWSCredential.GetNetworkCredential().Password) # Autodiscover or use global EWS URL if ($null -eq $EWSUrl) { $exchService.AutodiscoverUrl($EmailAddress, { $true }) $exchService.Url | Set-Variable -Name EWSUrl -Scope Global } else { $exchService.Url = $EWSUrl } # Set impersonation $exchService.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress) # Add the Anchor mailbox to the HTTP header $exchService.HttpHeaders.Add("X-AnchorMailbox", [string]$EmailAddress) # Search for hidden rules $SearchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, "IPM.Rule.Version2.Message") $ItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(500) $ItemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated # Create our property set to view $PR_RULE_MSG_NAME = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x65EC, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String) $PR_RULE_MSG_PROVIDER = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x65EB, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String) $PR_PRIORITY = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x0026, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer) $psPropset = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IDOnly, $PR_RULE_MSG_NAME, $PR_RULE_MSG_PROVIDER, $PR_PRIORITY) # Add the property set to the item view $ItemView.PropertySet = $psPropset # Do the search and return the items $ruleResults = $inbox.FindItems($SearchFilter, $ItemView) # Check each rule directly from $ruleResults $FoundHidden = $false foreach ($rule in $ruleResults) { if ([string]::IsNullOrEmpty($rule.ExtendedProperties[0].Value) -or [string]::IsNullOrEmpty($rule.ExtendedProperties[1].Value)) { $priority = ($rule.ExtendedProperties | Where-Object { $_.PropertyDefinition.Tag -eq 38 }).Value Out-LogFile ("Possible Hidden Rule found in mailbox: " + $EmailAddress + " -- Rule Priority: " + $priority) -Notice $RuleOutput = $rule | Select-Object -Property ID, @{ Name = "Priority"; Expression = { ($rule.ExtendedProperties | Where-Object { $_.PropertyDefinition -like "*38*" }).Value } } $RuleOutput | Out-MultipleFileType -FilePrefix "EWS_Inbox_rule" -Txt -User $user -Append $FoundHidden = $true } } # Log if no hidden rules are found if ($FoundHidden -eq $false) { Out-LogFile ("No Hidden rules found for mailbox: " + $EmailAddress) -Information } } } |