Finding All Tenants Unassigned Office 365 Licenses

I previously wrote about finding all the mailboxes across your Office 365 tenants, and today I am going to share a function I wrote to find all the unassigned Office 365 licenses across those tenants.  First, I should note that this function is modified off of one I found on the TechNet script gallery but for some reason even after searching through it I cannot seem to find it.  I am also using the MSOnline module for this, even though the new AzureAD module has supposedly replaced it. I have been in contact with someone on the team at Microsoft about what the current limitations are.  However, the functionality doesn’t exist in that module (yet) to get the information that we need so I am continuing to use the MSOnline Module instead.

It’s a pretty straight forward function so I am just going to break down what it does:

  • Connects to Office 365.  You will need to use an account that has delegated admin permissions across your tenants
    • If you have MFA enabled you won’t be able to login (or at least I couldn’t get it to work with my account)
  • Gets a list of all the tenants you have delegated admin access for
  • Creates an Array to store all the information
  • Gets all the associated AccountSkus from each tenant, with the exception of Power_BI and PowerApps
  • Compares the value of ConsumedUnits to ActiveUnits.  If the amount of ConsumedUnits is less than the amount of ActiveUnits, we know that there are unassigned licenses.

That’s all there is to it.  Full function is below.

 

Finding All Client Mailboxes in the Office 365 Partner Portal

Someone at work asked me “how many client mailboxes are we supporting in Office 365?”. It’s easy to tell how many clients you are supporting, as soon as you login to the partner portal it tells you that number. I had never tried to get the number of client mailboxes before, but I strongly suspected that I could do it using PowerShell. Turns out I was right!

The first thing you will need to do is to connect to Office 365 using PowerShell. If you haven’t done this before, go to this page and download the Office 365 PowerShell Module and install it.

After that is done, execute the commands below which will connect you to Office 365. It’s important to note that the credential you use must have delegated admin access to all the client accounts or the steps in this article won’t work.

Once that is done running the commands below will provide a list of all the commands in the MSOnline Module as well as only those commands which contain the word partner. I was hoping there was a cmdlet that would allow me to get all my clients information which I could then iterate through to get a list of all mailboxes.

MSOnlinePartner

The Get-MSOLPartnerContract looks interesting, lets try that.

MSOnlinePartnerContract

Well, that gets me a lot of Tenant ID’s, which doesn’t appear to be useful. Or does it? I know from using Office 365 with PowerShell in the past that there are commands that use the TenantID parameter to retrieve information.

Doing some more investigation I run the series of commands below. First I am storing all the Tenant ID’s in a $Clients variable, and then using Get-Member to see what properties this variable contains. Seeing that one of them is Default Domain Name, I run $Clients.DefaultDomainName which sure enough enumerates all of my client domain names so I can see that they are in fact my clients. I am then storing all the Tenant ID’s in another variable $Tenants which I will be using shortly.

Earlier I mentioned that I knew from past experience that there were cmdlets in the MSOnline module that used TenantID as a parameter. How could I find out what those commands are? By running the command below. I reduced the output by using -Verb Get since I am going to be getting the number of mailboxes.

Scrolling through the list I see that Get-MSOLUser is one of the cmdlets that uses TenantID as a parameter and think that might be a good place to start. I take one of my Tenant ID’s in my $Tenants variable and run the command below.

I was hoping to see that there was a domain or client name property, but unfortunately there is not. So in order to figure that out I ran the commands below. What I am doing here is taking the first user that comes up for the tenant and getting their User Principal Name (UPN). Since each client’s users have the same UPN, this will be OK. After that I am splitting the UPN at the ‘@’ symbol and using that information for the domain. This is definitely not the only way to do this (or probably the best) but it worked for me.

Next I am creating a hashtable with my properties and then creating a new PSObject Object and saving this information to a .CSV file. Notice in the properties section that for the Domain I am having to use $Domain[1] because when it split the UPN at the ‘@’ symbol it split it into two pieces, the section before the ‘@’ and the section after it.

Finally, I have tied all this into a Function I am calling Get-PartnerMailboxes that will iterate through all my Tenant ID’s and create a .CSV listing the domain and total number of licensed users for each tenant.

Installing 2010 Exchange Management Tools on Windows 8

This is all over the internet so it’s nothing new, but since I had to go to a couple of different places to get the whole picture I am putting it here.

You can install Exchange 2010 Management Tools on Windows 8 by temporarily modifying the registry setting below.  Note that the Management Tools need to Exchange 2010 SP2.  Exchange 2010 SP3 doesn’t work because it does an organizational check, which had all kinds of failures about the AD Schema and that I wasn’t a member of Enterprise/Schema Admins (even though I am).

Change the registry value HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionCurrentVersion from 6.2 to 6.1 .  This change will be reverted upon a restart.

Credit for the registry key value goes to this thread where I originally found it.

Exchange 2010 Database Rapidly Increases in Size

