Use PowerShell to determine lastbootup time of a server or multiple servers

scenarios:  You want to quickly determine the bootup time for your Exchange Servers via Powershell.

Resolution: Run the following:

#For a Single Server:
Get-WmiObject win32_operatingsystem -computername ExSvr1 | select csname, @{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}


#For Multiple Servers:
$1 = Get-ExchangeServer ExSvr*
$1 | %{Get-WmiObject win32_operatingsystem -computername $_.name | select csname, @{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}}

Use PowerShell to search through multiple log files for specific text and export the results

Scenario:  You have multiple log/txt files you need to search through for specific text.  You would like to export/dump the text into another file.

Solution:  Run the following PowerShell Script.  Note the pattern contains the word you are looking for.  Unlike the “FIND” function in the command prompt, the PowerShell search does not require an exact case sensitive match.

#Look for any lines that has a text Pattern of "Fail" on it.
$1 = Get-ChildItem c:Temp*.log | Select-String -Pattern "Fail"

#For each line, export it to a csv.
$1 | Select line | Export-csv C:temptestline.csv

Disconnect RDP sessions via PowerShell

Scenario:  You are about to start maintenance on your servers and you want to remove any existing RDP session whether active of disconnected.  You want a quick way of doing this on all of your Exchange servers.

Solution:  Download the PSTerminalServices module from: https://psterminalservices.codeplex.com

Once download and installed, copy the PSTerminalServices folder from the install path into C:windowssystem32WindowsPowerShellv1.0.  Then run the following script in Exchange Powershell:

#Imports Terminal Services module
import-module psTerminalServices 

#Collect each Exchange Server in a variable
$Servers = Get-exchangeserver Ex2013*

#Now loop it to remove any existing TS Session.
$servers | %{
$Sessions = get-tssession -computername $_.name | where {($_.useraccount -like "domainname*")}
$sessions
$sessions | %{Stop-TSSession $_.sessionid -force}
}

 

 

Copy and then Rename files via PowerShell

Scenario:  You want to collect logs from various servers and place the copied logs into a single directory.  Due to the log names being the same on each server, we want avoid overwriting existing logs. We also want to know the server from where each log was copied from.

Solution:  The following will copy the IMAP logs from 4 servers into 1 local directory. Each file when copied to the directory will be renamed by prefixing the file with the server name.  It will also add the counter to the end of the file.

$Servers = "ExSvr1","ExSvr2","ExSvr3","ExSvr4"
$servers | %{$File = Get-ChildItem -Path "\$_c$Program FilesMicrosoftExchange ServerV15LoggingIMAP4" -Recurse;$i=1;Foreach ($f in $File) {Copy-Item $f.FullName ("C:TempIMAPPOP$_" + $f.BaseName + $i +".log");$i++}}
#End

 

 

 

When removing a Public Folder Database, the error is displayed: “The public folder database specified contains folder replicas. Before deleting the public folder database, remove the folders or move the replicas to another public folder database. “

Scenario:  You are trying to remove the last Public Folder Database in your Exchange 2010 Organization, but you are receiving this error when running:  Remove-PublicFolderDatabase EXPF1

The public folder database specified contains folder replicas. Before deleting the public folder database, remove the   folders    or move the replicas to another public folder database.

Solution:  Run the following commands to deleted the PF Folders and then try to remove the public folder database again:

Public Folders:

Get-PublicFolder -Server Ex2010Srv1 “” -Recurse -ResultSize:Unlimited | Remove-PublicFolder -Server Ex2010Srv1 -Recurse -ErrorAction:SilentlyContinue

System Public Folders:

Get-PublicFolder -Server Ex2010Srv1 “Non_Ipm_Subtree” -Recurse -ResultSize:Unlimited | Remove-PublicFolder -Server Ex2010Srv1 -Recurse -ErrorAction:SilentlyContinue

Message Tracking Aging in Exchange 2013

Scenario: You have a message that was delivered into Exchange 2013 within the last 30 days, but you cannot locate any Message Tracking log entries for that message.  Clearly the message was delivered into the mailbox as the message header contains the Exchange 2013 server hops.

When we run the following in Exchange 2013, it outputs the following defaults:

get-transportservice Ex2013Srv1 | FL MessageTrackingLogMax*

MessageTrackingLogMaxAge:           30 Days
MessageTrackingLogMaxDirectorySize: 1000 MB
MessageTrackingLogMaxFileSize:      10MB

Looking deeper into the Message Tracking Logging in the actual File Directory where the messages are stored (C:Program FilesMicrosoftExchange ServerV15TransportRolesLogsMessageTracking), I see 30 days worth of logs and what appears to be well over 1000 MB in log files combined.

Here’s whats happening.

The Message Tracking Log Directory contains different message tracking log files, all prefixed with the type of Tracking Log it is.

MSGTRK - Logs associated with the Transport Service
MSGTRKMA - Logs associated with the approvals and rejections
MSGTRKMD - Logs associated with messages delivered to Mailboxes
MSGTRKMS - Logs associated with messages sent from mailboxes

