<< A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

–A–

AlternateEmailAddresses, users that have at least one

Get-MsolUser -all | where {($_.AlternateEmailAddresses.count -gt 0)} | ft UserPrincipalName,AlternateEmailAddresses

automap a shared mailbox, remove for several users

You can't just remove automapping. Instead, you must remove full access rights and then add full access again but this time with the automapping set to $false instead of default $true

specify the shared mailbox:

$sharedMailbox = "wantToShare@yourDomain.com"

verify the existing permissions on this shared mailbox. I normally use this in order to get rid of inherited permissions:

Get-Mailbox $sharedMailbox | Get-MailboxPermission | where {$_.user.tostring() -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false} | Select-Object user, AccessRights

But if you run the simpler version, you might see a "SID" tucked in there somewhere:

Get-Mailbox $sharedMailbox | Get-MailboxPermission

In at least one instance, I did get a SID and it was inherited. This may cause a problem.

populate array with delegates who you're going to remove and then add back permissions (but without automapping):

$delegates = @("user1@yourDomain.com", "user2@yourDomain.com", "user3@yourDomain.com")
$delegates | %{Remove-MailboxPermission -Identity $_ -User $sharedMailbox -AccessRights FullAccess -Confirm:$false}

I sometimes get the following message:

WARNING: Can't remove the access control entry on the object "CN=your user,OU=yourTenant.onmicrosoft.com,OU=Microsoft Exchange Hosted Organizations,DC=NAMPR10A004,DC=PROD,DC=OUTLOOK,DC=COM" for account "NAMPR10A004\share53598-1921233685" because the ACE doesn't exist on the object.

which doesn't make sense. But I proceed anyway.

$delegates | %{Add-MailboxPermission -Identity $_ -User $sharedMailbox  -AccessRights FullAccess -AutoMapping:$false}

verify:

$delegates | %{Get-Mailbox | Get-MailboxPermission -user $_}

I have yet to find any PowerShell command that actually tells the status of automapping. The command above merely verifies that the individuals still are delegates to the target shared mailbox with full access.

–B–

Behalf - as in "SendOnBehalfTo" - see

delegated mailboxes that a user has SendOnBehalfTo, SendOnBehalfTo, add this permission for a user on a shared mailbox

–C–

calendar activity, examine log

Get-CalendarDiagnosticLog -Identity someUser -StartDate "10/3/2018 6:00:00 AM" -EndDate "10/3/2018 5:00:00 PM" | ogv

I use this to test whether adding calendar items is reflected in another user who may have been inadvertently added as a delegate at the Outlook (not Exchange) level.

calendar, allow someone else to view

Add-MailboxFolderPermission whoseCalYouWantRead@yourDomain.com:\Calendar -User whoNeedsAccess@yourDomain.com -AccessRights FolderVisible,ReadItems

calendar, display all calendars for a user

Get-MailboxFolderStatistics "someUser" | ? {($_.foldertype -eq "Calendar") -or ($_.folderpath -like "/Calendar*")} | ft Name, Identity, folderpath, foldertype

calendar, remove permissions

Remove-MailboxFolderPermission -Identity whoseCalendar@yourDomain.com:\Calendar -User userWhoWantsPerms -confirm:$false

calendar, who has what permissions?

Get-MailboxFolderPermission -Identity whoseCalWantToKnowPerms@yourDomain.com:\Calendar

conference room, create - see room, create

conference rooms, filter out from list of mailboxes- see mailbox types, filter out types

contact, add - New-MailContact. Curiously, even though there's a Get-MsolContact command, there does not appear to be any corresponding New-MsolContact command

replicate all contacts in an OU in local AD to cloud (useful if not syncing)

$contacts = Get-ADObject -filter {objectclass -eq "contact"} -SearchBase "OU=yourOU,DC=yourDomain,DC=com" -Properties name, givenName, middleName, sn, mail | `
    Sort-Object sn, givenName | select name, givenName, middleName, sn, mail
$contacts | % {New-MailContact -Name $_.Name -DisplayName $_.Name -ExternalEmailAddress $_.mail -FirstName $_.FirstName -LastName $_.LastName}

replicate all users in an OU in local AD to cloud

$users = Get-ADUser -filter * -SearchBase "OU=somOU,DC=yourDomain,DC=com" `

    -Properties company, department, displayName, givenName, mail, middleName, name, physicalDeliveryOfficeName, sn, telephoneNumber, targetAddress

