Exchange: How to search by an email address?

What if you have an email address, you want to know which object that email address belongs to? Mailbox or Distribution Group or Contact or Public Folder?

You have to keep searching by the following commands till you find your object. Open PowerShell and connect to Exchange (or Exchange Online).

Get-Mailbox | %{$_.EmailAddresses | ?{$_ -like “*<email address>*”}}

Get-RemoteMailbox | %{$_.EmailAddresses | ?{$_ -like “*<email address>*”}}
Get-DistributionGroup | %{$_.EmailAddresses | ?{$_ -like “*<email address>*”}}

Get-MailContact| %{$_.EmailAddresses | ?{$_ -like “*<email address>*”}}
Get-MailPublicFolder | %{$_.EmailAddresses | ?{$_ -like “*<email address>*”}}


Hope you saved some time and found your Exchange Object. Enjoy!!


Find SQL Servers on the network by PowerShell

I will make simple and short. PowerShell command uses SQL Browser service to populate the local SQL servers and instances on the network.

So the requirements are:

  1. SQL Browser service installed and running (or run it on a SQL server)
  2. You should be a Administrator (preferably domain admin)
  3. You have to run this command on each site (on one of the local server)

Open PowerShell and run this command.


Things are getting much easier these days. 🙂

Office 365: Send service alert emails using PowerShell

Office 365 service health information (healthy, degraded, etc.,) can be checked at Office 365 Admin console or using Office 365 Admin App on the phone.

At least Office 365 Admin App (for iPhone/Android/Windows) alerts when there is a change in service status.

I wrote a script for old school boys and girls who want to receive the Office 365 service degradation in emails.

This script can be run in intervals using Windows Task Scheduler. There is no special requirements (PS Modules) to run the script in PowerShell.

First Step: Create a Password XML file

Copy/Paste the following two PowerShell commands to create the password XML file. We are saving just the password (of the Office 365 Administrator account) in encrypted form. When asked type the password carefully.

$text = Read-Host -AsSecureString -Prompt ‘Enter Password’
$text | Export-Clixml -Path “$home\Documents\mypassword.xml”

Note: We are only saving the password in encrypted form in XML file in the user profile. Since only the user has access to their user profile, password file is in safe location. And we are not storing the user name, so it is not useful without knowing which user this password belongs to.

Another Note: if you are going to run the script in different user context in Task Scheduler, you have move the mypassword.xml file to the user profile location of the correct user context.

Now the script:

Either copy/paste the script in NotePad and name it Get-O365-Service-Health-Alerts.ps1 or DOWNLOAD THE SCRIPT.

Important: Make sure you assign appropriate values in the beginning of the script.


Script Name: Get-O365-Service-Health-Alerts.ps1
Purpose: Get the Office 365 tenant service health alerts using
JSON and send email to admins if the any degraded service is

Prerequiste 1: mypassword.xml file in your documents folder

You have to create the password.xml file using the
following PowerShell commands:

$text = Read-Host -AsSecureString -Prompt ‘Enter Password’
$text | Export-Clixml -Path “$home\Documents\mypassword.xml”

Prerequiste 2: Assign correct values to the variables
in this script (see below)

Written by: Anand, the awesome, Venkatachalapathy


#Assign the appropriate values in these variables
$username = ‘’
$SMTPServername = “”
$SMTPPort = 25
$From = “”
$To = “”


# read in the secret and encrypted password from file
$password = Import-Clixml -Path “$home\Documents\mypassword.xml”
# add the username and create a credential object
$credential = New-Object -TypeName PSCredential($username, $password)

# convert the credential to JSON format   
$jsonPayload = (@{userName=$credential.username;password=$credential.GetNetworkCredential().password;} | convertto-json).tostring()

# Fetch the Office 365 sevice health status using REST
$cookie = (invoke-restmethod -contenttype “application/json” -method Post -uri “” -body $jsonPayload).RegistrationCookie
$jsonPayload = (@{lastCookie=$cookie;locale=”en-US”;preferredEventTypes=@(0,1)} | convertto-json).tostring()
$events = (invoke-restmethod -contenttype “application/json” -method Post -uri “” -body $jsonPayload)

#Assign the service health events to a variable
$serviceEvents = $events.Events

