Wednesday, July 4, 2018

Exchange Mailbox Litigation Hold Size Report

Most companies always have some sort of litigation going on, which requires putting users' mailboxes on hold to keep historical data. Sometimes I forget who's on litigation hold, and they stay in that state long after they should be - taking up storage space on Exchange.

I created a little script that will spit out an HTML report of mailboxes with litigation hold enabled and their total size.
This is also useful for when your higher-ups need that info for auditing and such, since it's easy to read in HTML format.

Grab the script from my Google Drive here.


Copy the following block and save as Litigation-Report.ps1

$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }"
$style = $style + "TD{border: 1px solid black; padding: 5px; }"
$style = $style + "</style>"

Get-Mailbox -ResultSize Unlimited -Filter {LitigationHoldEnabled -eq $True} | Get-MailboxStatistics | Sort totalitemsize -desc | select displayname, totalitemsize | ConvertTo-HTML -head $style | out-file Litigation_Size.htm

Once you have the script downloaded or copied, fire up the EMS (Exchange Management Shell) and cd to the location where you saved it.

Next, run Litigation-Report.ps1

The script will save the "Litigation_Size.htm" in the same location as the .ps1 file.

Now you have a nice, pretty report...give it your legal department and tell them they're using too much space :)

Saturday, June 16, 2018

Exchange Get Distribution Groups That Contain Mail Contacts

A lot of organizations, including mine, add external contacts to Distribution Groups. In my case, we have a US and EU business units and users need to be included in groups. A lot of administrative housekeeping involves reporting which of those groups contain contacts.

There's no easy oneliner or a way to grab all the groups at once in the EAC or ADUC to get that info, so I threw together a quick little script that will list those DL's for us.

You can grab the script from my Google Drive here


Copy the following block into Notepad and save it as something like Get-DL-Contacts.ps1

foreach($dl in get-group -resultsize unlimited )
  foreach ($member in $dl.members)
   $recipient = ($member | get-recipient -erroraction silentlycontinue)
   if ($recipient.RecipientType -eq "MailContact")
    Write-Host "$($dl.Name) Contains Contacts"

Once you have the .ps1 file, fire up the Exchange Management Shell, cd to the location you saved it and run Get-DL-Contacts.ps1

**Note** If you need to report on Mail Users instead of Contacts, change the $recipient.RecipientType -eq "MailContact") to $recipient.RecipientType -eq "MailUser")

Depending on the amount of distros you have, it might take a while to run (I have 1500 and it took about 30 minutes) but when it completes, you'll get the list of lists in the PS window.

**Note** When I have time I'll update the script to list both the DL's and the actual contacts within each one...unless one of my readers wants to do that for me :)

Saturday, May 26, 2018

Exchange (One of Many Reasons) IIS Worker Process Using 99% Memory

Our Infrastructure Team had to bounce a domain controller in the middle of the day (yeah they didn't listen to me and did it anyway).
After which, one of my Exchange 2016 Mailbox Servers puked it's guts out every time I tried a PowerShell cmdlet; restarting the EMS resulted in WinRM errors as well. The machine was also running slow, so I checked task manager and sure enough, RAM was pegged at 99% from an IIS Worker Process.

On a lot of blogs and forums, in order to see what's consuming resources, people say to install procmon, find the PID, get the process name, kill it with an elevated CMD, etc.
I for one, really don't like installing extra software on my Exchange servers. Also, killing an entire IIS service will almost always bounce your client connections, because in Exchange 2013/2016 TONS of backend services run off of IIS. Luckily, there's a much easier way to find out which IIS pool is hogging your resources, and we can recycle that specific pool without killing your connections.

The Fix:

Open IIS Manager (not IIS 6.0)

Click your server name, and then Worker Processes
IIS Manager Worker Process

Click the Virtual Bytes heading twice to sort in descending order.

In my case its the MSExchangePowerShellAppPool consuming all that RAM:

IIS Manager RAM Consumption

**Note** You can get the PID from here without having to install something like procmon ;)

Make sure to close the EMS

Click Application Pools

Right-click MSExchangePowerShellAppPool or whichever pool is consuming your resources.