Situation:
Windows Server 2008 R2, Exchange 2010 SP1 upgraded from Exchange 2003.  I should note that this upgrade occurred long before this issue happened.  The Exchange server is virtualized on VMWARE ESXi 5.0 Update 1.
Problem:
Thursday, May 31st, at midnight I received an alert that the Datastore my Exchange Database sits on was at 90% capacity.  This was odd because my Exchange Database had been right around 250GB for the last 9 months and the Datastore was 500GB in size.  Somehow it was up to 480GB.  After verifying there was no unusual activity, errors in the event logs, or backup snapshot issues, I doubled the size of the Datastore and went back to sleep.  When I got into the office the next day at 7AM, the Database was up to nearly 600GB in size. Clearly something was not right.
Solution:
Short version:  Install Exchange 2010 SP2 and all the rollup packages.  I ended up getting Microsoft support involved and this is a known issue for Exchange 2010 SP1 and is resolved with Exchange 2010 SP2 Rollup 1.
Longer version: 
For no apparent reason my Exchange Database was increasing by 1-2 GB every 10 minutes.  What started as a 250GB Mailbox Database ended up as a nearly 750GB Database in less than 36 hours.  Multiple server reboots did nothing to resolve the problem.  No users were experiencing issues and there were no errors or warnings of any kinds in the event logs.
Doing some research and reading online, it appeared the issue was possibly caused by a corrupt Mailbox and that moving the Mailboxes to a new Mailbox Database would resolve the issue.  While doing the move, the “old” Mailbox Database continued to grow at the same size, but the “new” one did not.  Everything was looking good I thought.  However, 2 Mailboxes failed to move because of corrupt items.  I moved them successfully by just increasing the number of corrupted items to allow to 10.  No sooner had those 2 Mailboxes moved over than the “new” Mailbox Database started growing at the same rate.  OK then.  Back to the drawing board.
Doing some more research I found that there were Powershell commands that let you repair Mailboxes or the individual Mailbox Databases.  I ran the following commands on the two Mailboxes that had corrupted items and failed the original move.
New-MailboxRepairRequest -Mailbox -CorruptionType SearchFolder,AggregateCounts,ProvisionedFolder,FolderView
New-MailboxRepairRequest -Mailbox    -CorruptionType SearchFolder,AggregateCounts,ProvisionedFolder,FolderView -archive
After those two commands finished, and the event logs showed there was no corruption issues I ran the command against the entire Mailbox Database.
New-MailboxRepairRequest -Database -CorruptionType SearchFolder,AggregateCounts,ProvisionedFolder,FolderView
The event logs also showed that command hadn’t found any corruption either.  So now what?
A post of mine on the Microsoft forums (http://social.technet.microsoft.com/Forums/en-US/exchangesvrgeneral/thread/7de2b043-a5e6-494c-9b2a-5fe2552fa21e/) had gotten some responses indicating that the Exchange User Monitor would help to figure out what user(s) were corrupted and causing the issue.  I installed it, and ran it, but had zero idea what I was looking at and couldn’t find anything that was of much use in telling me how to use it.  Sidenote, if you run it once and close it, apparently it requires a server reboot to run it again.  Good times.
It was at this point, with the “new” Mailbox Database closing in 600GB and the overall size of the Datastore up to nearly 1.4TB at this point that I decided to get Microsoft support involved.  While he couldn’t tell me why the Mailbox Repair Request didn’t find or fix the corrupted Mailboxes, he was positive the issue was fixed in SP2 Rollup Update 1, and it was.  After installing both and rebooting the Exchange server after each installation the Mailbox Database immediately finished growing.
Next thing I did was to move the Mailboxes to another “new” Mailbox Database so that it was the proper size, and then delete the two “old” Mailbox Databases.  Everything has been stable and back to normal ever since the updates were applied.

Failed to Mount Exchange 2010 Database: An Active Manager Operation Failed

This is the error message I received on my Exchange 2010 SP1 Server when creating a new mailbox database:
——————————————————–
Microsoft Exchange Error
——————————————————–
Failed to mount database ‘DBNAME’.


DBNAME
Failed
Error:
Couldn’t mount the database that you specified. Specified database:  DBNAME; Error code: An Active Manager operation failed. Error: The database action failed. Error: Operation failed with message: MapiExceptionNotFound: Unable to mount database. (hr=0x8004010f, ec=-2147221233)
. [Database:  DBNAME, Server: SERVERNAME.DOMAIN.COM].


An Active Manager operation failed. Error: The database action failed. Error: Operation failed with message: MapiExceptionNotFound: Unable to mount database. (hr=0x8004010f, ec=-2147221233)
. [ Database:  DBNAME, Server: SERVERNAME.DOMAIN.COM]


An Active Manager operation failed. Error: Operation failed with message: MapiExceptionNotFound: Unable to mount database. (hr=0x8004010f, ec=-2147221233)
. [ Server: SERVERNAME.DOMAIN.COM]


MapiExceptionNotFound: Unable to mount database. (hr=0x8004010f, ec=-2147221233)


To resolve the issue I ran the command below in Powershell:


  1. Set-ADServerSettings -PreferredServer



Also, it never hurts to check the following while you are at it.  It seems to also resolve the issue.

  1. Open EMC and right-click on “Organization Configuration”.  Choose “Modify Configuration Domain Controller”.
  2. Specify the domain and the DC.
  3. Open EMC and right-click on “Recipient Configuration”.  Choose “Modify Recipient Scope”.
  4. Specify the global catalog server.  Make sure it is the same as the chosen DC.

Import Contacts CSV Into Exchange 2010

Problem:  I need to import 700 of our “key client contacts” into Exchange 2010 from a CSV file

Solution:  Powershell!

Step 1:  Create the CSV

There are a ton of different fields you can use in your CSV to import into Exchange contacts, I am not going to go into them all here, but just check out the set-contact Powershell cmdlet for all your choices.

Because this was a fairly simple import, this is what the headers of my CSV file looked like.

Step 2:  Create the Powershell Script

 Import-CSV C:contacts.csv | ForEach {
 New-MailContact -Name $_.ContactFullName -ExternalEmailAddress $_.ContactEmail
-FirstName $_.ContactFName -LastName $_.ContactLName
-OrganizationalUnit “domain.com/Folder Structure Here”

 Set-Contact -Identity $_.ContactFullName -Phone $_.”ContactPhone” -MobilePhone $_.”ContactMobile”

 }

The first part creates a new mail contact using the mappings in the script.  So, the Name field in the Exchange contact uses the ContactFullName field in the CSV, the ExternalEmailAddress in the Exchange contact uses the ContactEmail field in the CSV, etc.

The second part sets other attributes on the contact, in this example the work and cell phone numbers of each contact by using the -Identity parameter mapped to the same ContactFullName field in the CSV used first in the script.

Step 3:  Do Something Really Dumb and Make Life Difficult For Yourself

So let’s just imagine for a minute that you are cleaning up your CSV file and notice some of your phone numbers have periods in them, and that because you are who you are, that bothers you, so you do a simple find and replace and problem solved!  You import your contacts and everything is perfect and takes about 3 minutes.  Then you notice a problem.  All of your email address look like this:  exchangecontact@exchangecom.  Oh yeah, because you took all the periods out dummy!  So, after I pulled the CSV information out of our SQL database again, I was ready to do another import, but needed to clean up the existing contacts first.  In retrospect, I think I could have just used the set-contact cmdlet to do this an easier way, but I’m new to Powershell and this is the first thing that came to mind.  And what was that?  DELETE ALL OF THE CONTACTS I JUST IMPORTED!

 Import-CSV C:contacts2.csv | ForEach {
 Remove-MailContact -Identity $_.ContactFullName -Confirm:$false
 }

That little script used an identical CSV that I had created to delete all of the contacts by using their ContactFullName as their Exchange identity.  Then just re-run your import script and you are good to go.

I could have used a script like this to just update the existing contacts:

Import-CSV C:contacts3.csv | ForEach {
 Set-Contact -Identity $_.ContactFullName -ExternalEmailAddress $_.ContactEmail
 }

Calendar Permissions Missing After Migration from Exchange 2003 to 2010

Situation:
All employees use Outlook 2007.  I have migrated our Exchange environment from Exchange 2003 to Exchange 2010 probably 3 months ago.

One user’s calendar (we will call him Tom)  was not showing Free/Busy information to any other user who had added Tom’s calendar to their Outlook.  In addition Tom mentioned that when he tried to edit his own calendar permissions it was throwing errors.

Troubleshooting:
I added the user’s calendar to my Outlook (which is version 2010) and nothing showed up.  I then setup an email profile for Tom on my computer and logged in and looked at his calendar permissions.  And, there were none.  Not even the default permissions, which was pretty awesome.  So I added in myself, clicked OK and it came up with the error message saying “Unable to Modify Permissions”.  I logged in as Tom through OWA and tried to modify the permissions and the same error occurred.

At this point I did what any good SysAdmin does and break out my Google Fu to see if it can shed any light on this issue, because I have no idea how to get the default permission to show up short of recreating the mailbox and I don’t quite want to go that route yet.  Sure enough after about 10 minutes of digging I came across this article (SysAdmin fail, I didn’t save the right link.  Crap.) that said one way to recreate the default permission was to add someone as a delegate and then remove.

Solution:
So I added myself as a delegate to Tom’s mailbox, closed out of Outlook, reopened Outlook and removed myself and then verified on Tom’s calendar that the default permission was now present.  I then logged into Outlook as myself and wasn’t able to view his Free/Busy information yet, but I was through OWA.  A few hours later Tom’s Free/Busy calendar information was showing in my Outlook and was for other users as well.