EWS Script: Reporting email items in the DiscoveryHolds folder located in RecoverableItems

Scenario:  You need to export a list of email items that are located in the DiscoveryHolds folder located in the RecoverableItems (Dumpster) of a Exchange Mailbox.  The report should include basic messaging information along with the Recipient email addresses. Note: If the message is a Draft (the isdraft property in the report) it may not have any of the common messaging information.

 

Scriptlet: Edit the #Variables.

#Finding items DiscoveryHolds in the RecoverableItems
#Variables
$cred = Get-credential  #credentials will fullaccess to access the mailbox
$mailboxname = “steve@domain.com”  #The Mailbox you wish to perform the query and restore on
$EWS_DLL = “C:Program FilesMicrosoftExchange ServerV15BinMicrosoft.Exchange.WebServices.dll”
$EWS_URL = “https://<your Exchange DNS namespace>/ews/exchange.asmx”
[datetime]$StartDate  = “6/26/2018” #Used for the LastModifiedTime
[datetime]$EndDate = “6/29/2018” #Used for the LastModifiedTime

#Configure connection to EWS
Import-Module -Name $EWS_DLL
$service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.Exchangeversion]::exchange2013)
$service.Url = new-object System.Uri($EWS_URL)
$service.UseDefaultCredentials = $false
$service.Credentials = $cred.GetNetworkCredential()

#Bind to the RootFolder
#$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::RecoverableItemsDeletions,$mailboxname)
#$Folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
#$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$mailboxname)
#$Folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)

$MailboxRootid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::RecoverableItemsRoot,$MailboxName)
$MailboxRoot=[Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$MailboxRootid)
#Find all folders in the mailbox
$FolderList = new-object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$FolderList.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
$findFolderResults = $MailboxRoot.FindFolders($FolderList)
$folder = $findFolderResults | Where displayname -like “DiscoveryHolds”

#Find Results for your Content Collection Filter
$sfCollection = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
$Sfgt = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsGreaterThan([Microsoft.Exchange.WebServices.Data.ItemSchema]::LastModifiedTime, $StartDate)
$Sflt = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThan([Microsoft.Exchange.WebServices.Data.ItemSchema]::LastModifiedTime, $EndDate)
$sfCollection.add($Sfgt)
$sfCollection.add($Sflt)
$view = new-object Microsoft.Exchange.WebServices.Data.ItemView(2000000)
$frFolderResult = $Folder.FindItems($sfCollection,$view)

#Enters the Recipient information into the $FrFolderResult Dataset
$ItemPropset = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
if ($frFolderResult.Items.Count -gt 0) {
[Void]$service.LoadPropertiesForItems($frFolderResult , $ItemPropset)
}

#Exporting with your Results
$frFolderResult | Select from,Sender,IsDraft,{$_.toRecipients},{$_.CCRecipients},{$_.BCCRecipients},Subject,DateTimeReceived,LastModifiedTime | Export-csv c:tempresult.csv

 

Error: “You cant use the domain because it’s not an accepted domain for your organization” when onboarding a mailbox to Exchange Online

Scenario:  You receive the following error message when you attempt to onboard a mailbox from Exchange On-Premises to Exchange Online:

“You cant use the domain because it’s not an accepted domain for your organization”

Solution:  Check their Email aliases (Get-mailbox steve | Select -expandproperty emailaddresses). The user account may have an invalid email alias OR an alias that is not an accepted domain for the Exchange Online tenant.  For Example,  the On-Prem mailbox may have an alias of  steve@xyz.com  but the @xyz.com is not an accepted domain in the cloud.  Either add that domain to the cloud OR remove the alias.

Disconnect Terminal Sessions via PowerShell on Remote ServersComputers

Scenario:  You want to disconnect all remote sessions on ServerComputers via PowerShell remotely.

Script:

#Disconnect Terminal Sessions via PowerShell################

#Gather the Servers in the $Servers Variable

$Servers = get-exchangeserver Exch* | Select -expandproperty Name

#Gather the Sessions
$TS = $Servers | %{
$computer = $_
quser /server:$computer 2>&1 | Select-Object -Skip 1 | ForEach-Object {
                $CurrentLine = $_.Trim() -Replace ‘s+’,’ ‘ -Split ‘s’
                $HashProps = @{
                    UserName = $CurrentLine[0]
                    ComputerName = $Computer
                }

                # If session is disconnected different fields will be selected
                if ($CurrentLine[2] -eq ‘Disc’) {
                        $HashProps.SessionName = $null
                        $HashProps.Id = $CurrentLine[1]
                        $HashProps.State = $CurrentLine[2]
                        $HashProps.IdleTime = $CurrentLine[3]
                        $HashProps.LogonTime = $CurrentLine[4..6] -join ‘ ‘
                        $HashProps.LogonTime = $CurrentLine[4..($CurrentLine.GetUpperBound(0))] -join ‘ ‘
                } else {
                        $HashProps.SessionName = $CurrentLine[1]
                        $HashProps.Id = $CurrentLine[2]
                        $HashProps.State = $CurrentLine[3]
                        $HashProps.IdleTime = $CurrentLine[4]
                        $HashProps.LogonTime = $CurrentLine[5..($CurrentLine.GetUpperBound(0))] -join ‘ ‘
                }

                New-Object -TypeName PSCustomObject -Property $HashProps | Select-Object -Property UserName,ComputerName,SessionName,Id,State,IdleTime,LogonTime,Error
                }

}