Hit Recycle:

IIS Manager Recycle Pool

Give it a minute and try the EMS again

That looks much better!

Task Manager Normal RAM

Successful EMS Session
Now, go yell at your infra guys to stop doing destructive things in the middle of a work day!

Sunday, May 13, 2018

Exchange Compare Distribution Group Members to Dynamic Distribution Group Members

I recently "converted" several Distribution Groups to Dynamic Distribution Groups in my Exchange environment. I say "converted" because there's no direct way to do so; you have to build new DDLs, delete the old DLs and move the DisplayNames, SMTP addresses and LegacyDN's over to the new ones.
The issue I had was, we use Attribute15 as our location code, which is where the DDLs pull the membership info from (see this post if you're interested how I created them) and I wanted to make sure that the users who were in the old DLs are also members of the new DDLs. And if they aren't listed in the new ones, most likely the Attribute15 is missing, so we can fix that easily.
There's no way in the EAC to see the members of Dynamic Groups; that has be done in the Shell, so I created a script that will compare Distros to Dynamic Distros, and spit out a CSV report for you.
You can grab the script from my Google Drive here
Copy and past the following block into Notepad, and save as Compare-DL-With-DDL.ps1
$name = Read-Host "Enter a Distribution Group Name"
$DL = Get-DistributionGroupMember –Identity "$name"
$dynname = Read-Host "Enter a Dynamic Distribution Group Name"
$members = Get-DynamicDistributionGroup -Identity "$dynname"
$DDL = Get-Recipient -ResultSize 1000 -RecipientPreviewFilter $members.RecipientFilter
Compare-Object $DL $DDL -IncludeEqual -Property DisplayName | export-csv DLLCompare.csv -notypeinformation
Once you have the script saved, fire up the Exchange Management Shell and cd to the location where you saved it.
Next, run Compare-DL-With-DDL.ps1

The script will prompt you to input the name of a regular Distribution Group

It will then prompt to enter the name of Dynamic Distribution Group

When it finishes, it will create a CSV report in the location where you ran the .ps1 from.

In the report, you'll get the Display Names for the users, and the "SideIndicator" which tells you whether the users exist in both groups, or one or the other.

The side indicators will look like so:

==” indicates that the user is present in both groups
=>;” indicates that the user is present only in the second group, this will be the New DDL
<=” indicates that the user is present only in the first group, the Old DL

And example report would be:

DisplayName               SideIndicator
User1                            ==
User2                            ==
User3                            <=
User4                            <=
User5                            =>
User6                            =>

So, according to the list, we'll need to fix User3 and User4, as they aren't included in the New Dynamic List; something is missing from whatever we filtered on to create the DDL (in my case Attribute15 is empty)

For User5/6 we don't need to worry about them, they probably just weren't manually added to the old list, and from now on they'll get those "all important" pizza lunch emails :)

Now, you have your comparo list, you can hand it off to your AD team to fix attributes, or if you're "lucky" and you do it all yourself, go fix it!

**Note** If you need to hand the report off to non-tech people, you can use Excel  to do Find/Replace to the change the Side Indicators to something readable like "== is Both", "=> is New DDL", "<= is Old DL"

Saturday, April 28, 2018

Exchange Mailbox Migration Batch Error: A subscription wasn't found for this user...

I recently needed to move 49 mailboxes from one Database to another because due to a bug way back in Exchange 2016 CU2, mailbox creation didn't autoprovision them on random databases...it shoved them all onto your first one, and I never got around to redistributing them.

So I created a CSV with the list of mailboxes I wanted to move and created a migration batch.
Some of these mailboxes in the list are GIANT (like 60GB) so naturally it took forever for them to move. So, I had to Suspend them until later.

The problem is, when moving mailboxes in a migration batch, manually suspending them with "Get-MoveRequest -Identity "mailbox" | Suspend-RemoveRequest" causes the EAC to "think" that since the move was suspended outside of the migration, it has failed.

Here's our scenario:

You've started your migration batch "DB01mailboxmoves" and see that they took too long, so in PowerShell you've suspended some of the mailbox moves (but not all) and let the migration batch complete the smaller mailboxes.

Later, for the ones we've suspended, we've run the cmdlet "Get-MoveRequest -MoveStatus Suspended | Resume-MoveRequest" and let those complete.

In the EAC, you can see that the batch has "completed with errors", there are 14 "finalized" moves meaning, the migration batch finished these, but there are 35 "failed" meaning the migration batch no longer has control of them so it cries failure!

EAC Migration Batch

If you hit View details and select one of the "failed" moves, you get a warning banner saying "the subscription for the migration user "emailaddress@domain.com" couldn't be loaded. The following error was encountered: A subscription wasn't found for this user..."

This comes from O365 and has no bearing in on-prem. Why it's present in Exchange 2016 I dunno, maybe Exchange product engineers were too lazy to take it out. But, you can safely ignore it.

And the next one: "Error: ExternallySuspendedException: Email migration failed for this user because the subscription was suspended externally to the Migration Service"

Again, there's no subscription, but it's partially correct: I did suspend the move from outside the migration batch...because there's no way to suspend moves within the migration batch! Again, you can ignore this error.

EAC Migration Errors

Back in the EAC migration control panel, you'll see the last piece of the puzzle. The migration isn't actually running any longer because we've taken control of the moves from within PowerShell. Notice the "play" button:

EAC Migration Play Button

What to do in this case?

Since we've manually resumed the suspended moves and can no longer see the status in the EAC, we'll want to verify that they have completed:

In the EMS, run the following cmdlet:

Get-MoveRequest -MoveStatus Completed

Your successful moves will be listed on the target DB.

Now we'll remove those by running:

Get-MoveRequest -MoveStatus Completed | Remove-MoveRequest -Confirm:$false

Next, we can safely remove the Migration Batch from the EAC:

Hit the trashcan icon in the control panel:

EAC Trashcan Icon
Click Yes:
EAC Yes To Remove

Now all those mailboxes have been successfully moved to another DB...even though the EAC threw a fit about it :)