The 30 day max directory age OR the 1000 MB max directory size applies to the different message tracking log types separately.  For example, I have 30 days worth of MSGTRKMS logs as there is less activity for sending messages from the transport service on the server and the combined MSGTRKMS logs are under 1000 MB in combined size.  But I only have  20 days worth of MSGTRKMD logs as the combined log files size has met the 1000 MB limit.  Circular logging kicks in and older log files that meets the max age or max size criteria are then replaced with newer message tracking logs.

In our scenario,  the messages have aged off based on the size of the cumulative message tracking types and/or the date of when the files were created.

 

 

Delete Calendar entries by Start date and End Date

Scenario:  When exporting a Calendar to a PST via New-MailboxExportRequest, there no good content filters to export via Start Date and End Date for exporting calendar entries to a date range.  The Created/Modified/Received dates which are saved into Indexing may not produce the correct result if those items are queried.  Instead follow these steps:

1. Export the entire calendar and import it into another mailbox.

2. On the new mailbox, give your account that you are running Exchange Powershell from FULL permissions to the mailbox you created (or the mailbox with the calendar you want to edit).

3. Run the following script.  Change that which is in blue:

*Note: You can only do up to 2 year increments.  You can also comment out (#) the delete lines to double check your work.

Import-Module -Name "C:Program FilesMicrosoftExchange ServerV15BinMicrosoft.Exchange.WebServices.dll"
$mailboxname = "TEST222@domain.com"
$service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.Exchangeversion]::exchange2013)
$service.Url = new-object System.Uri("https://Ex2013Svr1.domain.com/EWS/Exchange.asmx")
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar,$MailboxName) 
$Calendar = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)    
#Define Date to Query 
#running 2 Year Increment
$StartDate = "1/1/2006"
$EndDate = "12/31/2007"
$CalendarView = New-Object Microsoft.Exchange.WebServices.Data.CalendarView($StartDate,$EndDate,100000)    
$fiItems = $service.FindAppointments($Calendar.Id,$CalendarView)    
foreach($Item in $fiItems.Items){      
 "Start    : " + $Item.Start  
        #"ENd    : " + $Item.END
        "Subject     : " + $Item.Subject  
 $Item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
    }    
#running 1 Year Increment
$StartDate = "1/1/2008"
$EndDate = "12/31/2008"
$CalendarView = New-Object Microsoft.Exchange.WebServices.Data.CalendarView($StartDate,$EndDate,100000)    
$fiItems = $service.FindAppointments($Calendar.Id,$CalendarView)    
foreach($Item in $fiItems.Items){      
 "Start    : " + $Item.Start  
        #"ENd    : " + $Item.END
        "Subject     : " + $Item.Subject  
 $Item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)

Compare 2 powershell variable arrays and show values that do not match.

Scenario:  When performing a migration, we noticed a discrepancy in the  count of users that are in a distribution group compared to the count of users that have move requests (the move requests  were originally generated from that distribution group).  We have to determine which mailboxes are missing.

Resolution: Here is a quick way of comparing those 2 lists:

1. Pull the Distribution Group Members into a Variable:

$1 = Get-DistributionGroupMember Migration_710 | Select Alias

2. Pull the Move Requests that were batch into a second Variable:

$2 = Get-MoveRequest -batchname Migration_710 | Select Alias

3. Export both of those Aliases into a CSV file:

$1 | export-csv C:1.csv

$2 | export-csv C:2.csv

4. Import those csv back into new variables :

$file1 = Import-csv C:1.csv

$file2 = Import-csv C:2.csv

5. Compare the lists by running the following command.  The output should be the missing objects.

compare-object $file1 $file2

Search a mailbox for a specific email without using OWA or Outlook.

Scenario:  A user is missing a message in their mailbox claiming it ‘disappeared’.  The possibilities are:

  1.  The message was accidentally deleted.
  2. The message was accidentally moved into another folder.
  3.  The message exists in the mailbox folder, except the items in that folder are not sorted correctly. Note:Sorting by the Received date will make all emails in that folder in chronological order

Solutions:

You could request permission from the user who owns the mailbox to allow you to have full access permission and search their mailbox via OWA — but this can be a little time consuming.  Instead  perform a ‘search-mailbox’ against the mailbox to locate the missing message:

Get a count of all messages that match the subject line:

Search-Mailbox jdoe1 -SearchQuery Subject:”Attention: Please Read this Email” -EstimateResultOnly

Create a copy of the messages that match the subject line:

Search-Mailbox jdoe1 -SearchQuery Subject:”Attention: Please Read this Email” -targetmailbox ExAdmin1  -searchdumpster

OR for a search with additional properties to be queried:

Search-Mailbox jdoe1 -SearchQuery {Subject:”Attention: Please Read this Email” AND from:”President@Domain.com”  AND Sent:”7/10/2015″} -Targetmailbox ExAdmin1 -searchDumpster

