Selecting specific rows from a CSV file to perform Powershell functions/commands against

Scenario: You have a large CSV file that you need to import and perform specific PowerShell commands against. You need the results in a hurry and you want to split up the CSV so you can run multiple PowerShell sessions at once to pull the results in parallel. Instead of creating separate CSV files to import for each PowerShell session, you can tell PowerShell which rows of the import you want to target.

Code Example:   In each PowerShell you can import the CSV file. When calling the variable for the loop you can specify the rows you want to target.  In this example we are going to set customattribute1 to the string “MigrateME” for the first 1000 (well 1001) entries in the csv file in one PowerShell session.  In a second PowerShell session I would import the code but change [0..1000] to [1001..2000],  and repeat the increment for each additional PowerShell session.

$users = Import-csv C:TempAll_Mailboxes.csv

$users[0..1000] | Select -expandproperty alias | %{ set-mailbox $_ -customattribute1 “MigrateMe”}

Find Exchange ActiveSync Devices via ActiveDirectory PowerShell

Scenario:  If you want to list the mobile devices attached to an AD user and want to do it within the AD toolset, run the following  get-ADObject command.

PowerShell Snippit:

$name = “*steve*”

#To view the Devices:

$AD_EAS = Get-AdObject -filter {ObjectClass -like ‘msExchActiveSyncDevice’} | Where-object {$_.DistinguishedName -like $($name)}

$AD_EAS_Container = Get-ADObject -filter { ObjectClass -like ‘msExchActiveSyncDevices’} | Where-Object {$_.DistinguishedName -like $($name)}

PowerShell Scriptlets to check if NLA is enabled for Remote Desktop

Scenario: You want to see if  NLA (Network Level Authentication) is enabled on all of your servers for Remote Desktop.

The PowerShell code below is not a .ps1, although you can make a .ps1 out of it if you would like.  I like to teach working  “within” PowerShell, not just being a script monkey.

In order to run the code, you will need to open Powershell OR Powershell ISE with an account with elevated permissions to access your servers (Run-AS).  The purpose of working within PowerShell is so that you can  reuse/recycle the code below to do other things too.
Once PowerShell is opened, follow the steps:
  1. Build your $Servers Variable — Select a method to populate $Servers
  2. Run the Query to build the $Results table
  3. Display the $Results — Select a method

 

 

#1. Build your $Servers Variable — Select one of the methods below to populate $Servers

  $Servers = “ExSrv1″,”ExSrv2”   #Feel free to list the servers by name

    #-or-
        $Servers = Import-csv C:tempservers.csv | Select -expandproperty Name   #Create a CSV with a NAME column header

    #-or-
        $Servers =  get-adcomputer -searchbase “OU=Servers,DC=steve,DC=com” -properties Name -Filter *|  Select -ExpandProperty Name  #Pull a list of AD Computers via AD PowerShell

#2. Run the query to build the $Results variable 

$Results = @()
$Servers | %{
    #Collect NLA Data
    $name = $_
    $NLA = Get-WmiObject -class “Win32_TSGeneralSetting” -Namespace rootcimv2terminalservices -ComputerName $name -Filter “TerminalName=’RDP-tcp'” | Select -ExpandProperty UserAuthenticationRequired
   
    #Display in PowerShell Screen
    “$name : NLA_Enabled:$(If($NLA -eq 1){“Yes”}else{“No”})”

    #Add the data to the $results variable
    $ServerObj = New-Object PSObject
    $ServerObj | Add-Member NoteProperty -Name “Server” -value $name
    $ServerObj | Add-Member NoteProperty -Name “NLA_Enabled” -value $(If($NLA -eq 1){“Yes”}else{“No”})
    $Results += $ServerObj
   
    #Reset Variable
    $Name = $null
    $NLA = 0
}

#3. Display the $Results –  Select a method