Saturday, April 14, 2018

Exchange Bulk Create Dynamic Distribution Lists From CSV

Last year I migrated our company from Notes to Exchange 2016, and just recently found out that we're "missing" several Dynamic Distribution Lists...by several I mean 53.
So, instead of doing that all by hand, I thought building a CSV with that info sure would be handy!
I'll show you how to create multiple DDLs from a CSV, using PowerShell.

We're going to create a CSV with all the necessary information to automatically create these DDLs, and we'll be using the AD Custom Attribute 15 for the Location Codes for each group.
Since most DDLs are built by location or OU, that will be the scope of this post. Feel free to leave a comment if you need some other filterable properties.

**Note** We use Attribute15 in my environment to specify the location code (because we run a Resource Forest which syncs over from the Accounts forest), but you can change that to whatever attribute you use...for instance you can choose "ConditionalStateOrProvince" to use the State attribute.
Just change the "Attribute15" column heading to "State" in your CSV.

Create the CSV

Now, we'll create a CSV file in the following format:

Dynamic Distro CSV

In the example CSV, we'll use the following locations (which are populated for my users within CustomAttribute15 in AD):

NYC (New York)
CHI (Chicago)
DAL (Dallas)
BOS (Boston)

The CSV will specify the following:

Name - DDL Display Name

Alias - DDL Alias

OU - The Organizational Unit where the DDLs will be created e.g. "domain.com/DistributionLists"

Attribute15 - CustomAttribute15 (where the location code is stored)

Recip (RecipientTypes) - "MailboxUsers, MailContacts, MailUsers"

Email (PrimarySMTP) - The primary email address of each DDL e.g "LocAllUsers@domain.com"

Container (RecipientContainer) - Where the DDL will query AD to pull the members from e.g. "OU=Users,DC=domain,DC=com"

Now, save the CSV somewhere like: c:\temp\newdlls.csv

Create the Dynamic Distribution Groups

Once you have your CSV built and saved, run the following cmdlet in the EMS (Exchange Management Shell):

Import-CSV "C:\temp\newddl.csv" | % {New-DynamicDistributionGroup -Name $_.Name -OrganizationalUnit $_.OU -ConditionalCustomAttribute15 $_.Attribute15 -IncludedRecipients $_.Recip -PrimarySmtpAddress $_.Email -RecipientContainer $_.Container}

