Avoiding a Microsoft Teams Nightmare

Have you ever had the experience of providing users a document management system or Sharepoint site only to find that everyone uses it differently, creates folders all over the place in different ways, stores documents differently and after six months time it’s so hard to find anything that it defeats the purpose for which it was implemented in the first place? What a nightmare! You’re not alone.

With Microsoft Teams quickly becoming a preferred collaboration tool, you’d be forgiven for having fears of this nightmare becoming a reality all over again. The primary reason for that is there’s no technical ‘silver-bullet’ to prevent this from happening, it’s more of a governance discussion. Notwithstanding, there are some things you can do on a technical level that can help.

There are basically four levels of administration to be considered:

  • Global Settings – There are a number of features and functionality for Teams that can be turned on or off at a global level and these should be risk assessed for each environment. Ideally this should be done before the first Team site is even created.
  • Team creation – Microsoft Teams, while based off Office 365 Groups, will also provision a Sharepoint site for each Team. Therefore the decision as to who should be creating Teams is the same as for who should be creating Groups and Sites. One approach that we’ve found works well is to have these functions centrally managed with Teams created on request. There is of course an admin overhead to be considered however. See below;
  • Team Owners – These are the users that really run the individual Teams and will have the best insight as to the value of the Team and how it should be used. Trying to run this centrally is likely to lead to frustration all round so once created, administration should really be handed over to the Team owners. They can then add Team members, assign roles, create Channels and enable Apps etc as they see fit.
  • Team Users – Obvious statement but these are the ones who should be seeing value in Teams collaboration. Paradoxically one way to dilute that is by being in too many Teams. Users shouldn’t be confused about what spaces they should be collaborating in or where to store documents etc. To prevent this, ideally Teams should have clearly defined functions, whether that be organisational, operational or project based collaboration. Confusion arises where these functions overlap between Teams so clear delineation is important. This is another reason centrally managing Team creation can work well. In larger environments implementing practices like naming standards for Teams will also be of value.

Some of the central administration technical considerations are outlined here: https://docs.microsoft.com/en-us/microsoftteams/enable-features-office-365

Melissa Hubbard also provides some useful considerations in her blog post on the topic and while it’s a little while ago now, it’s still a great starter for some of the governance considerations:  https://melihubb.com/2017/07/25/microsoft-teams-governance-planning-guide

If Microsoft Teams is on your agenda for implementation, be sure to reach out to the Adexis team who can assist with design and implementation and help you to provide this wonderful platform to your users to enable communication and efficient collaboration, without the admin headaches.

Exchange hybrid – mailboxes missing on-premise

While hybrid exchange environments are awesome for stretching your on premise exchange topology to Office 365, they do introduce a bunch of complexity – primarily around user creation, licensing, and mail flow.

I recently had an issue at a client where they had email bounce-backs from an on premise service destined for a few Exchange Online mailboxes. For some reason, these few mailboxes didn’t appear in the on-premise exchange environment (as remote Office 365 mailboxes), so exchange was unable to route the emails destined for those particular mailboxes.

In general, you should be creating your mailboxes on premise (Enable-RemoteMailbox), then synchronising via AADConnect – that way the on premise environment knows about the mailbox and it can be managed properly. This client was actually doing this, but obviously the process broke somewhere along the way for a few mailboxes.

There’s a bunch of different options on Google about how to get the mailbox to show up on premise – with a lot of them recommending to remove the mailbox and start again (er… how about no!).

I came across this Microsoft article on a very similar issue, but for Shared Mailboxes created purely in Exchange Online. Looking at the process, it looked like a modified version may work for user mailboxes – and it does. Below is a quick and dirty powershell script that can be used to fix a single mailbox:

 

Azure AD Connect – Permissions Issues

I’ve had various versions of AD Sync/Azure AD Connect running in my development environment over the years, and have used a number of different service accounts when testing out different configurations or new features. Needless to say, the permissions for my Sync account were probably a bit of a mess.

Recently, I wanted to try out group writeback. It’s been a preview feature of Azure AD Connect for quite a while now – it allows you to synchronise Exchange Online groups back to your AD environment so that on premise users can send and receive emails from these groups.

Launched the AADConnect configuration, enabled Group Writeback, then kicked off a sync. Of course, I start getting ‘Access Denied’ errors for each of the Exchange Online groups – couldn’t be that easy!