Note: it may request you to name a target folder so it can create that folder in the ExAdmin1 mailbox.  The search results will be then copied to that target folder in the folder hierarchy for where the messages are stored. For example, if there are messages in the inbox and deleted items of the mailbox being searched against, you will have the search results copied to the inbox and deleted items folder under the targetfolder that was created.

Cannot Remove a Exchange 2013 Database

Scenario: When you are trying to remove an Exchange Database,  you receive the following error below.

This mailbox database contains one or more mailboxes, mailbox plans, archive mailboxes, public folder mailboxes or
arbitration mailboxes. To get a list of all mailboxes in this database, run the command Get-Mailbox -Database
<Database ID>. To get a list of all mailbox plans in this database, run the command Get-MailboxPlan. To get a list of
archive mailboxes in this database, run the command Get-Mailbox -Database <Database ID> -Archive. To get a list of all
public folder mailboxes in this database, run the command Get-Mailbox -Database <Database ID> -PublicFolder. To get a
list of all arbitration mailboxes in this database, run the command Get-Mailbox -Database <Database ID> -Arbitration.
To disable a non-arbitration mailbox so that you can delete the mailbox database, run the command Disable-Mailbox
<Mailbox ID>. To disable an archive mailbox so you can delete the mailbox database, run the command Disable-Mailbox
<Mailbox ID> -Archive. To disable a public folder mailbox so that you can delete the mailbox database, run the command
Disable-Mailbox <Mailbox ID> -PublicFolder. Arbitration mailboxes should be moved to another server; to do this, run
the command New-MoveRequest <parameters>. If this is the last server in the organization, run the command
Disable-Mailbox <Mailbox ID> -Arbitration -DisableLastArbitrationMailboxAllowed to disable the arbitration mailbox.
Mailbox plans should be moved to another server; to do this, run the command Set-MailboxPlan <MailboxPlan ID>
-Database <Database ID>.

You have also verified that there are no mailbox/mailbox types on the database you wish to remove by running the following commands:

get-mailbox -database DB01
get-mailbox -archive -database DB01 -DomainController <root dc>
get-mailbox -PublicFolder -database DB01
get-mailbox -Arbitration -database DB01

Resolution:  Although an archive mailbox did not reside on the database we are trying to remove, we found that the database was still referenced in an archive mailbox that resided on a different database.  The archive mailbox was referencing the database via the msExchArchiveDatabaseLink property in ADSIEdit.

Once we discovered the archive mailbox, we moved it to another database, thus refreshing the properties in ADSI Edit and removing the database we wished to remove.

To determine which mailbox may be holding you up from removing an Exchange Database, follow these steps:

1. Remove the database in verbose:   remove-mailboxdatabase DB01 -verbose

2. Before it shows the error message, pay attention to the Verbose logging as it references the mailbox which is preventing the database from being removed.
VERBOSE: [18:03:27.819 GMT] Remove-MailboxDatabase : Runspace context: Executing user:
domain.com/users/exadmin, Executing user organization: , Current organization: , RBAC-enabled:
Enabled.
VERBOSE: [18:03:27.851 GMT] Remove-MailboxDatabase : Active Directory session settings for ‘Remove-MailboxDatabase’
are: View Entire Forest: ‘False’, Default Scope: ‘domain.com’, Configuration Domain Controller:
‘DC1.domain.com’, Preferred Global Catalog: ‘DC1.domain.com’, Preferred Domain Controllers: ‘{
DC1.domain.com }’
VERBOSE: [18:03:27.866 GMT] Remove-MailboxDatabase : Beginning processing Remove-MailboxDatabase
VERBOSE: [18:03:27.866 GMT] Remove-MailboxDatabase : Instantiating handler with index 0 for cmdlet extension agent
“Admin Audit Log Agent”.
VERBOSE: [18:03:27.866 GMT] Remove-MailboxDatabase : Current ScopeSet is: { Recipient Read Scope: {{, }}, Recipient
Write Scopes: {{, }}, Configuration Read Scope: {{, }}, Configuration Write Scope(s): {{, }, }, Exclusive Recipient
Scope(s): {}, Exclusive Configuration Scope(s): {} }
VERBOSE: [18:03:27.866 GMT] Remove-MailboxDatabase : Searching objects “db01” of type “MailboxDatabase” under the
root “$null”.
VERBOSE: [18:03:27.882 GMT] Remove-MailboxDatabase : Previous operation run on domain controller
‘DC1.domain.com’.
VERBOSE: [18:03:27.960 GMT] Remove-MailboxDatabase : Verifying that there is no associated mailbox user or move request
 on the mailbox database “db01”.
VERBOSE: [18:03:28.023 GMT] Remove-MailboxDatabase : Mailbox with DistinguishedName
“CN=jdoe1,CN=Users,DC=domain,DC=com” is still present in this database.
VERBOSE: [18:03:28.038 GMT] Remove-MailboxDatabase : Admin Audit Log: Entered Handler:OnComplete.