The cmdlet will call each heading in the CSV, and pipe in the values you have specified for each group.

**Note** If you're using something other than Attribute15 like "State" for instance, in the above cmdlet, change the "-ConditionalCustomAttribute15" switch to "-ConditionalStateOrProvince $_.State" which will then match your CSV heading.

**Note** Depending on how many DDLs you're creating and how large your environment is, this could take a while - meaning the Shell might sit there and "do nothing" for a bit.

Once the cmdlet is finished, you'll see the new DDLs in your "domain.com/DistributionLists" OU, and they'll be populated from the Recipient Container we specified  (OU=Users,DC=domain,DC=com).

All done!

To get a membership report and see that our filters work, you can grab a script I wrote in this post, which will output a nice and pretty HTM file for ya!

Sunday, April 8, 2018

Exchange Reconnecting An Orphaned Linked Mailbox

Here's a "fun" scenario: Exchange is installed in a Resource Forest. A user's AD account in the Accounts Forest was deleted by our SAP automated system (I dunno why does it has so much control), which orphaned the Linked Mailbox because now there's no master account to attach to.

The mailbox isn't listed in the EAC:

EAC Missing Mailbox

And the recipient can't be found:

Get-Recipient sarah.one@exchangeitup.com

The operation couldn't be performed because object 'sarah.one@exchangeitup.com' couldn't be found on 'DC1.exchangeitup.com'.

Running the Get-MailboxStatistics cmdlet, shows that it does exist...but floating around in the ether maybe?

You can see that the mailbox isn't disconnected, but it's also not attached to an account:

Get-MailboxDatabase | Get-MailboxStatistics | Where { $_.DisplayName -eq "sarah one" } | fl DisplayName,Database,DisconnectReason

DisplayName               : Sarah One
Database                       : DB01
DisconnectReason        :

Reconnecting the Mailbox:

Resurrect the Account:

First, we'll need to de-tombstone the AD account in the Accounts forest, then do the same in the Resource Forest.

**Note** You'll need to have the AD Recycle Bin enabled...hopefully you already do. Otherwise, you'll need to create a new account for the user...that's painful.

Connect the Linked Mailbox:

Next, we'll connect the orphaned mailbox to the restored/new AD account. Fire up the EMS (Exchange Management Shell) and run the following:

$cred - Get-Credential

**Note** Passing creds is only required depending on your Trust setup. Once you run the above cmdlet you will input your Accounts Forest admin credentials.

Next, run:

Get-MailboxDatabase DB01 | Get-MailboxStatistics | where ($_.displayname -eq "Sarah One" } | Connect-Mailbox -Alias "SarahOne" -LinkedMasterAccount "exchitup.com\SarahOne" -LinkedDomainController "DC.exchitup.com" -Database DB01 -LinkedCredential $cred

**Note** Change "DB01", displayname, -Alias, -LinkedMasterAccount, -LinkedDomainController, and -Database to match your environment

And, done!

Check the EAC and you'll see the mailbox is alive.

Connecting a User Mailbox:

UserMailboxes don't tend to be "orphaned" very often when a user account is deleted, they just get disconnected.

But just to cover our bases, in case it does happen, the following cmdlet will get it back working.

After you restore the deleted AD account, run the following cmdlet:

Get-MailboxDatabase -Identity "D01"  | Get-MailboxStatistics | Where { $_.Displayname -eq "Sarah One" } | Connect-Mailbox -User "sarahone"

**Note** Again, change "D01", displayname, and -User

Your user should be happy...now fix whatever deleted your accounts!

Saturday, April 7, 2018

Exchange Set Resource Mailbox Calendaring Back To Defaults

If you follow my blog, you know that my company does some wacky (stupid) things with Resource Mailbox booking settings. They want calendars to function like Notes (which I migrated them over to Exchange from) and instead of letting Exchange manage calendars, we end up changing things that don't follow best or even sane practice.
Most of the time, they end up asking me to revert those settings. The problem is: I've changed so many settings over the months, I can't remember every thing that I was asked to set.
It'd be nice if there was a Set-RoomBackToDefault cmdlet, but there's not. So I cooked up a quick-and-dirty script that will set all settings on a Resource Mailbox back to default. This will save you time from deleting and re-creating the Mailbox!