#Check each event
foreach($event in $serviceEvents)
    $status = $event.status
    $detailedstatus = $event.AffectedServiceHealthStatus
    $Title = $event.Title
    $UpdatedTime = $event.LastUpdatedTime
    $Messages = $event.Messages

    #Check if the status is degraded
    If ($status -like “*degradation” )
        #form the mail subject
        $subject = $detailedstatus.ServiceName + ” – $status at $UpdatedTime”
        #display the subject

        #form the mail body
        $text = “”
        foreach($Message in $Messages)
            $text += $Message.MessageText

        #Send email to the admin
        Send-MailMessage -SmtpServer $SMTPServername `
                         -Port $SMTPPort `
                         -From $From -To $To `
                         -Subject $subject -Body $text
******************* End of the script ********************

SharePoint Online: Get Site Owners list from all Sites

I have been asked to get list of all explicit user accounts  and group with site owner permissions for all sites. I wrote a script using Get-SPOSite, Get-SPOUsers and Get-SPOGroup commands.

To make it easier I wrote the script requires the mandatory parameter of Office 365 Tenant name. The script will create a CSV file on the script working (current) directory.


  • Install SharePoint Online Management Shell (Download it from
  • Copy or Create the script to the desired location (e.g., C:\Scripts).
  • Open PowerShell and change the working directory to the location where script is located
  • Run the script with parameter TenantName
  • When asked provide the SharePoint Administrator credentials

e.g.,  if the sharepoint admin URL is, then the tenant name is contoso.

.\SiteOwnersList.ps1 -TenantName contoso

Download the script from HERE.

You may also copy/paste the script in PowerShell ISE and save as SiteOwnersList.ps1.

***    Script Name: SiteOwnersList.ps1
***    Purpose: List all SharePoint Online sites and it’s Owners from the site permissions list (Users and Groups) and create the report to a CSV file.
***             The generated CSV file stored at PowerShell script running location (local directory)
***    Parameters: <TenantName> – provide your SharePoint Online (Office 365) Tenant Name (usually your domain name)
***    Written By: Anand, the awesome, Venkatachalapathy

param (  [Parameter(Mandatory=$True)]
[string]$TenantName )

#Form a SharePoint Admin URl
$AdminURL = “https://$tenantName” + “”

#Add SharePoint PowerShell Snap-in and Importing the SharePoint Online module
Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
Import-Module ‘C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell’ -DisableNameChecking

#Connect to SharePoint Online
Connect-SPOService -Url $AdminURL -Credential (Get-Credential)

#Headers for the data
“Site URL`tOwner`tUsers`tGroup`tGroup Members” | Out-File -FilePath .\SharePointSiteOwners.csv

#Get all Sites (Root sites only)
$sites = Get-SPOSite -Limit All

#Process all sites
foreach($site in $sites)
$siteURL = $site.Url
$siteOwner = $site.Owner

    Write-Host $siteURL -ForegroundColor Cyan
Write-Host $siteOwner -ForegroundColor Cyan

#Get all users with Site Owner permissions
$siteAdmins = Get-SPOUser -Site $siteURL -Limit All | select LoginName,IsSiteAdmin | ? { $_.ISSiteAdmin }

    #Collect all site owners (user accounts) to a variable $siteUsers
$siteUsers = “”
foreach($siteAdmin in $siteAdmins) { $siteUsers += $siteAdmin.LoginName + ” , ” }

    Write-Host $siteUsers -ForegroundColor Cyan

#Get all Groups from the site permissions
$sitegroups = Get-SPOSiteGroup -Site $siteURL

#Get Group info and members that have site owners permissions
foreach ($sitegroup in $sitegroups)
$i = 0
foreach($role in $sitegroup.Roles)
if ( $role.Contains(“Site Owner”) -or $role.Contains(“Full Control”) )
$i = $i + 1
Write-Host $sitegroup.Title -ForegroundColor “Yellow”
Write-Host $sitegroup.Users -ForegroundColor “Blue”

                if ($i -gt 1)
“`t`t`t” + $sitegroup.Title + “`t” + $sitegroup.Users | Out-File -FilePath .\SharePointSiteOwners.csv -Append
“$siteURL`t$siteOwner`t$siteUsers`t” + $sitegroup.Title + “`t” + $sitegroup.Users | Out-File -FilePath .\SharePointSiteOwners.csv -Append

***                                                                            The END

Search-ADAccount for disabled, expired, inactive accounts

What would be the easiest way to list disabled accounts, inactive accounts or expired accounts from AD. You could use Get-ADUser or Get-ADObject, but they are more complicated & dealing with User attributes.

I found Search-ADAccount, it’s been much easier and generating reports from AD on the fly pretty much. Search-ADAccount description and help is at HERE.

Here is the sample commands. Note the number of days is set to 90 days in these commands. Change the day from 90 to your suitable number. You can remove Export-Csv command to show the results in the PowerShell window.

  • Search AD for Inactive Computer Accounts for more than 90 days.

Search-ADAccount -ComputersOnly -AccountInactive | ? { $_.LastLogonDate -lt (get-date).AddDays(-90) } | Select-Object Name,LastLogonDate,DistinguishedName | Export-Csv -Path .\Inactive-Computers-morethan-90days.csv –NoTypeInformation

  • Search AD for Inactive User accounts for more than 90 days

Search-ADAccount -AccountInactive -UsersOnly | ? { $_.LastLogonDate -lt (get-date).AddDays(-90) } | Select-Object Name,SAMAccountName,LastLogonDate,Enabled,LockedOut,PasswordExpired | Export-Csv -Path .\Inactive-Users-morethan-90days.csv –NoTypeInformation

  • Search AD for Expired User accounts for more than 90 days

Search-ADAccount -AccountExpired -UsersOnly | Select-Object Name,SAMAccountName,AccountExpirationDate,LastLogonDate,DistinguishedName | Export-Csv -Path .\Expired-UserAccounts.csv –NoTypeInformation

I believe you get the idea. Tweak the cmdlet or filter to get more combination of reports.

Outlook removes line breaks, but Why?

When we type beautiful emails with some (apparently) extra lines (line breaks) to make the message more readable sometimes. And when it reaches the user, Outlook removes the extra lines and make the email real ugly. Then Outlook displays this message on top of the message window: We removed extra line breaks from this message.


You can restore the extra lines by clicking on that message and choose Restore line breaks.


To permanently disable Outlook to remove the line breaks, you have to go to Outlook Options in File/Outlook Options, under Mail section.  Scroll down and find Remove extra line breaks in plain text messages option under Message Format section.


Machine generated alternative text:

Exchange: Members can’t remove themselves from security groups. Please set the group to Closed…

It was interesting to see when I was trying to add a member to a “mail enabled” security group in Exchange Admin Center, I get this:


Oh! I was freaking add a member…what the?

Well, we have two options.

One: Add the member using Active Directory Users and Computer console. It is easy, but we are not fixing the under laying issue.  So the option two is necessary.

Two: Make the group closed so members can’t leave themselves (even freaking though nobody is trying to leave the group) so we don’t get above message. Open PowerShell and connect to your Exchange Server and use the following cmdlet to close the group.

Set-DistributionGroup <Group Name or Alias>  -MemberDepartRestriction Closed

Did it help? Leave me a reply.