<# .Synopsis Remove text messaging configuration and inbox rules .Description Disable calendar notification, remove mobile devices added as a text messaging device and delete inbox rules that forward to a text messaging device. Works with Exchange 2010/2013/2016/EXO mailboxes. .Parameter EmailAddress Email address of the mailbox. Accepts pipeline input from Get-Mailbox. .Parameter EWSUrl To not use autodiscover, specify the URL to use for EWS. .Parameter Credential Provide credentials to use instead of the current user. .Parameter EWSApiPath Explicit path to EWS API DLL if it has not been installed via setup routine. .Parameter UseImpersonation Switch to specify connection to the mailbox via impersonation instead of full mailbox access. .Parameter UseExchangeOnline Switch to use the hard-coded EWS URL for Exchange Online. Cannot be used with the EWSUrl parameter. .Example Remove-TextMessagingConfiguration.ps1 -EmailAddress johndoe@company.com -Credential (get-credential) .Example Get-Mailbox johndoe | Remove-TextMessagingConfiguration -EWSUrl -UseImpersonation .Notes Version: 1.3 Date: 1/24/17 #>
#requires -version 3
[CmdletBinding(DefaultParameterSetName='autod')]
param
(
[parameter(Mandatory=$true,Position=0,ValueFromPipelinebyPropertyName=$true)][Alias('PrimarySMTPAddress')]$EmailAddress,
[parameter(Mandatory=$false,ParameterSetName='ews')][string]$EWSUrl,
[parameter(Mandatory=$false,ParameterSetName='exo')][switch]$UseExchangeOnline,
[parameter(Mandatory=$false)][pscredential]$Credential,
[parameter(Mandatory=$false)][string]$EWSApiPath,
[switch]$UseImpersonation
)
begin
{
$firstRun = $true
function Get-UserConfigurationMessage ($targetAddress, $className, $impersonate)
{
if ($impersonate)
{
$exchangeService.ImpersonatedUserId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $targetAddress)
}
#Bind to root of mailbox and return FAI with configuration class of specified name
$folderId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$targetAddress)
[Microsoft.Exchange.WebServices.Data.UserConfiguration]::Bind($exchangeService, $className, $folderId, [Microsoft.Exchange.WebServices.Data.UserConfigurationProperties]::All)
}
function Get-Rules ($targetAddress, $impersonate)
{
if ($impersonate)
{
$exchangeService.ImpersonatedUserId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $targetAddress)
}
#Search inbox for rule messages
$folderId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$targetAddress)
#Message class on 2013+
$searchFilter1 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass, 'IPM.Rule.Version2.Message')
#Message class on 2010
$searchFilter2 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass, 'IPM.Rule.Message')
$searchFilterCollection = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::Or)
$searchFilterCollection.Add($searchFilter1)
$searchFilterCollection.Add($searchFilter2)
$itemView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ItemView(100)
$itemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
,$exchangeService.FindItems($folderId, $searchFilterCollection, $itemView)
}
function Convert-XmlToString ($xml)
{
$sw = New-Object -TypeName System.IO.StringWriter
$xmlSettings = New-Object -TypeName System.Xml.XmlWriterSettings
$xmlSettings.ConformanceLevel = [System.Xml.ConformanceLevel]::Fragment
$xmlSettings.Indent = $true
$xw = [System.Xml.XmlWriter]::Create($sw, $xmlSettings)
$xml.WriteTo($xw)
$xw.Close()
$sw.ToString()
}
function Convert-StringToByteArray ($string)
{
$byteArray = New-Object -TypeName Byte[] -ArgumentList $string.Length
$i = 0
foreach ($char in $string.ToCharArray())
{
$byteArray[$i] = [byte]$char
$i++
}
,$byteArray
}
}
process
{
if ($firstRun)
{
#Test if any version of API is installed before continuing
if ($EWSApiPath)
{$apiPath = $EWSApiPath}
else
{
$apiPath = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services' |
Sort-Object Name -Descending | Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + 'Microsoft.Exchange.WebServices.dll')
}
if (Test-Path $apiPath)
{
Add-Type -Path $apiPath
}
else
{
Write-Error "The Exchange Web Services Managed API is required to use this script." -Category NotInstalled
break
}
$exchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$exchangeService = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExchangeService($exchangeVersion)
if ($Credential)
{
$exchangeService.Credentials = New-Object -TypeName Microsoft.Exchange.WebServices.Data.WebCredentials($Credential)
}
$firstRun = $false
}
if ($EWSUrl)
{
$exchangeService.Url = $EWSUrl
}
elseif ($UseExchangeOnline)
{
$exchangeService.Url = 'https://outlook.office365.com/ews/Exchange.asmx'
}
else
{
$exchangeService.AutodiscoverUrl($EmailAddress, {$true})
}
#Create custom object to hold results
$output = "" | Select-Object 'EmailAddress','CalendarNotify','TextConfiguration','InboxRules'
$output.EmailAddress = $EmailAddress
#Get calendar notification settings
try
{
$calNotify = Get-UserConfigurationMessage -targetAddress $EmailAddress -className 'CalendarNotification.001' -impersonate $UseImpersonation
#Convert binary property to XML
[xml]$calStream = [System.Text.Encoding]::ASCII.GetString($calNotify.XmlData)
#Disable the three notification types
$notifyEnabled = $false
if ($calStream.CalendarNotificationSettings.UpdateSettings.Enabled -eq 'true')
{
$calStream.CalendarNotificationSettings.UpdateSettings.Enabled = 'false'
$notifyEnabled = $true
}
if ($calStream.CalendarNotificationSettings.ReminderSettings.Enabled -eq 'true')
{
$calStream.CalendarNotificationSettings.ReminderSettings.Enabled = 'false'
$notifyEnabled = $true
}
if ($calStream.CalendarNotificationSettings.SummarySettings.Enabled -eq 'true')
{
$calStream.CalendarNotificationSettings.SummarySettings.Enabled = 'false'
$notifyEnabled = $true
}
if ($notifyEnabled)
{
#Convert XML back to binary and save
$calNotify.xmlData = Convert-StringToByteArray -string (Convert-XmlToString -xml $calStream)
$calNotify.Update()
$output.CalendarNotify = 'Deleted'
}
else
{
$output.CalendarNotify = 'NotConfigured'
}
}
catch
{
if ($error[0].Exception -like '*The specified object was not found in the store.*')
{
$output.CalendarNotify = 'NotFound'
}
else
{
$output.CalendarNotify = 'Error'
}
}
#Get text messaging settings
try
{
$textConfig = Get-UserConfigurationMessage -targetAddress $EmailAddress -className 'TextMessaging.001' -impersonate $UseImpersonation
#Convert binary property to XML
[xml]$textStream = [System.Text.Encoding]::ASCII.GetString($textConfig.xmldata)
if ($textStream.TextMessagingSettings.MachineToPersonMessagingPolicies.PossibleRecipient)
{
$xpath = '//MachineToPersonMessagingPolicies' #Node name that contains devices
#Remove any defined mobile devices
$textStream.SelectSingleNode($xpath).RemoveAll()
#Convert XML back to binary and save
$textConfig.xmlData = Convert-StringToByteArray -string (Convert-XmlToString -xml $textStream)
$textConfig.Update()
$output.TextConfiguration = 'Deleted'
}
else
{
$output.TextConfiguration = 'NotConfigured'
}
}
catch
{
if ($error[0].Exception -like '*The specified object was not found in the store.*')
{
$output.TextConfiguration = 'NotFound'
}
else
{
$output.TextConfiguration = 'Error'
}
}
#Check for inbox rules that forward to mobile device
try
{
$inboxRules = Get-Rules -targetAddress $EmailAddress -impersonate $UseImpersonation
if ($inboxRules.Count -gt 0)
{
#Get property for 2013+ version rules that contains rule actions
$propExtRuleActionsV2 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x0E99,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)
#Get property for 2010 version rules that contains rule actions
$propExtRuleActionsV1 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x65EF,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)
$propertySet = New-Object -TypeName Microsoft.Exchange.WebServices.Data.PropertySet(@($propExtRuleActionsV2,$propExtRuleActionsV1))
[void]$exchangeService.LoadPropertiesForItems($inboxRules, $propertySet)
$matchingRule = $false
foreach ($rule in $inboxRules.Items)
{
$ruleActionsV2 = $null
$ruleActionsV1 = $null
if ($rule.TryGetProperty($propExtRuleActionsV2,[ref]$ruleActionsV2))
{
#Convert from binary and look for string that indicates forwarding to device
if ([System.Text.Encoding]::ASCII.GetString($ruleActionsV2) -like '*MOBILE:*')
{
$rule.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
$matchingRule = $true
$output.InboxRules = 'Deleted'
continue
}
}
elseif ($rule.TryGetProperty($propExtRuleActionsV1,[ref]$ruleActionsV1))
{
#Convert from binary and look for string that indicates forwarding to device
if ([System.Text.Encoding]::ASCII.GetString($ruleActionsV1) -like '*MOBILE:*')
{
$rule.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
$matchingRule = $true
$output.InboxRules = 'Deleted'
}
}
}
if (-not($matchingRule))
{
$output.InboxRules = 'NotConfigured'
}
}
else
{
$output.InboxRules = 'NotConfigured'
}
}
catch
{
$output.InboxRules = 'Error'
}
$output
}