Here's some settings that I've been asked to set. This is just an example, but it sets the Room to allow me (the delegate) to book without requiring myself to accept/decline my own meetings, but requires all other users to book through me; allows conflicts; allows the subject; and allows text in the body (comments).

Set-Calendarprocessing "test room" -AllowConflicts $true -DeleteComments $false -AddOrganizerToSubject $false -DeleteSubject $false -AllBookInPolicy $false -AllRequestOutOfPolicy $false -AllRequestInPolicy $true -BookInPolicy "stacey branham" -ResourceDelegates "Stacey Branham"

Get-CalendarProcessing "test room" | fl

AutomateProcessing                            : AutoAccept
AllowConflicts                                     : True
BookingWindowInDays                      : 180
MaximumDurationInMinutes              : 1440
AllowRecurringMeetings                     : True
EnforceSchedulingHorizon                  : True
ScheduleOnlyDuringWorkHours         : False
ConflictPercentageAllowed                  : 0
MaximumConflictInstances                  : 0
ForwardRequestsToDelegates               : True
DeleteAttachments                                 : True
DeleteComments                                    : False
RemovePrivateProperty                         : True
DeleteSubject                                         : False
AddOrganizerToSubject                        : False
DeleteNonCalendarItems                       : True
TentativePendingApproval                    : True
EnableResponseDetails                          : True
OrganizerInfo                                         : True
ResourceDelegates                                 : {exchangeitup.com/Users/staceybranham}
RequestOutOfPolicy                              : {}
AllRequestOutOfPolicy                         : False
BookInPolicy                                          : {/o=exchangeitup/ou=Exchange Administrative Group
(FYDIBOHF23SPDLT)/cn=Recipients/cn=026f8db5e35544e082e8c123cf9c190f- staceybranham}
AllBookInPolicy                                    : False
RequestInPolicy                                     : {}
AllRequestInPolicy                                : True
AddAdditionalResponse                        : False
AdditionalResponse                               :
RemoveOldMeetingMessages               : True
AddNewRequestsTentatively                : True
ProcessExternalMeetingMessages         : False
RemoveForwardedMeetingNotifications : False
ObjectState                                              : Changed

I created the following script to ask you to provide a Resource Mailbox name (this way you don't have to edit the script itself every time you run it), then it will run against that Resource Mailbox and set all settings to default according to this MS TechNet Article.
This basically saves you from typing all the switches mentioned in the above article, manually ;)

You can grab the script from my Google Drive here


Copy and paste the following block into Notepad, and save as Set-Calendar-Defaults.ps1

$name = Read-host "Enter a Resource Mailbox Name"
Set-CalendarProcessing -Identity $name -AddAdditionalResponse $false -AddNewRequestsTentatively $true -AddOrganizerToSubject $true -AllBookInPolicy $true -AllowConflicts $false -AllowRecurringMeetings $true -AllRequestInPolicy $false -AllRequestOutOfPolicy $false -AutomateProcessing AutoAccept -BookingWindowInDays 180  -BookInPolicy $null -ConflictPercentageAllowed 0 -DeleteAttachments $true -DeleteComments $true -DeleteNonCalendarItems $true -DeleteSubject $true -EnableResponseDetails $true -EnforceSchedulingHorizon $true -ForwardRequestsToDelegates $true -MaximumConflictInstances 0 -MaximumDurationInMinutes 1440  -OrganizerInfo $true -ProcessExternalMeetingMessages $false -RemoveForwardedMeetingNotifications $false -RemoveOldMeetingMessages $true -RemovePrivateProperty $true -RequestInPolicy $null -RequestOutOfPolicy $null -ResourceDelegates $null -ScheduleOnlyDuringWorkHours $false -TentativePendingApproval $true; Get-CalendarProcessing -Identity $name | FL

Once you have the .ps1 saved, fire up the Exchange Management Shell (EMS) and run Set-Calendar-Defaults.ps1