#Disconnect the Sessions
$TS | %{
    $id = $_.id
    $Name = $_.computerName
    $User = $_.Username
    rwinsta $ID /server:$name
    Write-Host “Session $Id for $User on $Name successfully disconnected”
}
#######################################################

 

“Can’t remove the access control entry on the object “CN=TestUser,DC=xyz,DC=com” for account “xyzsteve” because the ACE doesn’t exist on the object.”

Scenario:  You are attempting to remove the full access permission on a mailbox by running the remove-mailboxpermission command:

remove-mailboxpermission TestUser -user steve -accessrights Fullaccess -confirm:$False

But you are receiving this error :

Warning= “Can’t remove the access control entry on the object “CN=TestUser,DC=xyz,DC=com” for account “xyzsteve” because the ACE doesn’t exist on the object.”

Clearly the permission exists when you check with the get-mailboxpermission.

 

Solution:  Append the -deny:$True to the end of the powershell command and try it again.

remove-mailboxpermission TestUser -user steve -accessrights Fullaccess -confirm:$False -deny:$True

Get-ADUser to find Exchange Mailboxes

Scenario:  You want to use Get-ADUser to find all Exchange mailboxes in your environment.

Scriptlet:   Running the following will provide you with the detail:

#First, lets store some results into $1 for every mailbox
$1 = Get-ADUser -filter {HomeMDB -ne ‘$null’} -Properties MailNickName, HomeMDB, DisplayName| Select MailNickName, HomeMDB, DisplayName

 

#Now its time to play with your data

#Grab a count of mailboxes Excluding the HealthMailboxes
($1 | Where MailNickName -notlike “HealthMailbox*”).Count

#Grab a count of mailboxes per DB Excluding the HealthMailboxes
$1 | Where MailNickName -notlike “Healthmailbox*” | Group HomeMDB | Sort Name

#Filter mailboxes on a specific database
$1 | Where HomeMDB -like “CN=DB01*”

 

Cannot View Free/Busy information of user after Outlook 2016 client upgrade

Scenario:  After a Outlook client upgrade to 2016, you notice that you cannot view/alter the calendar of someone you have delegated permissions for in the Outlook client. OWA works fine and you can still view/alter the calendar through a Outlook 2013 client.

Resolution:  We found that the WindowsEmailAddress is:

  • Different than the PrimarySMTPAddress
  • not a email alias for the mailbox (The WindowsEmailAddress shows a alias that is not in the proxy addresses/Emailaddresses).

Change the WindowsEmailAddress to an address that matches the PrimarySMTPAddress (which is a alias/proxyaddress for the mailbox)

Set-Mailbox jdoe1 -windowsemailaddress <whatever the primarysmtpaddress is>

Get a list of all users that have a target address of a specific domain

Scenario:  You wish to see how many remote mailboxes have the correct email domain configured for their remote routing address (TargetAddress).  You want to perform a AD PowerShell query for speed.

Scriptlet:

Get-ADuser -filter {TargetAddress -like “*.mail.onmicrosoft.com”} | Select Name, TargetAddress

OR you just want a count:

(Get-ADuser -filter {TargetAddress -like “*.mail.onmicrosoft.com”} | Select Name, TargetAddress).count

Format the TLSCertificateName in a SendConnector so it uses the X.509 certificate value

Scenario:  You need to change the TLSCertificateName for the send connector because you recently upgraded your certificate.  (Get-sendconnector | Select Name, TLSCertificateName)

Solution: Perform the following steps:

#Pull the Cert Info into a Variable:

$TLSCert = Get-ExchangeCertificate -Thumbprint <Thumbprint> -server <Servername>

#Format the CertName so it an acceptable value for the TLSCertificateName property

$TLSCertName = “<I>$($TLSCert.Issuer)<S>$($TLSCert.Subject)”

#Set the TLSCertificateName for the send connector:

Set-SendConnector <Name of send connector> -TLSCertificateName $TLSCertName

 

 

 

 

 

Check MountPoints for Database

Scenario:  You use mountpoints in your Exchange organization and you want to check for specific disk information for your mountpoints by database name.   Note: The label of the mountpoint reflects the database name.

Script:

 

#Enter the DB Variable
$Db = "DB01"
#Script
$Servers = Get-mailboxdatabasecopystatus $DB | Select -ExpandProperty MailboxServer
$1 = @()
$Servers | %{
    "Checking on $_ for $Db"
    $1+= Invoke-Command -Computer $_ -argumentlist $db -ScriptBlock {Get-WmiObject win32_volume | Where label -like $args[0] | Select Name, Label, FreeSpace, FileSystem, SerialNumber}
}
#ViewResults
$1

 

Failure downloading upgrade list: received invalid update manifest response

Scenario:  When upgrading Cisco Email Security Appliances, you may run into the following error when upgrading from one OS to the next:

Error:  Failure downloading upgrade list: received invalid update manifest response

Solution: Check where the server is pointing to for pulling the list of updates:

Run the following commands via the CLI:

  • Updateconfig
  • dynamichost
  • update-manifests.sco.cisco.com:443
  • Commit