Generally speaking, you need to also run one of the “Initialize-<something>Writeback” commands. When I went looking for the appropriate commands (as I don’t remember these things off the top of my head!), I came across an interesting TechNet Blog article: Advanced AAD Connect Permissions Configuration – it’s pretty much a comprehensive script that handles all the relevant permissions (including locating the configured sync account and sync OUs).

Gave it a whirl, entered credentials as required, and what do you know – permissions all now good!

Microsoft Exchange Federation Certificates – Keep an eye on the expiry!

I recently had a client experience an issue with their hybrid exchange setup (365/On Premise) – users were suddenly unable to retrieve free/busy and calendar information between the two environments. As it turns out, the certificate used to secure communications to the Microsoft Federation Gateway (MFG) had expired.

Federation certificates within exchange are generally created as part of the federation creation wizard (or the 365 Hybrid Configuration Wizard) – so in most cases, people don’t realise they’ve been created. If you’re not actively monitoring certificate expiry dates on your servers (which you should be!), you may get into the situation where this certificate expires – which results in the federation no longer working.

Why is it important to renew it before it expires? Because if you don’t, you need to remove and re-create the federation – a significantly larger task than the federation certificate renewal process. The reason for needing to re-create the trust is due to the fact that the federation certificate is used to authenticate any changes to the federation – so once it expires you can’t make any changes and have to start from scratch. Lets take a look at the steps involved in both:

Renewing before expiry:

  1. Create a new self-signed federation certificate
  2. Set the new certificate as the ‘Next’ certificate in the federation trust
  3. Wait for AD replication
  4. Test the certificate and trust (Test-FederationTrustCertificate, Test-FederationTrust)
  5. Roll-over the ‘Current’ certificate to the ‘Next’ certificate
  6. Refresh the federation metadata

Renewing after expiry:

  1. Document the existing trust settings (federated domains, federation settings)
  2. Force remove each federated domain from the federation
  3. Remove the federation trust
  4. Wait for AD replication
  5. Create a new self-signed federation certificate
  6. Create a new federation trust
  7. Update the trust organisation information
  8. Configure the required settings in the trust (as per the documentation you created in step 1)
  9. Wait for AD replication
  10. Test the certificate and trust (Test-FederationTrustCertificate, Test-FederationTrust) – it can take 12-48 hours before the trust reports as being no longer expired!
  11. Add each of the federated domains back into the trust (this will involve generating domain ‘Proof’ entries and adding them to your external DNS, then waiting for DNS propagation)

So in short, don’t let your federation certificates expire!

Decommissioning Skype for Business 2015 on premise after migrating to O365

Depending on how you utilise Skype for Business, you may have no requirement to maintain a hybrid environment once all users are within Skype for Business online.

Documentation around decommissioning the on premise environment was surprisingly sparse.

One of the better documents around web was here – but it still stopped a little short, in my opinion.

So below is my attempt at rounding this process out.

 

All steps below assume you have already migrated all users to Skype for business and that you are aware of the requirements to stay in hybrid depending on your EV setup. If you are unsure, do not start this process.

 

Step 1 – Update DNS entries

This document really nails the DNS changes required, so good work Mark Vale. I am going to paraphrase the article a little, just so it’s all in one place.

Depending on your environment, you have a fair idea of idea of how long you need to wait externally and internally for convergence. This will lead to downtime, so it is wise to perform this outside of business hours.

Its also wise to take a backup of your existing values, just in case.

External DNS changes

ActionDNS Record NameTypeValue
ModifySipCNAMEsipdir.online.lync.com
ModifylyncdiscoverCNAMEwebdir.online.lync.com
Modify_sipfederationtls._tcpSRV0 0 5061 sipfed.online.lync.com
Modify_sip._tlsSRV0 0 443 sipdir.online.lync.com
DeleteDialinA
DeleteMeetA/Cname
DeletelyncwebA/Cname
Delete_xmpp-serverSRV

 

Internal DNS changes

ActionDNS Record NameTypeValue
Add_sipfederationtls._tcpSRV0 0 5061 sipfed.online.lync.com
ModifysipCNAMEsipdir.online.lync.com
ModifylyncdiscoverCNAMEwebdir.online.lync.com
DeletelyncdiscoverinternalA
DeletedialinA
DeletemeetA
DeletelyncwebA
Delete_sipinternaltls._tcpSRV