$users | % {New-MailContact -DisplayName $_.DisplayName -Name $_.Name -FirstName $_.givenName `
    -ExternalEmailAddress $_.targetAddress.split(":")[1] -LastName $_.LastName}

There are many attributes you simply can't include when adding a contact. These include such important attributes as: company, department, office, phone, title. But we can add them after the fact using the Set-Contact command.

$users | % {Set-Contact $_.DisplayName -company $_.company -department $_.department -Office $_.physicalDeliveryOfficeName -phone $_.telephoneNumber -title $_.title}

contact, find and remove a contact with the same name as a user

Find

$DepartingUserIdentity = "someUser";

Get-ADObject -LDAPFilter "objectClass=Contact" -Properties Name,mail,DistinguishedName  | Where-Object{$_.mail -like "$($DepartingUserIdentity)*"} | ft Name, mail, DistinguishedName

Remove

$EmployeeDetails = Get-ADUser $DepartingUserIdentity -properties *

Get-ADObject -Filter {(cn -eq $EmployeeDetails.Name) -and (objectClass -eq "Contact")} | Remove-ADObject -Confirm:$False

or hard-coded name instead of using a variable:

Get-ADObject -Filter {(cn -eq "Some User") -and (objectClass -eq "Contact")} | Remove-ADObject -Confirm:$False

contact info (with proxyAddress),

Get-MailContact -Identity someUser @someDomain.net | select DisplayName,alias,externalEmailAddress,emailAddresses

contacts, bad according to DirSync - find and remove

run this:

Get-MsolContact -All | where {($_.ValidationStatus -eq "Error")} | sort DisplayName | select DisplayName, EmailAddress, objectID

in order to get known problems. To remove same:

Get-MsolContact -All | where {($_.ValidationStatus -eq "Error")} | Remove-MsolContact -Force

This doesn't always get everything. So, try this to find more:

Get-MsolDirSyncProvisioningError -ErrorCategory PropertyConflict | where {$_.ObjectType -EQ "contact"} | ft

And then delete these:

Get-MsolDirSyncProvisioningError -ErrorCategory PropertyConflict | where {$_.ObjectType -EQ "contact"} | Remove-MsolContact -Force

contacts, display "proxyAddresses" and "targetAddress"

contacts on the cloud don't really have the same "proxyAddresses" or "targetAddress" as local AD contacts. Instead, they have "externalEmailAddress" and "emailAddresses" analogs:

Get-MailContact | select DisplayName,alias, externalEmailAddress, emailAddresses

contacts, proxyAddresses add

this example takes whatever the main address is and adds another email with a new suffix:

$contacts = Get-MailContact | Select-Object Identity, PrimarySmtpAddress, emailAddresses
$contacts | % {Set-MailContact -Identity $_.Identity -EmailAddresses @{Add = "smtp:" + $_.PrimarySmtpAddress.split("@")[0 ] + "@yourDomain.com"}}

–D–

delegate a mailbox to another user - see permissions - assign mailbox permissions/delegation of one user to another user

delegates don't show up as expected in Outlook

You've added delegates to a user with full access rights. And they show up just fine in WebMail. But not in Outlook. Answer: you have to take away full access and then add it back again with Automapping. The following forces all of a user's delegates to show up in Outlook.

$Delegates = Get-Mailbox | Get-MailboxPermission -user 'someUser@yourDomain.com'
$Delegates | %{Remove-MailboxPermission -Identity $_.Identity -user $_.User -AccessRights FullAccess -Confirm:$False}
$Delegates | %{Add-MailboxPermission -Identity $_.Identity -user $_.User -AccessRights FullAccess -AutoMapping:$True}

Perhaps, instead, you want to make sure just one of a user's delegates to show up in his Outlook. If, for example, you want to reset the "marketing" shared mailbox for "Bob", "marketing" is the "sourceUser" below and "Bob" is the "targetUser" below:

Get-Mailbox "sourceUser@yourDomain.com" | Remove-MailboxPermission -user "targetUser@yourDomain.com" -AccessRights FullAccess -Confirm:$False | Add-MailboxPermission -AccessRights FullAccess -Automapping $true -User "targetUser@yourDomain.com"

If you want to verify, you can run something like this:

Get-Mailbox "gdpr@foodchainid.com" | Get-MailboxPermission | where {$_.user.tostring() -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false}

Unfortunately, it doesn't return any automapping field. That column doesn't show up even if you add a "| fl" at the end. I haven't yet figured out how to get the automapping field to show up in any PowerShell command.

delegates for a (normally shared) mailbox

Get-Mailbox someUser | Get-MailboxPermission | where {$_.user.tostring() -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false} | Select-Object user, AccessRights

remove one of the delegates

Remove-MailboxPermission -identity someUser -user someDelegate@yourDomain.com -AccessRights FullAccess -confirm: $false

delegated mailboxes that a user has access to

Get-Mailbox | Get-MailboxPermission -user 'someUser@yourDomain.com'

delegated mailboxes that a user has FullAccess

find

$DepartingUserIdentity = "someUser";

Get-Mailbox | Get-MailboxPermission -user $DepartingUser

(or another way)

Get-Mailbox | ? {$_.GrantSendOnBehalfTo -match $DepartingUserIdentity}

Or, with an individual, hard-coded email address:

Get-Mailbox | Get-MailboxPermission -user 'someUser@yourDomain.com'

(or another way)

Get-Mailbox | ? {$_.GrantSendOnBehalfTo -match "someUser"}

The most common permission we need to worry about is “FullAccess”.

Remove

Attempt to remove “FullAccess” in one fell swoop fails because we run out of threads

Get-Mailbox | Get-MailboxPermission -user $DepartingUser | % {Remove-MailboxPermission -identity $_.Identity -user $_.User -AccessRights FullAccess -InheritanceType All -confirm: $false}

Error is

Remove-MailboxPermission : The session WinRM1, 24b1bbc8-5f00-4836-b7c0-097b589ed891, outlook.office365.com is not available to run commands.  The session availability is Busy.

Which means trying to do too much at once.

But split this up into 2 parts, seems to work better

$targetUsers = Get-Mailbox | Get-MailboxPermission -user $DepartingUser

$targetUsers | % {Remove-MailboxPermission -identity $_.Identity -user $_.User -AccessRights FullAccess -InheritanceType All -confirm: $false}

delegated mailboxes that a user has SendOnBehalfTo

find

$DepartingUserIdentity = "someUser";

Get-Mailbox | ? {$_.GrantSendOnBehalfTo -match $DepartingUserIdentity}

remove

delegates, generate list

Get-Mailbox | Get-MailboxPermission | where {$_.user.tostring() -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false}

delegate, remove

Remove-MailboxPermission -identity someUser -user someDelegate@yourDomain.com -AccessRights FullAccess -confirm: $false

what if you get:

The operation couldn't be performed because 'someUser' matches multiple entries.

Get IDs for the dupes:

Get-Mailbox someUser | select UserprincipalName, Guid, ExchangeGuid

then re-run the delete command using the Guid:

Remove-MailboxPermission -identity c5909e04-1407-423f-82c8-0f60de50cf0c -user someDelegate@yourDomain.com -AccessRights FullAccess -confirm: $false

You may ask: why not just rename one of the aliases to remove the alias? First of all, if you sync with local AD, you'd have to make the change in local AD. Second of all, there's probably a good reason why there are duplicate aliases. "Alias" is the same as "proxyAddress". And you might one user with someuser@yourDomain1.com and another someuser@yourDomain2.com. Like if this user moved to a different division but we kept the old mailbox hanging around as a shared mailbox for successor to monitor.

delete emails

This will delete all emails for a particular user which are older than a certain date:

Search-Mailbox -Identity "Bob Smith" -SearchQuery "(Received < 11/1/2018)" -DeleteContent -Confirm:$false

or

Get-Mailbox -Identity "some body" | Search-Mailbox -SearchQuery "(Received < 11/1/2018)" -DeleteContent

A few things to note:

I've found that if I run this too many times in succession, I might get an error:

Deletion failed with error 'Move/Copy messages failed.' for the following item:

And then followed by the subject and some other gobbledegook for each of hundreds of emails in the date range. I think this has to do with the index getting corrupt. If I wait a day or so, it seems I can resume. I had this problem deleting 10,000 at a time for a mailbox which had over half a million records. Even if I crunched down the time span to a much smaller interval:

Search-Mailbox -Identity "some body" -SearchQuery {Received:9/1/2018..9/2/2018} -DeleteContent -Confirm:$false

which, in this case, resulted in only 3 records, I still get the same error

deleted emails, permanently delete

Search-Mailbox -Identity someUser -SearchQuery '#deleted items#' -DeleteContent

Should return something like:

WARNING: The Search-Mailbox cmdlet returns up to 10000 results per mailbox if a search query is specified. To return more than 10000 results, use the New-MailboxSearch cmdlet or the In-Place eDiscovery & Hold console in the Exchange Administration Center.
Confirm
Deleting content from mailboxes someUser
[Y] Yes [A] Yes to All [N] No [L] No to All [?] Help (default is "Yes"): a
 

RunspaceId       : 1e74c7bf-a89d-44d8-b9bc-3298b5f5ab93
Identity         : Some User
TargetMailbox    :
Success          : True
TargetFolder     :
ResultItemsCount : 68
ResultItemsSize  : 16.2 MB (16,987,063 bytes)

To get

deleted emails, recover

My initial mistake of setting "Discovery Search Mailbox" as the target mailbox was the beginning of a long detour.

Search-Mailbox "haplessEndUser@theirDomain.com" -SearchQuery "subject:""$9 million dollar signed contract!""" -TargetMailbox "Discovery Search Mailbox" -TargetFolder "Signed Contract Recovery" -LogLevel Full

This worked.  I got 8 items:

RunspaceId       : d8758080-fe7c-4006-ae91-3a0d56aad4e0
Identity         : Hapless EndUser
TargetMailbox    : DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852}
Success          : True<
TargetFolder     : \Signed Contract Recovery\Hapless EndUser-3/22/2018 3:48:33 PM
ResultItemsCount : 8
ResultItemsSize  : 245.4 KB (251,260 bytes)

But I should have thought better before sending this to the “Discovery Search Mailbox".  Where the heck is that?  It turns out the system somehow recognized the word "Discovery Search" and made a mailbox with special, limited properties. Those properties include locking any search results in it in such a way that once they go in, you can't move them anywhere else. But I didn't know that right off. So I tried moving these same 8 items somewhere else.  Note: you can’t just send it to the same mailbox as the source mailbox or you’ll get this:

WARNING: The source mailbox 'Hapless EndUser' will not be searched because it is the target mailbox. The source mailbox cannot be used as the target mailbox.

So, instead send to my email box:

Search-Mailbox "haplessEndUser@theirDomain.com" -SearchQuery "subject:""$9 million dollar signed contract!""" -TargetMailbox "longSufferingSysAdmin@myDomain.com" -TargetFolder "Signed Contract Recovery" -LogLevel Full

But that returns nothing:

RunspaceId       : d8758080-fe7c-4006-ae91-3a0d56aad4e0
Identity         : Hapless EndUser
TargetMailbox    : Longsuffering SysAdmin
Success          : True
TargetFolder     : \Signed Contract Recovery\Hapless EndUser-3/22/2018 4:05:25 PM
ResultItemsCount : 0
ResultItemsSize  : 0 B (0 bytes)

Well, that was annoying and surprising.  Let’s see if we can dig them out of that discovery mailbox and put them in my mailbox:

Search-Mailbox "Discovery Search Mailbox" -SearchQuery "subject:""$9 million dollar signed contract!""" -TargetMailbox "longSufferingSysAdmin@myDomain.com" -TargetFolder "Signed Contract Recovery" -LogLevel Full

Again, no results:

RunspaceId       : d8758080-fe7c-4006-ae91-3a0d56aad4e0
Identity         : DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852}
TargetMailbox    : Longsuffering SysAdmin
Success          : True
TargetFolder     : \Signed Contract Recovery\Discovery Search Mailbox-3/22/2018 4:06:57 PM
ResultItemsCount : 0
ResultItemsSize  : 0 B (0 bytes)

Same “no results” if I choose a more verbose name I find for this box:

Search-Mailbox "DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852}" -SearchQuery "subject:""$9 million dollar signed contract!""" -TargetMailbox "longSufferingSysAdmin@myDomain.com" -TargetFolder "Signed Contract Recovery" -LogLevel Full

OK, so they’re stuck in this weird Discovery box.  Can I make myself a delegate?

Get-Mailbox -Resultsize unlimited -Filter {RecipientTypeDetails -eq "DiscoveryMailbox"} | `
    Add-MailboxPermission -AccessRights FullAccess -Automapping $true -User "longSufferingSysAdmin@myDomain.com"

Apparently:

WARNING: The appropriate access control entry is already present on the object "CN=DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852},OU=yourDomain.onmicrosoft.com,OU=Microsoft Exchange Hosted Organizations,DC=NAMPR10A004,DC=PROD,DC=OUTLOOK,DC=COM" for account "NAMPR10A004\jmosc50247-845198855".

 

Identity             User                 AccessRights   IsInherited Deny
--------             ----                 ------------   ----------- ----
DiscoverySearchMa... NAMPR10A004\jmosc... {FullAccess}

Well, it didn’t error out.  But it seems to think I already have access.  This didn’t show up as a new mailbox in Outlook.  Nor coulc I find it through WebMail. But after half an hour or so, it finally did show up as a delegated box in my Outlook and I was able to copy the email to my main mailbox & send (couldn’t send from that mailbox because I hadn’t set myself up with “SendAs” privileges.)

So, the big lesson learned: just send it to my own dang email box to begin with.  Otherwise it gets trapped in that Discovery mailbox that’s created on the fly and the only way to get it out then is by setting myself up as a delegate.

deleted mailboxes, list - see also deleted users (soft deleted), list

Get-Mailbox -SoftDeletedMailbox | Select DisplayName,ExchangeGuid,PrimarySmtpAddress,ArchiveStatus,DistinguishedName | Out-GridView -Title "Select Mailbox and GUID" -PassThru

deleted mailbox, recover mailbox when synced user associated with that deleted mailbox is still present

First, get the ExchangeGUID of the deleted mailbox

get-mailbox -SoftDeletedMailbox -identity somedeleteduser | fl ExchangeGUID

Simlarly, get the ExchangeGUID of the target user. Make sure this target user has an email licenses of some kind and that we've logged in at least once - to create an empty mailbox to migrate into

get-mailbox -identity userWhoLostHisMailbox | fl ExchangeGUID

Copy the stuff from the deleted mailbox to the target, using the ExchangeGUIDs you got above as appropriate:

new-MailboxRestoreRequest -SourceMailbox "8c86592c-5cb7-4bc5-8b06-7f6a57b84d2b" -TargetMailbox "4c587005-e303-4689-aed7-564e49b0734b" -AllowLegacyDNMismatch

deleted mailbox, recover a soft deleted / disconnected mailbox merged to another user on exchange online - So You Need To Recover A Soft Deleted / Disconnected Mailbox Merged To Another User On Exchange Onlines or Office 365 and Exchange Online Restore and Recover Processes for Soft-Deleted Mailboxes

DirSync errors, list

Get-MsolDirSyncProvisioningError -ErrorCategory PropertyConflict | ft

disabled accounts, filter out from list of mailboxes - see mailbox types, filter out types

distribution group, bulk change WindowsEmailAddress of cloud-only (exclude those synced with local AD)

$distGroup = Get-DistributionGroup | ? {$_.isdirsynced -eq 0 -and ($_.WindowsEmailAddress.split("@")[1] -match "yourdomain.com")}

Optional: inspect first before proceding to the command that actually applying our changes:

$distGroup | ft name, proxyAddresses

Now proceed to actually do what we set out to do: set "PrimarySmtpAddress" for all users which had corresponding "PrimarySmtpAddress" correpsonding to our domain:

$distgGp | %{Set-DistributionGroup -identity $_.identity -WindowsEmailAddress ($_.WindowsEmailAddress.split("@")[0] +"@yourTenant.onmicrosoft.com")}

Note that we could have done all this in one command without the intermediate variable. But it's nice to actually see the group we intend to change things before we actually apply changes (using the Set-DistributionGroup command) just to make sure.

domain, list all emails for

Get-MsolUser | where {($_.userprincipalname -match "yourDomain.com")}

or

Get-Mailbox *yourDomain.com

list shared mailboxes for a domain with who has permissions on them

Get-Mailbox *yourDomain.com | Get-MailboxPermission | where {$_.user.tostring() -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false} | Select-Object Identity, User, AccessRights

domains, sort email boxes by - see mailboxes, sort by domain

–E–

email traffic

Best place I've found to get this is directly from the message trace log. I've had pretty good luck with Get-DetailedMessageStats.ps1. It neatly summarizes traffic by email box per day with separate columns for inbound & outbound counts & sizes. The only weird things were:

  1. Even though I specified credentials as an argument, it still insisted on collecting them from me
  2. Although it claims to attempt to grab all the data available in the log (which I would think would be around 30 days), It only got 3 days' worth

There's other traffic besides sent/received emails - at least as measured by our gateway. Such traffic that comes to mind is Outlook fetching email for non-cached clients. Haven't figured out how to capture that from the server yet.

emails, find all emails with some subject in some user's email box - see subject of email, find

–F–

FullAccess delegated, to which users does a particular user have this access? - see delegated mailboxes that a user has FullAccess

–G–

GAL - see Global Address List (GAL) (or Offline Address Book / OAB), suppress entries

Get-MailboxStatistics

individual

Get-MailboxStatistics -Identity "someUser@yourTenant.com"

By default, this command also gives the LastLogonTime but it does not give what we care most about: how big the dang box actually is. So make sure that shows up in the output, too.

Get-MailboxStatistics -Identity "someUser@yourTenant.com" | ft DisplayName, ItemCount, TotalItemSize

for a domain

What if you only care about a certain domain's emails?

Get-MsolUser | where {($_.userprincipalname -match "yourDomain.com")} | % {Get-MailboxStatistics $_.userprincipalname}

Sometimes this causes and error for some records which don't exist

The specified mailbox "someUser@yourDomain.com" doesn't exist.

You can try this instead to bypass that error

Get-Mailbox *yourDomain.com | Get-MailboxStatistics | select DisplayName, ItemCount, TotalItemSize | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\fileBaseName$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"

But this might find duplicate names:

The specified mailbox "Some User" isn't unique.


for the whole tenant

get-mailbox | get-mailboxstatistics | select DisplayName,ItemCount,TotalItemSize | export-csv "MailboxSizes.csv"

this often finds the same problem with duplicate names
Also, this only gives the mailbox size in MB/GB with actual size behind in parentheses. I usually split this cell in Excel using the data function. It'd be nice if I could find a PowerShell command that would do all this in one fell swoop. Maybe someday.

Global Address List (GAL) (or Offline Address Book / OAB), suppress entries - the key is either:


Cloud only (not local AD)

This first section assumes that you want to change this attribute for cloud-only IDs that are not synced with local AD.

To list mailboxes showing the status of this attribute

Get-Mailbox | Sort-Object HiddenFromAddressListsEnabled,displayName | ft identity,displayName,HiddenFromAddressListsEnabled

list individuals whose status is false or null

Get-Mailbox | ? {($_.HiddenFromAddressListsEnabled -eq $true) -or ($_ .HiddenFromAddressListsEnabled -eq $null) } | ft identity,displayName,HiddenFromAddressListsEnabled

how to change this attribute for an individual

If a user has an email license, the following two commands will work to find …

Get-Mailbox -Identity someuser@yourTenant.onmicrosoft.com | ft identity,displayName,HiddenFromAddressListsEnabled

…and remove them from showing up in the GAL or OAB

Set-Mailbox -Identity someuser@yourTenant.onmicrosoft.com -HiddenFromAddressListsEnabled $true

 

Bulk method #1: Set-MailUser

But what if these users don't have an email license but have that annoying "HiddenFromAddressListsEnabled" set to "$false" (the default)? They'll still show up in the GAL and you can't get at them using the Get-Mailbox command as we do above! This comes up if we had a user that was synced with local AD and an email license, deleted him, and then restored him and take away his email license. We do this, for instance, if we move him from one tenant to another but decide to let him hang around in some capacity with no email license but perhaps a SharePoint license. Assume that we only care about "real" emails and not emails ending with "*.onmicrosoft.com". This command all by itself finds them:

Get-MailUser | Where {($_.UserPrincipalName -like '*onmicrosoft.com') -and ($_.HiddenFromAddressListsEnabled -eq $False)

And then this following command goes one step further to gets rid of the offending "HiddenFromAddressListsEnabled" by setting it to "true".

Get-MailUser | Where {($_.UserPrincipalName -like '*onmicrosoft.com') -and ($_.HiddenFromAddressListsEnabled -eq $False)} | ForEach-Object {Set-MailUser $_.userprincipalname -HiddenFromAddressListsEnabled $true}

 

Bulk method #2: Set-Mailbox

Sometimes, even though these users don't have a license, using the Set-Mailbox command instead of Set-MailUser works anyway:

$onmicrosoftUsersNotHidden = Get-Mailbox *onmicrosoft.com -filter {HiddenFromAddressListsEnabled -eq $False}

Note that, unlike other commands, for Get-Mailbox it seems that using Where in a pipe after the initial command won't filter properly. Instead, you must apply the filter immediately after the Get-Mailbox with a simple wildcard - "*onmicrosoft.com" in this case

Optional: make sure we have the right users before actually applying our changes:

$onmicrosoftUsersNotHidden | ft userPrincipalName,displayName,HiddenFromAddressListsEnabled

Now proceed to actually do what we set out to do: hide these users from showing up in the GAL

$onmicrosoftUsersNotHidden | % {Set-Mailbox -identity -identity $_.identity -HiddenFromAddressListsEnabled $true}


local AD users (not cloud-only)

$DepartingUserIdentity = "someUser";

Set-ADUser -identity $DepartingUserIdentity -add @{msExchHideFromAddressLists = $True}

Or maybe “replace” instead of “add” if the value is not null (haven't tested)

GUID for a mailbox

Get-Mailbox -identity someuser | select DisplayName, GUID, ExchangeGUID

–H–

HiddenFromAddressListsEnabled - this cloud attribute is equivalent to msExchHideFromAddressLists in local AD

What it's set to:

Get-Mailbox "someUser@yourDomain.com" | Select-Object displayName, HiddenFromAddressListsEnabled

To change it:

Get-Mailbox "someUser@yourDomain.com" | Set-Mailbox -HiddenFromAddressListsEnabled $true

–I–

–J–

–K–

kiosk mailbox, filter out from list of mailboxes - see mailbox types, filter out types

–L–

language zone bulk change

set all mailboxes in our Office 365 Tenant to German language

Get-mailbox -ResultSize unlimited | Set-MailboxRegionalConfiguration -Language 1031 -TimeZone "W. Europe Standard Time" -LocalizeDefaultFolderName

as well as set time zone to W. Europe and change all of the default folders

last mailbox login time - see Get-MailboxStatistics

Get-MailboxStatistics -Identity "someUser@yourDomain.com" | ft DisplayName, LastLogonTime

list mailboxes, see mailboxes, list

login time, most recent for mailbox - Get-MailboxStatistics

Get-MailboxStatistics -Identity "someUser@yourDomain.com" | ft DisplayName, LastLogonTime

–M–

mailbox, create

$UPN = "noreply@yourDomain.de"
$LO = "DE"
New-Mailbox -Alias noreply -Name noreply -Firstname noreply -LastName noreply -DisplayName "noreply" -MicrosoftOnlineServicesID $UPN -Password ( ConvertTo-SecureString -String 'topSecret' -AsPlainText -Force) -ResetPasswordOnNextLogon $true

Need to assign a location before we can assign a license. But we have to wait a bit after creation before we can set a location. So wait a few seconds.

start-sleep -s 20
set-msoluser -userprincipalname $UPN -UsageLocation $LO

Now assign a license. But we have to wait a bit after setting location before we can assign a license. So wait a few seconds.

start-sleep -s 20
Set-MsolUserLicense -UserPrincipalName $UPN -AddLicenses "yourTenant:EXCHANGESTANDARD_DE"

mailbox types, filter out types

filter out:

Get-Mailbox -ErrorAction SilentlyContinue -identity $_.UserPrincipalName `
    -Filter {(-not(RecipientTypeDetailsValue -eq 'SharedMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'RoomMailbox')) `
    -and (-not(RecipientTypeDetailsValue -eq 'EquipmentMailbox')) -and (ExchangeUserAccountControl -ne 'AccountDisabled') `
    -and (HiddenFromAddressListsEnabled -eq $false) -and (MailboxPlan -notlike "ExchangeOnlineDeskless*")} | `
    Sort-Object MailboxPlan, Identity | `
    Select-Object DisplayName, WindowsEmailAddress, MailboxPlan | Export-Csv "EmailList.csv"

I could not filter out Kiosks. When I try to filter, you always get 0 records. But you can sort. So, sort, include that value in the display & lop off bottom records.

mailbox size - see Get-MailboxStatistics

mailboxes, list

This also sorts by domain

Get-Mailbox | Select-Object @{n="Dom";e={$_.UserPrincipalName.split("@")[1]}}, displayName, userprincipalname | Sort-Object dom, displayName

mailboxes, sort by domain

Get-Mailbox | Select-Object @{n="Dom";e={$_.UserPrincipalName.split("@")[1]}}, displayName, UserPrincipalName | Sort-Object dom, displayName

mailboxes which are deleted, list - see deleted mailboxes, list

message trace - see trace message

most recent mailbox login time - see Get-MailboxStatistics

Get-MailboxStatistics -Identity "someUser@yourDomain.com" | ft DisplayName, LastLogonTime

msExchHideFromAddressLists - this local AD attribute is equivalent to HiddenFromAddressListsEnabled in the cloud

–N–

–O–

Off-line Address Book (OAB), suppress entries from - see Global Address List (GAL), suppress entries

out of office message, see status

Get-Mailbox someUser@yourDomain.com | Get-MailboxAutoReplyConfiguration | select AutoReplyState, ExternalMessage, InternalMessage | fl

out of office message, specify

Initialize some variables

$message = "Hi. Thank you for your email. Bob Smith has left the company.
Please update your records with our accounts email address: accounts@yourDomain.com "
$EmployeeDetails = Get-ADUser Bob.Smith -properties *

Run the command

Set-MailboxAutoReplyConfiguration -Identity $EmployeeDetails.Mail -AutoReplyState enabled -ExternalAudience all -InternalMessage $message -ExternalMessage $message

Verify results

Get-MailboxAutoReplyConfiguration -Identity $EmployeeDetails.Mail

out of office message, turn off

Set-MailboxAutoReplyConfiguration -Identity someUser@yourDomain.com -AutoReplyState disabled

I sometimes like to go a step further and also clear out messages

Set-MailboxAutoReplyConfiguration -Identity someUser@yourDomain.com -AutoReplyState disabled -InternalMessage "" -ExternalMessage ""

–p–

permissions, assign mailbox permissions/delegation of one user to another user

The command below will give the user (perhaps a sysadmin) access to all mailboxes. The “Automapping $false” means that, even though the user will have permissions/be a delegate, the other peoples' mailboxes will not automatically show up in his Outlook

Get-Mailbox -ResultSize Unlimited | Add-MailboxPermission -AccessRights FullAccess -Automapping $false -User someuser@yourdomain.com

To give just one delegated user access to one source user (and also make sure that the other person's mailbox will automatically show up in his Outlook):

Get-Mailbox "sourceUser@yourDomain.com" | Add-MailboxPermission -AccessRights FullAccess -Automapping $true -User "targetUser@yourDomain.com"

or simpler:

Add-MailboxPermission -Identity sourceUser -AccessRights FullAccess -Automapping $true -User "targetUser@yourDomain.com"

Unlike the full access delegation above, you can't add "SendAs" permission with UserPrincipalName. Instead, you have to apply the "SendAs" permission using Identity.

$DepartingUserIdentity = "sourceUser";
$DelegatedUserIdentity = "delegatedUser";
Add-RecipientPermission $DepartingUserIdentity -AccessRights SendAs -Trustee $DelegatedUserIdentity -Confirm:$False

proxyAddresses, add or delete

user

$OldToDelete = "SMTP:" + $identity + "@" + $TenantDomain
$NewToAdd = "smtp:" + $identity + "@" + $TenantDomain
Set-Mailbox -Identity $identity -EmailAddresses @{Add = $NewToAdd; remove = $OldToDelete}

can not change proxyAddresses using Set-MsolUser

add proxyAddresses for contacts - see contacts, proxyAddresses add

proxyAddresses, find match

Get-MsolUser -all | where-Object {$_.ProxyAddresses -match "someaddress" } | fl

proxyAddresses for contacts - although local AD contacts have "proxyAddresses", on Office 365 this property translates to "emailAddresses" - see contacts, display proxyAddresses and targetAddress

proxyAddresses, list for a contact - see contact info (with proxyAddress),

proxyAddresses, list for a user

Get-MsolUser -UserPrincipalName someUser@yourDomain.com | Select-Object DisplayName, UserPrincipalName, proxyAddresses

or

Get-Mailbox someUser | fl EmailAddresses

also show the primary proxyAddress

Get-MSOLUser -UserPrincipalName someUser@yourDomain.com | Select userprincipalname, @{e={$_.ProxyAddresses -cmatch '^SMTP\:.*'};name='Primaryaddress'},Proxyaddresses

public folders, list

Get-PublicFolder -resultsize unlimited -recurse

–Q–

–R–

resources, set delegates - see permissions, assign mailbox permissions/delegation of one user to another user

room, create

Create on local AD as a regular user & sync.
Temporarily assign a license, log in as the new user using WebMail to "force" creation of a mailbox.
Make sure the mailbox exists:

Get-Mailbox -Identity MeetingRoom4@yourDomain.com

Convert to a room:

Set-Mailbox -identity MeetingRoom4@yourDomain.com -Type Room

Don't forget to take away the license when you're done.

rooms, set delegates - see permissions, assign mailbox permissions/delegation of one user to another user

rules, list

Get-InboxRule -mailbox someUser | select name, enabled, description | fl

–S–

SendAs permission delegation

check for one person

Get-Mailbox -identity mailboxToAllowPerm | Get-RecipientPermission -AccessRights SendAs -Trustee whoNeedsPerm

delete SendAs permission for every mailbox to which a user has such permission

$DepartingUserIdentity = "bob"

$departedRecipientPerm = Get-Mailbox | Get-RecipientPermission -AccessRights SendAs -Trustee $DepartingUserIdentity
$departedRecipientPerm | % {Remove-RecipientPermission $_.Identity -AccessRights SendAs -Trustee $_.User -Confirm:$False}

grant SendAs permission on a shared mailbox to a delegate's mailbox

Add-RecipientPermission someSharedMailbox@yourDomain.com -AccessRights SendAs -Trustee someUser@yourDomain.com -Confirm:$False

SendOnBehalfTo, add this permission for a user on a shared mailbox - I have seen where attempting to add through the GUI appears as if it gives the proper permissions but really doesn't

first view

Get-Mailbox -identity someSharedMailbox@yourDomain.com | Select-Object GrantSendOnBehalfTo

then change

Set-Mailbox someSharedMailbox@yourDomain.com -GrantSendOnBehalfTo @{add="whoYouWantToHaveAccess@yourDomain.com"}

or

Set-Mailbox 'someSharedMailbox' -GrantSendOnBehalfTo @{add="whoYouWantToHaveAccess@yourDomain.com"}

or even

Set-Mailbox 'someSharedMailbox' -GrantSendOnBehalfTo @{add="whoYouWantToHaveAccess"}

SendOnBehalfTo, find all mailboxes to which a user has been delegated - see delegated mailboxes that a user has SendOnBehalfTo

shared mailbox, convert individual mailbox to shared mailbox

Set-Mailbox "someUser@yourDomain.com" -Type shared

shared mailbox doesn't show up in outlook - see delegates don't show up as expected in Outlook

shared mailbox, filter out from list of mailboxes- see mailbox types, filter out types

shared mailboxes, list all

Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited | Select Identity,Alias,PrimarySmtpAddress,WindowsEmailAddress,UserPrincipalName,DisplayName | sort displayname

shared mailboxes, list all shared mailboxes upon which a user has permissions

full access

Get-Mailbox | Get-MailboxPermission -user "someUser@yourDomain.com"

SendOnBehalfOf

Get-Mailbox | ? {$_.GrantSendOnBehalfTo -match "someUser@yourDomain.com"}

shared mailbox, list delegates

Get-Mailbox -Identity someuser | Get-MailboxPermission | where {($_.IsInherited -eq $False) -and -not ($_.User -like "NT AUTHORITY\SELF")} | ft identity,user,accessrights

shared mailboxes, list who's delegated to each for a domain

First, stash the mailboxes into a variable. If you only want to list the shared mailboxes and don't care about delegates, you can dispense using the variable as an intermediate step and can stop here. But in the next step we'll list the delegates using the contents of this variable.

$mailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited | `
    where {$_.PrimarySmtpAddress -match "yourdomain.com"} | `
    Select Identity,Alias,DisplayName,user,AccessRights | sort displayname

Now list the delegates for each of these shared mailboxes.

$mailboxes | sort displayname | foreach {Get-MailboxPermission -Identity $_.alias | `
    where {($_.IsInherited -eq $False) -and -not ($_.User -like "NT AUTHORITY\SELF") } | `
    ft identity,user,accessrights} > somefile.txt

shared mailbox, remove automapping for several users - see automap a shared mailbox, remove for several users

size of mailbox - see Get-MailboxStatistics

spam message trace

Show spam for the past week

Get-MessageTrace -Start (Get-Date).AddDays(-7) -End (Get-Date) -Status "FilteredAsSpam" | `
    Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\FilteredAsSpam$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"

Note that we put in the FilteredAsSpam as part of the base search rather than piping unfiltered results to a where clause. You can only get up to 1000 records at a time. Depending on how much spam is being filtered, if you don't add the filter right up front, you may get very few records for the week - only the most recent ones. Even with the filter up front, you may not get a whole week's worth

For a particular user's history

$spamTraces = Get-MessageTrace -Start "10/25/2018 5 PM" -End "11/01/2018 4:00 PM" -Sender "someUser@yourDomain.com" | Where {$_.Status -eq "FilteredAsSpam"}

and then expand for more detail

$spamTraces | Get-MessageTraceDetail | Select-Object MessageID, Date, Event, Action, Detail, Data | ogv

special characters, export users into CSV

Get-MsolUser -all | select displayName, userprincipalname | export-csv 'Users.csv' -Encoding UTF8

subject of email, find

Let's say you want to see all the emails with a subject of "Some Important Subject" in Bob Smith's email box. You must specify a "TargetMailbox" and a "TargetFolder". So we'll specify Sam Snead's ("snead") mailbox and "BobSmith" as a directory in Sam Snead's in box:

Search-Mailbox "Bob Smith" -SearchQuery 'Subject:"Some Important Subject"' -TargetMailbox snead -TargetFolder BobSmith

As soon as the command above finishes, Sam Snead will see a new "BobSmith" as a directory in Sam Snead's in box (in Outlook). Under that he'll see a directory named something like "Bob Smith-11/5/2018 8:54:34 PM" and under that "Primary Mailbox" and then under that a list of the various folders which might contain the emails.

Actually, you don't really have to specify a "TargetMailbox" and a "TargetFolder" if all you want to do is delete these. If that's all you want, then see delete emails where you'll see that you can simply specify -DeleteContent there instead.

See here for discussion and more examples.

switch users

sometimes we want to move a user to a whole new division but leave their mailbox behind for their supervisor or successor to inherit. We want the user's local AD to stay intact so all their bookmarks, cookies, passwords, etc. stay intact. So we'll create a whole new ID in their old division, move the user's old mailbox over to the new ID, convert the new ID to a shared mailbox, and delegate that to their successor

So create the new user. Use different userPrincipalName, targetAddress. Leave proxyAddresses blank for now.

Stash the old ImmutableIDs

$oldUserImmutableID = (Get-MsolUser -UserPrincipalName oldUser@yourDomain.com).ImmutableID

$newUserImmutableID = (Get-MsolUser -UserPrincipalName newUser@yourDomain.com).ImmutableID

Change UPN, email, main proxyAddress for old user.

The next step is very important: make sure that your old user doesn't have its targetAddress or proxyAddresses duplicated somewhere else.

$userString = "oldUserNameFragment"
Get-MsolUser | where {($_.userprincipalname -match "$userString") -or ($_.ProxyAddresses -match "$userString") } | `
    Select-Object DisplayName, UserprincipalName, ProxyAddresses
Get-ADUser -Filter "ProxyAddresses -like '*$userString*'" -Properties DisplayName, UserprincipalName, ProxyAddresses, TargetAddress | `
    Select-Object DisplayName, UserprincipalName, ProxyAddresses, TargetAddress | ogv
Get-ADUser -Filter "TargetAddress -like '*$userString*'" -Properties DisplayName, UserprincipalName, ProxyAddresses, TargetAddress | `
    Select-Object DisplayName, UserprincipalName, ProxyAddresses, TargetAddress | ogv

Carefully examin for dupes. If you're satisfied, sync. If you missed a dupe, the next steps will work but you won't be able to create a new mailbox for the old user.

Assign old email proxy to new user. Sync. Move both new and old users out of OUs that are synced to an OU that isn't. Sync again. This will soft-delete both users so we can muck around with their ImmutableIDs. Verify that both are soft deleted.

Get-MsolUser -All -ReturnDeletedUsers | Sort-Object UserPrincipalName | ft UserPrincipalName, DisplayName, ObjectId, ImmutableID

Restore users as "floaters"

Verify

Clear immutableIds of floaters

Switch ImmutableIDs

Verify reassigned ImmutableIDs

Restore both soft-deleted users by moving their IDs back to synced OUs in local AD and syncing. This is where, if you weren't careful with making sure the targetAddresses and proxyAddresses were unique, problems.

Sync Errors - see DirSync errors, list

–T–

targetAddress for contacts - although local AD contacts have "targetAddress", on Office 365 this property translates to "externalEmailAddress" - see contacts, display proxyAddresses and targetAddress

time of last mailbox login - see Get-MailboxStatistics

time zone bulk change

set all mailboxes in our Office 365 Tenant to W. Europe Standard Time

Get-mailbox -ResultSize unlimited | Set-MailboxRegionalConfiguration -Language 1031 -TimeZone "W. Europe Standard Time" -LocalizeDefaultFolderName

as well as set language to German and change all of the default folders

trace message - (for emails, not calendars; for calendars, see calendar activity, examine log instead) - see also spam message trace

Log times are in UTC - which isn't necessarily the same time zone that your emails are in. If you don't want to mess with UTC offset in the command and just want to find by UTC:

Get-MessageTrace -Start "9/20/18 8 pm" -End "9/20/18 9 pm" -Sender "haplessUser@yourDomain.com" | Select-Object Received, SenderAddress, RecipientAddress, Subject, Status, ToIP, FromIP, Size, MessageID, MessageTraceID | Where {$_.Status -eq "Failed"} | Out-GridView

But it's useful to search for messages using the same time as your local time zone. So start by finding the offset:

$rawUTCOffset = (([TimeZoneInfo]::Local).BaseUtcOffset).TotalHours
$adjustedUTCOffset = if ((Get-Date).IsDayLightSavingTime()) {$rawUTCOffset+1} else {$rawUTCOffset}

Once you know offset, you can more accurately find stuff by searching for time spans that make sense to you in the time zone where you are:

Get-MessageTrace -Start ([datetime]"10/11/2018 11:30 PM").AddHours($adjustedUTCOffset*(-1)) -End ([datetime]"10/11/2018 11:50 PM").AddHours($adjustedUTCOffset*(-1)) `
    -Sender "some.user@yourDomain.com" | Where {$_.Subject -like "Email subject*"} |`
    Select-Object @{n="UTReceived";e={$_.Received}}, @{n="YourLocalTime";e={$_.Received.AddHours($adjustedUTCOffset)}}, `
    @{n="SomeOtherTimeMaybeEurope";e={$_.Received.AddHours(1)}}, SenderAddress, RecipientAddress, Subject, Status, size | ogv

trace message including a wild card

Get-MessageTrace -Sender "someUser@yourDomain.com" -Start (Get-Date).AddDays(-7 ) -End (Get-Date) | ? {$_.RecipientAddress –like "someOtherUser*"} | ogv

you can put in wildcard ("*") immediately before or after the "@" for the recipient or sender. But I haven't had luck putting something like "@yourDomain.*" - system complains "Invalid RecipientAddress value"

filtering on subject:

Get-MessageTrace -Start "9/7/18 1:50 pm" -End "9/7/18 11 pm" | Where {$_.Subject -like "*xyz*"} | Out-GridView

trace message that have errors

You can also get more detail on errors. You can start with the general info (usually with a very narrow time window which I determine by looking at previous Get-MessageTrace statements without specifying Failed):

Get-MessageTrace -Start "10/03/18 10:25:30 am" -End "10/03/18 10:25:35 am" | Where {$_.Status -eq "Failed"} | `
    Select-Object Received, SenderAddress, RecipientAddress, Subject, Status, ToIP, FromIP, Size, MessageID, MessageTraceID |`
    Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\failedDeliveries$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"

and then pipe that same statement into another Get-MessageTraceDetailstatement to get the details associated with the failed emails:

Get-MessageTrace -Start "10/03/18 10:25:30 am" -End "10/03/18 10:25:35 am" | Where {$_.Status -eq "Failed"} `
    | Get-MessageTraceDetail | Select-Object MessageID, Date, Event, Action, Detail, Data | `
    Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\failedDeliveryDetails$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"

If you run both these, to make sense of how they relate to each other, you'll have to open both files side-by-side. But there's a better way where we can see elements of the message we attempted to send along with the error it encountered. This time we do specify fail:

$rawUTCOffset = (([TimeZoneInfo]::Local).BaseUtcOffset).TotalHours
$adjustedUTCOffset = if ((Get-Date).IsDayLightSavingTime()) {$rawUTCOffset+1} else {$rawUTCOffset}
$failedTraces = Get-MessageTrace -Start ([datetime]"10/11/2018 11:30 PM").AddHours($adjustedUTCOffset*(-1)) -End ([datetime]"10/11/2018 11:50 PM").AddHours($adjustedUTCOffset*(-1)) `
    -Sender "haplessUser@yourDomain.com" | Where {$_.Subject -like "some subject*"} | Where {$_.Status -eq "Failed"}
$failedTraces | Foreach-Object{
    $trace = $
    $stats = $trace | Get-MessageTraceDetail -event FAIL
    New-Object -TypeName PSObject -Property @{
        MessageUTCTime = $trace.Received
        MessageLocalTime = $trace.Received.AddHours($adjustedUTCOffset)
        MessageEuropeTime = $trace.Received.AddHours(1)
        Sender = $trace.SenderAddress
        Recipients = $trace.RecipientAddress
        Subject = $trace.Subject
        MessageSize = $trace.Size
        StatusMessage = $stats.Detail
    }} | ogv

For some reason, the order of the columns is completely different from the order above.

For emails older than a week, need to run Start-HistoricalSearch instead.

traffic (email) - see email traffic

–U–

unified group, bulk change email addresses

"unified groups" include

Let's say we want to find all the groups belonging to the "yourdomain" domain and purge all emailAddresses for that same domain. Find all the groups that fit this profile and put it in a variable:

$UnifiedGroup = Get-UnifiedGroup | where-Object {$_.emailAddresses -like "*yourdomain.com" }

Optional: inspect first before proceding to the command that actually applying our changes:

$UnifiedGroup | ft name, emailAddresses

Now proceed to actually do what we set out to do: remove all "emailAddresses" corresponding to our domain:

$UnifiedGroup | % {Set-UnifiedGroup -identity $_.identity -emailAddresses @{remove = "smtp:" + $_.PrimarySmtpAddress.split("@")[0] +"@yourdomain.com"}}

Note that, unlike many other objects, unified groups use "emailAddresses" much the same way as other objects (such as users) use "proxyAddresses". Also note that we could have done all this in one command without the intermediate variable. But it's nice to actually see the group we intend to change things before we actually apply changes (using the Set-UnfiedGroup command) just to make sure.

unified group, bulk change primary SmtpAddress

$UnifiedGp = Get-UnifiedGroup | ? {$_.isdirsynced -eq 0 -and ($_.PrimarySmtpAddress.split("@")[1] -match "yourdomain.com")}

Optional: inspect first before proceding to the command that actually applying our changes:

$UnifiedGp | ft name, emailAddresses

Now proceed to actually do what we set out to do: set "PrimarySmtpAddress" for all users which had corresponding "PrimarySmtpAddress" correpsonding to our domain:

$UnifiedGp | % {Set-UnifiedGroup -identity $_.identity -primarysmtpaddress ($_.PrimarySmtpAddress.split("@")[0] +"@yourTenant.onmicrosoft.com")}

Note that we could have done all this in one command without the intermediate variable. But it's nice to actually see the group we intend to change things before we actually apply changes (using the Set-UnfiedGroup command) just to make sure.

–W–

–X–

–Y–

–Z–