You will prompted to input a Resource Mailbox:

EMS Set Calendar Defaults

Enter the mailbox name (it doesn't need quotes around it) and the script will fire off.

After the script sets the defaults, it will then automatically run the Get-CalendarProcessing cmdlet on the mailbox you ran the script against to show that the revert-to-default was successful:

AutomateProcessing                         : AutoAccept
AllowConflicts                                  : False
BookingWindowInDays                    : 180
MaximumDurationInMinutes            : 1440
AllowRecurringMeetings                   : True
EnforceSchedulingHorizon                : True
ScheduleOnlyDuringWorkHours       : False
ConflictPercentageAllowed                : 0
MaximumConflictInstances                : 0
ForwardRequestsToDelegates             : True
DeleteAttachments                              : True
DeleteComments                                 : True
RemovePrivateProperty                       : True
DeleteSubject                                       : True
AddOrganizerToSubject                      : True
DeleteNonCalendarItems                     : True
TentativePendingApproval                  : True
EnableResponseDetails                        : True
OrganizerInfo                                       : True
ResourceDelegates                               : {}
RequestOutOfPolicy                            : {}
AllRequestOutOfPolicy                       : False
BookInPolicy                                       : {}
AllBookInPolicy                                  : True
RequestInPolicy                                   : {}
AllRequestInPolicy                              : False
AddAdditionalResponse                      : False
AdditionalResponse                             :
RemoveOldMeetingMessages             : True
AddNewRequestsTentatively              : True
ProcessExternalMeetingMessages      : False
RemoveForwardedMeetingNotifications : False
ObjectState                                          : Changed

Now, all settings are back to the way they were when you first created the mailbox; and surprise surprise, it works pretty well out-of-the-box...tell your users that!

Saturday, March 17, 2018

Exchange Resource Mailbox Exclude Delegates From Accepting/Denying Their Own Meetings

When you have a Resource Mailbox set to require Delegates to manage meetings, the default setting is that meetings from all users must be accepted/rejected by Delegates. Even the Delegates' own meetings. This is counterintuitive, since of course the Delegate would know when the Resource is free or busy. The default settings should exclude the Delegates, but we can't have everything we ask for, can we Microsoft?

In order to exclude the Delegates from accepting/denying their own meeting requests, we need to manually change the BookInPolicy on the mailbox; in Exchange 2013/2016 it must be done in PowerShell...there's no option to change it in the EAC.

The requirements for the Resource Mailbox to allow Delegates to book automatically, but require all other users to book with approval are as follows:

All Book In Policy: False

All Request Out of Policy: False

All Request In Policy: True

Book in Policy: One or More Users/Group Defined

Resource Delegates: One or More Delegates Defined

Fire up the Exchange Management Shell (EMS) and run the following cmdlet to set the above options:

Set-CalendarProcessing "Conference Room HR" -BookInPolicy "receptionist@exchangeitup.com","assistant@exchangeitup.com" -AllBookInPolicy $False -AllRequestOutOfPolicy $False -AllRequestInPolicy $True

**Note** Change "Conference Room HR" to the name of your Resource Mailbox, and "receptionist@exchangeitup.com","assistant@exchangeitup.com" to the email addresses of your Delegates.

**Note** I'm assuming you already have Resource Delegates set on the Mailbox, but if you need to add those as well, just include -ResourceDelegates "receptionist@exchangeitup.com","assistant@exchangeitup.com" in your cmdlet

What this cmdlet does is sets the Resource policies listed above, and adds your Delegates to the "BookInPolicy" list.
You can use a Distribution Group if you have multiple Delegates you want to set; you would just use the DL's email address in place of the Delegates' addresses like so: -BookInPolicy "roommanagersDL@exchangitup.com" -ResourceDelegates "roommanagersDL@exchangeitup.com"

To the check that the settings have been applied to the Resource Mailbox, run:

Get-CalendarProcessing "Conference Room HR" | FL AllBook*,AllReq*,BookInPol*,Request*,Resource*

You'll get the following output:

AllBookInPolicy               : False
AllRequestOutOfPolicy    : False
AllRequestInPolicy           : True
BookInPolicy                    : {/o=exchangeitup/ou=Exchange Administrative Group
                                  (FYDIBOHF23SPDLT)/cn=Recipients/cn=91bb55ebc2a64cb4844b31c470833308-                                           receptionist,
                                          /o=exchangeitup/ou=Exchange Administrative Group
                               (FYDIBOHF23SPDLT)/cn=Recipients/cn=f3ac6e3f538d47f19da77d79b6f7a407-                                          assistant}
RequestOutOfPolicy        : {}
RequestInPolicy               : {}
ResourceDelegates           : {exchangeitup.com/Mailboxes/assistant,


In the above output, you can see that your Delegates are now listed in the "BookInPolicy" in LegacyDN format.

Now to test, have one your Delegates schedule a meeting in that Room and see that the request will automatically be accepted or denied based on availability and they don't get the request itself forwarded to their mailbox.

You should have happy Delegates now that they don't get tons of requests coming in...I usually advise organizations to always use automatically booking because it saves a lot of work for both the Exchange admin and the delegates, and 99% of the time I end up being told to switch the rooms back to auto-booking when the delegates get tired of managing so many requests...maybe they should listen to me in the first place.

Sunday, March 4, 2018

Exchange Automatically Enable OWA For New Mailboxes

My Exchange 2016 resides in a Resource Forest in the US and I share an Accounts Forest with our EU parent company who also has an Exchange 2016 Resource Forest. We use the same mailbox provisioning script for both Exchange environments, which simplifies the creation process, but I don't run the same configuration as they do in Europe so I have to change a bunch of settings...like enabling OWA for all users.

I'll show you how to set a scheduled task to enable OWA on all new mailboxes so we don't have to do it manually.

Create a Service Account:

First, you'll want to create a Service Account in your domain, which will be used to run the scheduled task. It's best practice to use service accounts rather than your own account to run scheduled tasks, so if you ever leave your position and they deactivate your account, it won't break the task!

In your domain, create a new user called something like exchscriptaccount and set a super-strong password.

This account will need to be a member of the Server Management Role Group, otherwise it won't have permissions to enable OWA on mailboxes.

Next, add the newly created user to the Local Administrators Group on your Exchange Management Tools server or Exchange server if your running it from there. The scheduled task will need local admin rights to run PowerShell things, and since you have a super strong password, it's not an issue.

Creating The Task:

On your Exchange Management Server or an Exchange Server, open the Task Scheduler Control Panel, click Action > Create Task...

On the General tab:

Give it a name like Enable OWA

Click "Change User or Group..." hit "Locations" and switch to your domain, then search for your exchscriptaccount service account.

Check the box for "Run with highest privileges"

On the Triggers Tab:

Click "New..."

Set it for how often you need it to run. I run mine Daily at 12AM - no specific reason, but you do want it to run Daily depending on your onboarding turnover.

On the Actions Tab:

Set the "Action" dropdown to "Start a program"

Under Program/Script, copy/paste the following:


In the "Add arguments" field, copy/paste the following:

-NonInteractive -WindowStyle Hidden -command ". 'C:\Program Files\Microsoft\Exchange Server\V15\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; Get-CASMailbox -ResultSize unlimited | ? {$_.OWAEnabled -eq $False} | Set-CASMAilbox -OWAEnabled $True"

**Note** What this cmdlet does is finds any mailbox with OWA disabled ($False), and sets the flag to $True (enabled)

In the Settings Tab:

Checkmark the following boxes:

- Allow task to be run on demand

- Stop the task if it runs longer than: 1 hour (if it runs longer than an hour, you got something wrong!)

- If the running task does not end when requested, force it to stop

Click OK when you have everything set.

Testing the Task:

In the main task window, right-click your new "Enable OWA" task, and click Run.

When it finishes running, you should have a (0x1) Last Run Result.

Check Our Work:

Check that OWA is set on All Mailboxes by running:

Get-CASMailbox -ResultSize unlimited | ? {$_.OWAEnabled -eq $False}

The output should be empty.

Now, Exchange will do the boring job of turning on OWA for you :)