after completing these updated, check via the O365 portal that O365 is reporting the Skype DNS entries as all good. I find this is generally pretty quick, so I assume that the source DNS server is used for DNS record checks and it doesn’t have to wait for convergence.

 

Step 2 – Check functionality

After an appropriate convergence time, check that all functionality is working before moving on to further steps.

Again, this depends on the size of your environment and your internal and external DNS configuration.

Marks post has a couple of scripts you can run if you wish to speed up the process internally.

 

Step 3 – Disable Shared SIP Address Space

Ensure you have the Skype for business powershell module

  • Import-Module LyncOnlineConnector
  • $credential = Get-Credential “<yourSkypeForBusinessAdminAccount”
  • $session = New-CsOnlineSession -Credential $credential
  • Import-PSSession $session
  • Set-CsTenantFederationConfiguration –SharedSipAddressSpace $false

 

Step 4 – Uninstall on premise components

On one of your home servers

  • Open the Skype for Business server control panel or PowerShell (whichever way you prefer)
    • Remove all objects possible (see Phase 3 of this document). These will vary greatly, so I have not listed all of the things to remove, but let me know if you are having trouble with one.
  • Open the Skype of Business topology manager
    • Download your existing topology
    • Remove configuration and components to allow you to strip the environment bare
      • Remove global routes to your edge servers, which will allow the edge servers to be removed
      • Remove application servers
      • Remove any configuration pointing to your mediation servers, then remove them
      • Remove persistent chant pools
      • Remove everything you can, which will be everything except the last server where your CSS is stored (if running standard)
    • Publish the topology
      • Run Skype for Business Server Deployment wizard on the edge and mediation (if this is co-located, there will not be additional mediation servers) servers, and allow it to remove all roles
      • These servers can now be switched off
  • Open the Skype of Business topology manager
    • Download your existing topology
    • Now when right clicking on your final server, if you to “topology” you will have an option of “Remove Deployment”
    • Select this and publish your topology again
  • Open Skype for business management shell
    • Get-CsConferenceDirectory | Remove-CsConferenceDirectory -Force
    • Publish-CsTopology -FinalizeUninstall
    • Run C:\Program Files\Skype for Business Server 2015\Deployment\bootstrapper.exe /scorch
    • Remove-CsConfigurationStoreLocation
    • Disable-CsAdDomain (This will remove the RTC groups from your AD permissions structure)
    • Disable-CsAdForest ((This will remove the CS* groups from your AD)
    • I found once this had completed, a couple of RTC groups still existed under the “users” container. This is likely due to the fact that the domain has hosted versions of Lync/OCS etc. sync LCS 2005. I deleted these manually.
  • Once this was completed, shut down your last Skype for business server on premise.

 

 

References

Mark Vale, August 17 2015, Decommissioning Skype for Business Hybrid and Going Cloud Only

Microsoft,  September 11 2013, Decommissioning a Deployment

Microsoft, March 26 2012, Remove-CsConfigurationStoreLocation

Microsoft, April 12 2011, Publish Final Topology and Remove Last Front End

Scripting Office 365 licensing with disabled services

In the past I’ve had a few clients request scripts to automatically set/assign licenses to users in Office 365 – Generally pretty simple stuff. Recently I had a client ask to disable a particular service within a license – again, not all that difficult – unless you want to actually check if a license/service is already configured correctly (and not make any changes if it is). Took a little while to work out, so figured I’d share the love!

Just to set a license for a user is a pretty simple process – all you need is the license ‘SkuId’ value of the relevant license. To get a list of the ones available in your tenant, run: Get-MsolAccountSku You’ll get a list of the available license SkuId’s and how many are active/consumed. In this article we’ll use an example SkuId of Contoso:STANDARDWOFFPACK_IW_STUDENT. Once you have the SkuId, all you need to run to assign the license is:

You’ll notice that the code above sets the location first – this is required, as you can’t apply a license without a location being set! What if you didn’t want to have all the applications available for the user? For example, the above license includes Yammer Education. In this case, we need to create a ‘License Options’ object first.

 So where did we get the “YAMMER_EDU” from? You can list the available services for a license by running:

What if we wanted to disable multiple services in the License Option? The “-DisabledPlans” option accepts a comma-separated list. For example:

Ok, so now we know how to get the available licenses and related services – as well as how to assign the license to the user. What if we wanted to check if a license is assigned to a user first? Personally, I’m not a huge fan of just re-stamping settings each time you run a script – so I thought I’d look into it. The easiest method I’ve found is to try bind to the license, then check if it’s $null or not:

From there we can do whatever we want – if the license is found and that’s all you care about, you can skip – otherwise you can use the other commands to set the license.
So what if we also want to make sure YAMMER_EDU is disabled as well? That’s a little trickier. First we need to bind to the license like we did above, then we need to check the status of the relevant ‘ServicePlan’.

At this point it’s probably a good idea to talk about the structure of these objects – you may not need to know it, but for anyone trying to modify these commands it might be helpful:

  • A ‘User’ object contains an attribute ‘Licenses’. This attribute is an array – as a user can have multiple licenses assigned.
  • A ‘License’ object contains two attributes relevant to this script; ‘AccountSkuID’ and ‘ServiceStatus’
    • AccountSkuId is the attribute that matches up with the AccountSkuId we’re using above
    • ServiceStatus is another array – it contains an array of objects representing the individual services available in that license – and their status.

The two attributes attached to a ‘ServiceStatus’ object that we care about are:

  • ServicePlan.ServiceName – this is the name to match the service above (eg: YAMMER_EDU)
  • ProvisioningStatus – this can be a bunch of values, but mostly ‘Success’, ‘Disabled’ or ‘PendingInput’. I’d assume there’s also ‘Provisioning’, but I’ve never seen it.

With this in mind, we can put together a script like the following – it reads the UPN and AccountSkuID from a CSV file, though you could use whatever source you like and update the script accordingly.

Note: In order to run this script, you’ll need:

 

Automating Mailbox Regional Settings in Exchange Online

When you migrate (or create) a mailbox in Exchange Online, the first time a user goes to open their mailbox they are prompted to select their Timezone and Language. I recently had a client ask for a more automated method of pre-populating these values, so thought I’d have a look into it.

Of course, there’s no global way to define these settings for users before they get a mailbox, so the settings have to be set once the mailbox has been migrated – this really only leaves the option of a custom powershell script – either something you run after each migration (or creation), or on a periodic schedule.

First, to the settings themselves. As it turns out, you can use the same commands that you’d use in on premise Exchange: Get-MailboxRegionalConfiguration and Set-MailboxRegionalConfiguration – which also means this script could be adapted to be used on premise as well. The two settings we’re concerned with here are “Language” and “TimeZone”. Since the client we’re dealing with here is solely based in Australia, we’re going to be setting all users to a language of “en-AU”. For the TimeZone, Microsoft provide a list of valid values here: https://support.microsoft.com/en-us/kb/2779520

Except that they’re missing two Australian time zones. The actual valid values for Australia are:

  • AUS Central Standard Time – Darwin
  • Cen. Australia Standard Time – Adelaide
  • AUS Eastern Standard Time – Canberra, Melbourne, Sydney
  • E. Australia Standard Time – Brisbane
  • Tasmania Standard Time – Hobart

So with that in mind, we can use the following commands:

Since we’re talking about a national business with users in different time zones, the time zone value is going to need to change for each user. In order to automate this, we’ll need some source information available that indicates in which state the user is located – ideally, you’re going to be using the ‘Office’ field in the user’s AD account – though obviously you could use any available attribute. The reason I recommend ‘Office’ (or ‘physicalDeliveryOfficeName’) is because it’s synchronised to Office 365 with the user account (and becomes ‘Office’).

Note: You don’t actually need the value in Office 365 – if you’re running the script on premise, you can query your AD directly and ignore the attributes in 365. When I wrote the script I opted to solely use data that was in Office 365 – primarily because I was developing the script remotely and didn’t have direct access to their AD – so if you want to use your local AD instead of values in 365, you’ll need to modify the script!

For this client, the ‘Office’ value for each user is prefixed with the state (ie: SA, NSW, QLD, WA) – so it was relatively simple to use a ‘Switch’ function in Powershell (similar to a ‘Case’ statement in vbscript).

In order to use the script, you need the following:

You’ll also need to update the 5 variables at the top of the script (paths, etc), as well as the Time Zones (and criteria) in the Switch statement.