$Results

    #-or Export the Results –
        $Results | Export-CSV C:tempresults.csv

    #-or Email the Results –
        $Header = @”
        <style>
        TABLE {border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
        TH {border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #6495ED;}
        TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black; text-align: center;}
        tr:nth-child(odd) { background-color:#F2F2F2;}
        tr:nth-child(even) { background-color:white;}
        </style>
“@
        $body =”$($results | ConvertTo-Html -Head $header)”
        $smtp = “smtp.steve.com”
        $to = “steve@steve.com”
        $from = “SteveDoingSomething@steve.com”
        $subject = “Results of NLA”
        send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -BodyAsHtml -Priority high

Analyzing the Get-MobileDeviceStatistics -GetMailboxLog to determine Sync Errors

Scenario:  You have already enabled ActiveSync Debug Logging  (Set-CASMailbox steve -ActiveSyncDebugLogging:$true) and now you want to collect and analyze the logs for errors.  ActiveSync is chatty so it creates a TON of logging data to sift through. So how do we know which log entries are good and which are bad? Here is the dirty way we sifted through it.

Pull the ActiveSync Debug Log:

$1 = Get-MobileDeviceStatistics -Mailbox steve -GetMailboxLog

Lets take a quick glance at the status provided for each ActiveSync transaction provided in the MailboxLogReport

$1.MailboxLogReport | Out-file C:tempmobiledevicedebuglog.txt
$Text = “<status>”
$statuscheck = Get-Content C:tempmobiledevicedebuglog.txt | Select-String -Pattern $Text
$statuscheck

This should provide a long list of StatusCodes.  Usually a status of 1 (<status>1</status>) down the list is great!

BUT if you receive other statuses, then we may have to dive deeper into figuring out what the status means related to the ActiveSync command which caused it.  To do this, you will need to do the following:

  1. Navigate to the Microsoft document which provides a list of each ActiveSync Command and their status codes.  It can be found here.

2. Open the C:tempmobiledevicedebuglog.txt  which was created in previous steps and perform a find on that status code. In this example, we will use:  <status>2</status> as our questionable status.

3. Perform a search for that status and in the responsebody: found in the text file, that section should list the ActiveSync command that was attempted that produced a result.  For example our <status>2</status> was for the PING command.

Digging deeper, it appears the <status>2</status> for PING is fine because it just lets me know that: “Changes occurred in at least one of the monitored folders. The response specifies the changed folders.”  which is fine — no big deal. I found that status code  here.

BUT lets pretend I found a status 8 (<status>8</status>). This would be an issue that was caused/recognized by the Exchange  server.  Something like this could help in troubleshooting a server issue versus a client issue.

 

 

Collect more than 1000 Results in a Exchange Online Message Trace

Scenario: Recently I was attempting to perform a Message Trace in Exchange Online for a message that went out to 7000+ recipients but realized I could only pull back 1000 results.

Solution:  I used Page and PageSize with the Get-MessageTrace in a loop to pull back more results

 #Collect more than 1000 results in Exchange Online
$P = 1
$messages = $null
do 

    Write-Host “Message Trace – Page $P…” 
    $temp_Messages = Get-MessageTrace -senderaddress maccount@microsoft.com -startdate 8/14/2019 -enddate 8/15/2019 -PageSize 1000 -Page $P
    $P++ 
    $Messages += $temp_Messages 
}until ($temp_Messages -eq $null)

#display messages
$Messages.Count
$Messages

 

 

 

Duplicate Mailbox in Exchange Online after Offboarding to Exchange On-Premises

Scenario:   We migrated (offboarded) a mailbox from Exchange Online to Exchange On-Premises.  Although the mailbox was successfully migrated to On-Premises, the Exchange Online mailbox (which should have been deprovisioned) was still available in the cloud with the following error found in the Users:

Exchange: Failed to disable the mailbox <GUID> due to a conflict in directory settings. To disable this mailbox, first run Enable-RemoteMailbox on-premises. After the next Dirsync sync cycle, run Disable-RemoteMailbox on-premises to disable this mailbox in the datacenter.; Exchange: An unknown error has occurred.

The issue is that we cannot Enable-RemoteMailbox On-Premises because a Mailbox already exists for the user account On-Premises.  Also we already disabled the Exchange Online license for that account.  Its just not working, MICROSOFT!

Instead we got around the issue by doing this:

Solution:   In ADSIEdit, we cleared the value for msExchRemoteRecipientType.   Originally this value was set to a ‘8’ (DeprovisionMailbox ).  By clearing this value, the mailbox and the error are no longer present in Exchange Online and everything is good.  There had to be an error in the process of the sync or the mailbox conversion, but after clearing the error there are no issues with the mailbox.

Remove an orphaned MSExchDelegateListBL (autodiscover) entry

Scenario:  A user no longer has fullaccess to a shared mailbox BUT the shared mailbox still attempts to reconnect via Autodiscover in the Outlook profile.

Solution: The following scriptlets will detect the autodiscover links associated with the problem mailbox and attempt to remove them.  Note, you can remove all backlinks, or specific backlinks.

  $u = "Steve"
  $u_DN = Get-ADUser $u | select -ExpandProperty DistinguishedName
  $d = Get-ADUser $u -Properties msExchDelegateListBL |  select msExchDelegateListBL
  
  #To remove all backLinks
  $d.msexchdelegatelistBL | %{Set-ADUser $_ -Remove @{msExchDelegateListLink = "$u_dn"}}
  
  #To Remove specific BackLinks
  $SharedMailboxToRemove
  $d | Where msexchdelegatelistBL -like "*$SharedMailboxToRemove*" | Select -ExpandProperty msexchdelegatelistBL | %{Set-ADUser $_ -Remove @{msExchDelegateListLink = "$u_dn"}}

Exchange EWS applications continuously disconnect and reconnect

Scenario:  Users are reporting that their Mac Mail and Outlook for Mac email clients continuously disconnect and then reconnect making their mail client unreliable and unstable.  EWS is the only mail protocol that is affected, all other protocols are fine.

Troubleshooting:  We noticed the following (the timing for each item found was at the same time or really close together):

Event Viewer: We found the following events in the Application logs that tied together errors with ASP.Net and the crashing/restarting of the  MSExchange Web Services app pool:

  • EventID:  1325   –  Source: ASP.NET 4.0.30319.0 – Application ID: /LM/W3SVC/2/ROOT/EWS Message: Missing signing certificate
  • EventID: 2 – The Exchange Web Services started successfully.

Wireshark: We saw connection Resets (RST) being issued from the server to the client, meaning it was the server that was the cause of disconnecting clients to the server. Wireshark Filter:  (ip.dst==10.1.1.2 or ip.src==10.1.1.2) and tcp.flags.reset ==1

AuthConfig: Troubleshooting the ASP.NET error and the message: missing signing certificate, we realized that the certificate currently being used for server authentication was expired.  (ExPowershell: Get-authconfig)

Solution:  ASP.NET was breaking as a result of the certificate used for AuthConfig. When ASP.NET broke, so did EWS. We created/deployed a new certificate and this fixed our issue.

We created a new certificate:

New-ExchangeCertificate -KeySize 2048 -PrivateKeyExportable $true -SubjectName “cn=Microsoft Exchange Server Auth Certificate” -FriendlyName “Microsoft Exchange Server Auth Certificate” -DomainName “contoso.com”

Then we exported the new cert  and imported to each Ex Server:

Export-ExchangeCertificate -Thumbprint E5AAEBA3DCB406331949D3FB5E108FC7EF3B0B62 -FileName “\ExSrv1C$authcert.pfx” -BinaryEncoded -Password (ConvertTo-SecureString -String ‘password’ -AsPlainText -Force)

$Servers = get-exchangeserver
$servers.name | %{
    “$_”
    Import-ExchangeCertificate -Server $_ -FileName “\ExSrv1C$authcert.pfx” -Password (ConvertTo-SecureString -String ‘password’ -AsPlainText -Force)
}

Next we set the AuthConfig to the new certificate:

Set-AuthConfig -NewCertificateThumbprint E5AAEBA3DCB406331949D3FB5E108FC7EF3B0B62 -NewCertificateEffectiveDate (Get-Date)

Next we Published the Cert:

Set-AuthConfig –PublishCertificate

Since this issue was a result of ASP.NET errors, this made the errors go right away.  I followed up with  Restarting the Web App Pools for the following just in case:

Restart-WebAppPool MSExchangeOWAAppPool
Restart-WebAppPool MSExchangeECPAppPool
Restart-WebAppPool MSexchangeServicesAppPool

 

 

 

 

PowerShell Scriplet: Determine Time Zone and Current Time for your Servers

Scenario:  When attempting to run the Office 365 Hybrid Configuration wizard, we received an error similar to the following when attempting to validate domain ownership of a brand new email domain:   Failed – Unable to federate your domain. Your system time appears to be more than five minutes out of sync with the time on our federation servers.  Ensure your system time is correct and retry the Hybrid Configuration Wizard.

Scriptlet: This scriptlet below will pull the Exchange servers in and show you the Time Zone and Current Time for each server.

$Servers = get-exchangeserver
$servers | %{
$timeZone=Get-WmiObject -Class win32_timezone -ComputerName $_
$localTime = Get-WmiObject -Class win32_localtime -ComputerName $_
$output =@{‘ComputerName’ = $localTime.__SERVER;
‘Time Zone’ = $timeZone.Caption;
‘Current Time’ = (Get-Date -Day $localTime.Day -Month $localTime.Month);
}
$object = New-Object -TypeName PSObject -Property $output
$Object
}