Exchange cmdlets in PowerShell ISE

My colleague made me happy when he described an easy procedure how to import Exchange cmdlets into PowerShell ISE so let me share it here.

  1. Connect to an Exchange server, run Exchange Management Shell and find folder location for Exchange cmdlets by Get-Module and path property.
    8- 10- 2015 7-38-56
  2. Copy the folder to C:\Windows\System32\WindowsPowerShell\v1.0\Modules on your local PC
  3. Restart PowerShell ISE

NirSoft utilities (portable)

Hi, I had to investigate issue at Citrix side without possibility to install troubleshooting tools like Fiddler or Wireshark and I had success to find NirSoft utilities so collection of small and freeware utilities in portable form, hm I would say really nice thing…

http://www.nirsoft.net/utils/index.html

10- 6- 2015 22-55-57

PowerShell Tip: Get string array from your list

Very easy procedure how to get string array from listed items from somewhere (e.g. txt file).

Well, run PS, declare a variable like $something=” paste your lines then close it by ” and convert it into the array $something=something.split(“`n”)

26- 5- 2015 22-31-55

26- 5- 2015 22-28-41

Of course there are a lot of other possibilities how to declare the same array e.g. $array = @(“10.10.10.26″,”10.10.10.35″,”10.10.10.44”), but anyway the paste option is useful thing ;).

Remote Migration And (500) Internal Server Error

Experience with Exchange 2010 based hybrid and the following remote migration failure (move requests/test cmdlet):

  • Microsoft.Exchange.Migration.MigrationServerConnectionFailedException: The connection to the serve
    r ‘mail.ficility.net’ could not be completed. —> Microsoft.Exchange.MailboxReplicationService.Remote
    TransientException: The Mailbox Replication Service could not connect to the remote server because
    the remote server encountered an internal error.
  • The remote server returned an error: (500) Internal Server Error.. –> The content type
    text/html of the response message does not match the content type of the binding (application/soap
    +xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is
    implemented properly.
PS C:\> Test-MigrationServerAvailability -ExchangeRemoteMove -RemoteServer mail.ficility.net -Credentials $GetOnpremCred

RunspaceId : 4da526a1-2d3a-4ec7-b484-c39e436c4bcc
Result : Failed
Message : The connection to the server 'mail.ficility.net' could not be completed.
ConnectionSettings :
SupportsCutover : False
ErrorDetail : Microsoft.Exchange.Migration.MigrationServerConnectionFailedException: The connection to the serve
 r 'mail.ficility.net' could not be completed. ---> Microsoft.Exchange.MailboxReplicationService.Remote
 TransientException: The Mailbox Replication Service could not connect to the remote server because
 the remote server encountered an internal error. The call to 'https://mail.ficility.net/EWS/mrsproxy.
 svc' failed. Error details: The content type text/html of the response message does not match the
 content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder, be s
 ure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the re
 sponse were: '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <HTML dir=ltr><HEAD><TITLE>The page cannot be displayed</TITLE>
 <STYLE id=L_defaultr_1>A:link {
 FONT: 8pt/11pt verdana; COLOR: #ff0000
 }
 A:visited {
 FONT: 8pt/11pt verdana; COLOR: #4e4e4e
 }
 </STYLE>
 <META content=NOINDEX name=ROBOTS>
 <META http-equiv=Content-Type content="text-html; charset=UTF-8">
 <META content="MSHTML 5.50.4522.1800" name=GENERATOR></HEAD>
 <BODY bgColor=#ffffff>
 <TABLE cellSpacing=5 cellPadding=3 width=410>
 <TBODY>
 <TR>
 <TD id=L_defaultr_0 valign=middle align=left width=360>
 <H1 id=L_defaultr_2 style="FONT: 13pt/15pt verdana; COLOR: #000000"><ID id=L_defaultr_3><!--
 Problem-->The page cannot be displayed
 </ID></H1></TD></TR>
 <TR>
 <TD width=400 colSpan=2><FONT id=L_defaultr_4
 style="FONT: 8pt/11pt verdana; COLOR: #000000"><ID id=L_defaultr_5><B>Explanation: </B>There
 is a problem with the page you are trying to reach and it cannot be displayed.</ID></FONT></TD></
 TR>
 <TR>
 '. --> The remote server returned an error: (500) Internal Server Error.. --> The content type
 text/html of the response message does not match the content type of the binding (application/soap
 +xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is
 implemented properly. The first 1024 bytes of the response were: '<!DOCTYPE HTML PUBLIC "-//W3C//
 DTD HTML 4.0 Transitional//EN">
 <HTML dir=ltr><HEAD><TITLE>The page cannot be displayed</TITLE>
 <STYLE id=L_defaultr_1>A:link {
 FONT: 8pt/11pt verdana; COLOR: #ff0000
 }
 A:visited {
 FONT: 8pt/11pt verdana; COLOR: #4e4e4e
 }
 </STYLE>
 <META content=NOINDEX name=ROBOTS>
 <META http-equiv=Content-Type content="text-html; charset=UTF-8">
 <META content="MSHTML 5.50.4522.1800" name=GENERATOR></HEAD>
 <BODY bgColor=#ffffff>
 <TABLE cellSpacing=5 cellPadding=3 width=410>
 <TBODY>
 <TR>
 <TD id=L_defaultr_0 valign=middle align=left width=360>
 <H1 id=L_defaultr_2 style="FONT: 13pt/15pt verdana; COLOR: #000000"><ID id=L_defaultr_3><!--
 Problem-->The page cannot be displayed
 </ID></H1></TD></TR>
 <TR>
 <TD width=400 colSpan=2><FONT id=L_defaultr_4
 style="FONT: 8pt/11pt verdana; COLOR: #000000"><ID id=L_defaultr_5><B>Explanation: </B>There
 is a problem with the page you are trying to reach and it cannot be displayed.</ID></FONT></TD></
 TR>
 <TR>
 '. --> The remote server returned an error: (500) Internal Server Error. ---> Microsoft.Exchang
 e.MailboxReplicationService.RemoteTransientException: The call to 'https://mail.ficility.net/EWS/mrspr
 oxy.svc' failed. Error details: The content type text/html of the response message does not match
 the content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder,
 be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of th
 e response were: '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <HTML dir=ltr><HEAD><TITLE>The page cannot be displayed</TITLE>
 <STYLE id=L_defaultr_1>A:link {
 FONT: 8pt/11pt verdana; COLOR: #ff0000
 }
 A:visited {
 FONT: 8pt/11pt verdana; COLOR: #4e4e4e
 }
 </STYLE>
 <META content=NOINDEX name=ROBOTS>
 <META http-equiv=Content-Type content="text-html; charset=UTF-8">
 <META content="MSHTML 5.50.4522.1800" name=GENERATOR></HEAD>
 <BODY bgColor=#ffffff>
 <TABLE cellSpacing=5 cellPadding=3 width=410>
 <TBODY>
 <TR>
 <TD id=L_defaultr_0 valign=middle align=left width=360>
 <H1 id=L_defaultr_2 style="FONT: 13pt/15pt verdana; COLOR: #000000"><ID id=L_defaultr_3><!--
 Problem-->The page cannot be displayed
 </ID></H1></TD></TR>
 <TR>
 <TD width=400 colSpan=2><FONT id=L_defaultr_4
 style="FONT: 8pt/11pt verdana; COLOR: #000000"><ID id=L_defaultr_5><B>Explanation: </B>There
 is a problem with the page you are trying to reach and it cannot be displayed.</ID></FONT></TD></
 TR>
 <TR>
 '. --> The remote server returned an error: (500) Internal Server Error.. ---> Microsoft.Exchan
 ge.MailboxReplicationService.RemotePermanentException: The content type text/html of the response
 message does not match the content type of the binding (application/soap+xml; charset=utf-8). If u
 sing a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The
 first 1024 bytes of the response were: '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional/
 /EN">
 <HTML dir=ltr><HEAD><TITLE>The page cannot be displayed</TITLE>
 <STYLE id=L_defaultr_1>A:link {
 FONT: 8pt/11pt verdana; COLOR: #ff0000
 }
 A:visited {
 FONT: 8pt/11pt verdana; COLOR: #4e4e4e
 }
 </STYLE>
 <META content=NOINDEX name=ROBOTS>
 <META http-equiv=Content-Type content="text-html; charset=UTF-8">
 <META content="MSHTML 5.50.4522.1800" name=GENERATOR></HEAD>
 <BODY bgColor=#ffffff>
 <TABLE cellSpacing=5 cellPadding=3 width=410>
 <TBODY>
 <TR>
 <TD id=L_defaultr_0 valign=middle align=left width=360>
 <H1 id=L_defaultr_2 style="FONT: 13pt/15pt verdana; COLOR: #000000"><ID id=L_defaultr_3><!--
 Problem-->The page cannot be displayed
 </ID></H1></TD></TR>
 <TR>
 <TD width=400 colSpan=2><FONT id=L_defaultr_4
 style="FONT: 8pt/11pt verdana; COLOR: #000000"><ID id=L_defaultr_5><B>Explanation: </B>There
 is a problem with the page you are trying to reach and it cannot be displayed.</ID></FONT></TD></
 TR>
 <TR>
 '. ---> Microsoft.Exchange.MailboxReplicationService.RemotePermanentException: The remote serve
 r returned an error: (500) Internal Server Error.
 --- End of inner exception stack trace ---
 --- End of inner exception stack trace ---
 --- End of inner exception stack trace ---
 at Microsoft.Exchange.MailboxReplicationService.MailboxReplicationServiceFault.<>c__DisplayClas
 s1.<ReconstructAndThrow>b__0()
 at Microsoft.Exchange.MailboxReplicationService.ExecutionContext.Execute(Action operation)
 at Microsoft.Exchange.MailboxReplicationService.MailboxReplicationServiceFault.ReconstructAndTh
 row(String serverName, VersionInformation serverVersion)
 at Microsoft.Exchange.MailboxReplicationService.WcfClientWithFaultHandling`2.<>c__DisplayClass1
 .<CallService>b__0()
 at Microsoft.Exchange.Net.WcfClientBase`1.CallService(Action serviceCall, String context)
 at Microsoft.Exchange.Migration.MigrationExchangeProxyRpcClient.CanConnectToMrsProxy(Fqdn serve
 rName, Guid mbxGuid, NetworkCredential credentials, LocalizedException& error)
 --- End of inner exception stack trace ---
 at Microsoft.Exchange.Migration.DataAccessLayer.ExchangeRemoteMoveEndpoint.VerifyConnectivity()
 at Microsoft.Exchange.Management.Migration.TestMigrationServerAvailability.InternalProcessEndpo
 int(Boolean fromAutoDiscover)
IsValid : True
Identity :
ObjectState : New

Reason:

Mail.ficility.net pointed to TMG with enabled custom web security filter.

TMG:

26- 5- 2015 22-17-08

The filter disabled and then:

PS C:\> Test-MigrationServerAvailability -ExchangeRemoteMove -RemoteServer mail.ficility.net -Credentials $GetOnpremCred

RunspaceId : 0e75133c-e53f-4dec-86cb-f87eb68bbf5c
Result : Success
Message :
ConnectionSettings : <ExchangeConnectionSettings HasAdminPrivilege="True" HasAutodiscovery="False" HasMrsProxy="True" A
 utodiscoverUrl="" IncomingEmailAddress="" IncomingRPCProxyServer="mail.ficility.net" IncomingExchangeS
 erver="mail.ficility.net" IncomingNSPIServer="" IncomingDomain="europe" IncomingUserName="x98490" Encr
 yptedIncomingPassword="AAAAAQXEWAAEEC2a321JsEZNpm0sI75meOsGCWCGSAFlAwQCAQYJYIZIAWUDBAIBBglghkgBZQM
 EAQIEIH0n3HnypPK+ASyxgq4uJEXHwgGP7SSaO0gnsudrdL+wBBCEzLR+aCScgC21Yo5AUc3eIEBhgAiNca5RquKktuEWNqZZc
 4oJHPOZXfz6RRUrYMZaWd5M/XPUawKeIdj10bPj/W0xvzt5R2hsHyYsj1wd4dLq" IncomingAuthentication="Basic" Se
 rverVersion="" TargetDomainName="" SourceMailboxLegDn="" PublicFolderDatabaseServerLegacyDN="" />
SupportsCutover : False
ErrorDetail :
IsValid : True
Identity :
ObjectState : New

The counter list and portability (read I/O operations)

An ExRAAP scanning detected this issue “The read I/O operations latency is greater than expected for an Exchange database” with an advice I started to monitor related performance counters according to post Analysing Exchange Server 2010 Jetstress BLG Files By Hand which contains also the following table:

7- 8- 2014 12-15-22Time to time I needed to check read I/O operations without a Data Collector Set, but I did not want to have the counter list/settings dependent on particular server (i.e. the server below hosts mailbox database MDB01 or MDB05 but not MDB02 and I want to have counters for all of them and I do not mind that some counter will not work).

7- 8- 2014 12-03-147- 8- 2014 12-44-28Well, I saved the settings from the server into HTML file and modify its content for 18 databases.

  • Changing value: <PARAM NAME=”CounterCount” VALUE=”18″/>
  • Adding parameters for missing databases (be careful you have to always use unique PARAM NAME):7- 8- 2014 12-59-42After that I could check the latency by pasting the same counter list on any server.

7- 8- 2014 13-12-18

 

Exchange Cmdlet Statistics

You can use administrator audit logging in Microsoft Exchange Server to record actions taken by a user or administrator that make changes in your organization. By keeping a log of the changes, you can trace a change to the person who made it. You can also augment your change logs with detailed records of the change as it was implemented, use the records to comply with regulatory requirements and requests for discovery, and so on…. [source].

Yes, yes, the auditing is very useful. But I wanted to show you how could look a cmdlet statistic for a month:

PS C:\> Search-AdminAuditLog -StartDate $(get-date).addMonths(-1) -ResultSize 100000 -IsSuccess $true|select CmdletName|
group CmdletName|sort count -Descending|ft count,name -a

Count Name
----- ----
12318 Set-MailboxFolderPermission
12307 Set-CalendarProcessing
 8752 Set-MailboxAutoReplyConfiguration
 5860 Set-Mailbox
  678 Add-MailboxFolderPermission
  645 Set-User
  174 Add-DistributionGroupMember
  163 Add-MailboxPermission
  126 Remove-DistributionGroupMember
   98 Remove-MailboxFolderPermission
   89 Add-ADPermission
   84 Remove-MailboxPermission
   71 Enable-Mailbox
   26 Set-InboxRule
   24 Set-DistributionGroup
   18 Clean-MailboxDatabase
   16 Remove-ADPermission
   16 Remove-Mailbox
   16 Set-CASMailbox
    8 New-MailContact
    6 Remove-ActiveSyncDevice
    6 Disable-Mailbox
    5 Remove-MailContact
    4 New-DistributionGroup
    3 New-InboxRule
    2 Remove-AcceptedDomain
    2 Enable-DistributionGroup
    2 Set-SendConnector
    1 Update-Recipient
    1 New-MoveRequest
    1 Update-MovedMailbox
    1 Add-PublicFolderClientPermission
    1 New-SendConnector
    1 Remove-DistributionGroup
    1 New-MailboxSearch
    1 Disable-InboxRule
    1 Remove-InboxRule

Note: Cmdlets that begin with the verb Test, Get and Search aren’t logged by default.

Connect-Mailbox and AllowLagacyDNMismatch

I have solved a one case where we wanted to connect (Use the Connect-Mailbox cmdlet to connect a disconnected mailbox to an Active Directory user object.) an archive mailbox to a linked mailbox in Exchange 2013.

Error from EMS:

25- 7- 2014 10-32-07

[PS] C:\>Connect-Mailbox -Identity "Personal Archive - Jan Novak" -Archive -User JanNovak2 -Database "EXDAG1-DB03"
WARNING: An unexpected error has occurred and a Watson dump is being generated: Object reference not set to an instance
 of an object.
Object reference not set to an instance of an object.
    + CategoryInfo          : NotSpecified: (:) [Connect-Mailbox], NullReferenceException
    + FullyQualifiedErrorId : System.NullReferenceException,Microsoft.Exchange.Management.MapiTasks.ConnectMailbox
    + PSComputerName        : server1.contoso.com

Error from GUI:

The LegacyDN "/o=CONTOSO/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=Jan Novak" of "cb67270a-ada2-472e-94cc-eb7140f3520f" is in use by the following user in Active Directory: "Pepa Novak (new)". The value for LegacyDN must be unique to each user.

Obviously, the LegacyDN attribute was not unique and defended to connect the mailbox.

[PS] C:\> # disconnected archive
[PS] C:\>(Get-mailboxdatabase|Get-Mailboxstatistics|?{$_.DisconnectReason -ne $null -and $_.DisplayName -like "*Jan*"}).LegacyDN
/o=CONTOSO /ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=Jan Novak

[PS] C:\># linked mailbox
[PS] C:\>(Get-mailbox JanNovak2).LegacyDN
/o=contoso/ou=exchange administrative group (fydibohf23spdlt)/cn=recipients/cn=Jan Novak

How to connect mailbox in case this case? According to Technet and Connect-Mailbox (Exchange 2013) there is available a switch:

25- 7- 2014 10-23-48Well, we have available the switch for similar scenario (i.e. AllowLagacyDNMismatch), but it is reserved only for MS use. I do not know why is it so (let me know if you a clue), but it worked for me without problem:

[PS] C:\> Connect-Mailbox -Identity "Personal Archive - Jan Novak" -Archive -User JanNovak2 -Database "EXDAG1-DB03" -AllowLegacyDNMismatch

[PS] C:\> Test-ArchiveConnectivity jan.novak@contoso.com

RunspaceId               : 7df20326-4fc0-4ca3-877f-5273aea0d5b7
Identity                 : jan.novak@contoso.com
PrimaryMRMConfiguration  :
PrimaryLastProcessedTime :
ArchiveDomain            :
ArchiveDatabase          : EXDAG1-DB03
ArchiveMRMConfiguration  :
ArchiveLastProcessedTime :
ComplianceConfiguration  : ElcV2
ItemMRMProperties        :
Result                   : Successfully logged on to the users Archive mailbox.
Error                    :
IsValid                  : True
ObjectState              : New

Test-ExchangeServer2010.ps1

Let me publish my script which tests and gathers information directly from Exchange server 2010 (Windows 2008). It is my little helper in case of patching or troubleshooting. Basically it is nothing special, but let’s look at its help:

.DESCRIPTION
    Test-ExchangeServer2010.ps1 - filip.kasaj@tieto.com - v1.180714
    This script performs test cmdlets and gathers information from Exchange Server 2010 (Windows Server 2008) into own txt log.
    It can be used only directly on the Exchanger server (the server role is chosen automatically). 
    Only get and test cmdlets are used for this type of health check.
    Run-space: PowerShell 2.0 or Exchange Management Shell.
    Prerequisite: new-TestCasConnectivityUser.ps1
    
    Tests and information:
    ----------------------
      Always:
        - Get-WMIObject (Operating System, Volumes)
        - Get-ExchangeServer
        - GCM Exsetup
        - Test-ServiceHealth
        - Get-ExchangeCertificate
        - IIS Status
        - Test-PowerShellConnectivity
        - Test-FederationTrust
        - Server Services
        - Bad Application Events
        - Bad System Evenets
        - Top processes - CPU,MemorySize
        - Server Performance
      Mailbox role:
        - Get-MailboxDatabaseCopyStatus
        - Get-DatabaseAvailabilityGroup
        - Cluster /quorum
        - Cluster group /stat
        - Cluster /prop
        - Test-Mailflow
        - Test-MAPIConnectivity
        - Test-ReplicationHealth
      CAS role:
        - Test-OwaConnectivity
        - Test-ActiveSyncConnectivity
        - Test-WebServicesConnectivity
        - Test-OutlookWebServices
        - Test-OutlookWebServices
        - Test-OutlookConnectivity
        - Test-EcpConnectivity
        - Test-ImapConnectivity
        - Test-PopConnectivity
      HUB role:
        - Test-SmtpConnectivity
        - Get-Queue
    
    .EXAMPLE
    Test-ExchangeServer.ps1 
    # It performs test cmdlets and gathers information into txt log generated in C:\temp.
    
    .EXAMPLE
    Test-ExchangeServer.ps1 -ShowOutputLog
    # It performs test cmdlets and gathers information into txt log generated in C:\temp and opens the log in notepad at the end.
    
    .EXAMPLE
    Test-ExchangeServer.ps1 -OutputLogPath "D:\Report\ExchangeServerLog.txt"
    # It performs test cmdlets and gathers information into the specified log file.
    
    .EXAMPLE
    Test-ExchangeServer.ps1 -ShowOutputLog -OutputLogPath "D:\Report\ExchangeServerLog.txt"
    # It performs test cmdlets and gathers information into the specified log file and opens the log in notepad at the end.

How to use it?

Just copy the script to your Exchange server and go ahead:

19- 7- 2014 13-07-58Output log as its result:

19- 7- 2014 13-17-56How to compare logs (i.e. check the state before/after patching)?

For example via Total Commander:

19- 7- 2014 12-50-56Download: Test-ExchangeServer2010.ps1 – http://1drv.ms/1wI2eS4

 

Exchange disk statistics

Here is a tip how to gather disk statistics such as
CapacityGB, FreeSpaceGB, FreeSpace% for all disks in your Exchange organization.

$vols = @()
Get-ExchangeServer | % { 
$comp = $_.Name
$vols += Get-WmiObject -computername $comp -query "select Name, DriveType, FileSystem, FreeSpace,   Capacity, Label from Win32_Volume where DriveType = 2 or DriveType = 3" | select @{Name='Server';Expression={$comp}},Label,Name,@{Name='CapacityGB';Expression={$_.Capacity/1GB}},@{Name='FreeSpaceGB';Expression={$_.FreeSpace/1GB}},@{Name='FreeSpace%';Expression={($_.FreeSpace*100)/$_.Capacity}}
}
$vols | Export-Csv -NoTypeInformation -Delimiter ";" -path "E:\ExchangeDiskreport.csv"