Wednesday, 5 August 2020

Avoiding Connection Issues with Skype for Business Online PowerShell

I’ve been doing a deep dive recently on Skype for Business Online PowerShell and the Move-CsUser command for a customer that has a highly secured Skype for Business deployment.  The details about how these commands actually work in practice are not described in much detail in the Microsoft documentation. They give few examples about what the practical requirements are for making these commands work in more complex scenarios. I personally think that this information is critical when you’re trying to transition smoothly to the cloud and can end up being a painful trial-and-error situation without good documentation. As a result, I decided to write up my understanding of the requirements and limitations of getting these modules and commands to work in different circumstances. I'm not going to be documenting how to set up Hybrid as this is pretty well documented. Instead I'll be focused more on the various authentication approaches of the PowerShell module and Move-CsUser command. Here are the areas we’ll cover in this post:

·       Connecting using Skype for Business Online PowerShell (version
·       Connecting using the Move-CsUser command.

Skype for Business Online PowerShell

The Skype for Business Online PowerShell module as of has two methods of authenticating with Office 365 (as opposed to the module which only supported legacy auth). There was also 2 versions of the Online Module that shows as being, so it's worth checking that you have the latest version from the download site. The first and original method of connection uses Legacy Auth or Live ID based authentication. The second method of connecting uses a Modern Authentication method using OAuth. The Modern Authentication method supports authenticating with full Multi-Factor Authentication support. The legacy authentication method is not aware of MFA and will fail if you try and connect using an MFA enabled account.

The Anatomy of the Skype for Business Online PowerShell Module Connection

There are several steps that the Skype for Business Online module does in order to set up the connection. Each one of these steps could be the cause of connection failures, so it’s useful to understand what the steps actually are and what can go wrong with them. A good way to understand what phase the connection fails at is to run the New-CsOnlineSession command with the -Verbose flag. When you do that you will see the following steps in a successful connection:

Determining domain to admin
In this step the PowerShell module tries to determine what the domain is for the admin account being used. There are two ways for this to happen: either it will parse the admin account URI and select the domain after the @ symbol, or you have included the OverrideAdminDomain flag in the New-CsOnlineSession command.
AdminDomain = ''
This step describes the admin account domain that it will use to discover the URI endpoint (e.g. the part after the @ symbol in the admin account name or the OverrideAdminDomain flag value).
Discovering PowerShell endpoint URI
The PowerShell module connects to a URI that is specific to the location where the tenant is deployed. In order to find this out the module queries the Lyncdiscover URL based on the specified admin domain:
Note: If the domain is still pointing to an on-prem/Hybrid Skype for Business deployment this step (in my experience) will fail unless you have specified an online only domain using the OverrideAdminDomain flag (e.g.
TargetUri = ''
The module will then parse the response of the LyncDiscover call to find out what the tenant's PowerShell connection URI is, which it refers to as the TargetUri. In this case it's

Note: If you already know what this is you can specify it on the New-CsOnlineSession command using the TargetUri flag which will allow the previous steps to be bypassed.
Requesting authentication token
The module will then authenticate and retrieve a token which it will use for the session. To do this (when using the OAuth method) it will sent a HTTP POST to to retrieve a token. If this step fails, a good way to test it is to open up Internet Explorer and try to log into and see if you can get through the login steps from the browser on the machine you’re connecting from.
Initializing remote session
After authenticating and retrieving a token it will try to setup the PowerShell connection.
At this point I have seen issues with Proxies. All the previous connections seem to automatically use the Proxy settings that are set in the Control Panel > Internet Options > Connection (Tab) > Lan Settings (commonly referred to as the Internet Explorer proxy settings). However, at this point when the PowerShell module is attempting to connect it does not use the Proxy settings by default. If you see the connection fail here and you know that there is a Proxy being used you need to ensure that you include SessionOption flag on the New-CsOnlineSession command which is described in greater depth below.

Below is an example of these step shown in a working connection (using Legacy Auth) when the Verbose flag is being used:

PS > Import-Module SkypeOnlineConnector
PS > $cred = Get-Credential

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
PS > $session = New-CsOnlineSession -Credential $cred -Verbose
VERBOSE: Determining domain to admin
VERBOSE: AdminDomain = ''
VERBOSE: Discovering PowerShell endpoint URI
VERBOSE: TargetUri = ''
VERBOSE: Requesting authentication token
VERBOSE: Success
VERBOSE: Initializing remote session
VERBOSE: Success
PS > Import-PSSession $session -AllowClobber

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0        tmp_1rjupt3z.xju                    {Clear-CsOnlineTelephoneNumberReservation, ConvertTo-JsonF...

The Two Authentication Methods

The two methods for Authentication are shown in their basic form below:

Basic Legacy Auth Method (when using a non-hybrid Skype for Business domain admin account):

This is the basic form of the commands when you are connecting using an admin account (domain name) that has lyncdiscover records that point online (i.e. a non-Hybrid Skype for Business domain).

Import-Module SkypeOnlineConnector
$cred = Get-Credential
$session = New-CsOnlineSession -Credential $cred -Verbose
Import-PSSession $session -AllowClobber

Basic Legacy Auth Method (When using an admin account where the domain portion is a Hybrid Skype for Business domain)

The command below uses the OverrideAdminDomain setting in order to bypass the requirement to use the lyncdiscover query string shown in Step 3 of the connection process. For the OverrideAdminDomain, I suggest you use the onmicrosoft domain for your tenant because this always points online (and will always work):

Import-Module SkypeOnlineConnector
$cred = Get-Credential
$session = New-CsOnlineSession -Credential $cred -OverrideAdminDomain -Verbose
Import-PSSession $session -AllowClobber

Modern Authentication Method

The Modern Authentication method is triggered when you don’t include the -Credential flag in the New-CsOnlineSession command. It’s also recommended to use the OverrideAdminDomain setting here and specify the onmicrosoft domain of your online tenant. The Modern Auth method supports MFA and federation based authentication so you can use it with basically any type of admin account (on prem, online, with or without MFA).

Import-Module SkypeOnlineConnector
$session = New-CsOnlineSession -Verbose -OverrideAdminDomain
Import-PSSession $session –AllowClobber

After running the Modern Authentication New-CsOnlineSession command you will see a Modern Authentication window that you will use to enter your credentials:

Dealing with Web Proxies

If the machine that you’re on requires web proxy settings in Internet Options (e.g. the Internet Explorer proxy settings) in order to access the internet, then you will need to add some extra Session Options to the connection commands. The SessionOptions flag in combination with the ProxyAccessType of IEConfig will allow the Remote PowerShell session to use the IE Proxy settings when connecting. Keep this in mind when you’re dealing with servers behind proxies.

Import-Module SkypeOnlineConnector
$proxySettings = New-PSSessionOption -ProxyAccessType IEConfig
$session = New-CsOnlineSession -Verbose -SessionOption $proxySettings -OverrideAdminDomain
Import-PSSession $session –AllowClobber

Note: If your proxy has any kind of interactive authentication process for connecting through it (for example Basic Auth challenge) then the connection will likely fail. If this is the case you need to set up a whitelist in the proxy for the server to get through without being asked to authenticate.

Online Module Disconnection Issues

The Online Module only remains connected for 60 minutes by default, however, If you plan on being connected for longer than this then you will want to use a new command in conjunction with the connection commands documented above. The command is Enable-CsOnlineSessionForReconnection and Randy Chapman has a good write up about it over at his blog here:

My Rules for using the Skype for Business Online PowerShell Module (

·       If the authenticating admin account has a domain (e.g. admin@<>) with lyncdiscover DNS records that point to an on-prem Skype for Business deployment (e.g. Hybrid Skype for Business) then you need to use the OverrideAdminDomain flag with an online only domain name (i.e. the onmicrosoft domain e.g.
·       The Legacy Authentication method (with Credential flag) will not work for MFA accounts with the Skype for Business Online PowerShell module. (Note: This is not the case with the Move-CsUser command which bypasses MFA when using Legacy Auth mode)
·        If you have proxy settings specified in your Control Panel > Internet Options (i.e. the old Internet Explorer Proxy settings) then you need to use the “New-PSSessionOption -ProxyAccessType IEConfig” setting to force the Remote PowerShell session to use the proxy.

Move-CsUser Command

The command used to move users from on premises Skype for Business server to the cloud is not part of the Skype for Business Online PowerShell Connector module. It’s actually part of the on-premises SkypeForBusiness PowerShell module and behaves a bit differently than the Online PowerShell module. To use this command you need both on premises credentials and Online credentials.

The On-prem credentials requires the following Skype for Business RBAC role:

·       CsAdministrator

The specific online permissions that you need the following credentials:

·       Skype for Business Online Administrator
·       User Administrator – Note: This is required because the command needs permissions to query the user’s current licences to see if it has the correct licences to function correctly when moved to online. If this check fails then the whole command will fail to run.
·       OR Global Administrator

When the move command runs, it checks that the user being moved online has been given appropriate licensing so that when they move online they have the matching level of functionality that they had on premises. There are a couple of different licences that it checks when doing this:

·       If you’re moving the user to Skype for Business (i.e you have not specified the MoveToTeams flag in the Move command) then it will check if the user has a licence with Skype for Business (Plan 2) enabled. If not it will give an error.
·       If you’re using the MoveToTeams flag then the user requires a Teams licence in Office 365 or the Move command will give an error.
·       If the user is determined to be using On Premises Dial-In conferencing then the Move command will look for an Audio Conferencing licence to be assigned to the user. If you want to bypass this check you can use the BypassAudioConferencingCheck flag.
·       If the user is enabled for Enterprise Voice on premises then it will check if they have a Phone System licence assigned in the cloud. You can also bypass this check by using the BypassEnterpriseVoiceCheck flag on the Move command.

You’ll note there isn’t a bypass flag for having a Skype for Business or Teams licence. You need to ensure that you’ve assigned your licences prior to moving users. Also keep in mind that just because someone has an E5 licence doesn’t mean that these sub-licences are enabled on the account.

Before running this command you need to determine what the hosted migration service URL will be for your tenant (this bypasses the auto-discovery process for domains currently in Skype for Business Hybrid mode that have Autodiscover records that point on-prem). This has the same starting component to the URL that the Online module uses for the TargetUri. You can discover this using the following command from the Skype for Business Server PowerShell module:

PS > Get-CsOnlinePowerShellEndpoint -TargetDomain | select-object Host


The command above will run the lyncdiscover process to find the host portion of the hosted migration URL.
or alternatively, another method is to use the following procedure:

The value of the hosted migration override URL is a variant of the following URL:
In the above URL, replace the XX with either two or three characters, determined as follows:

·        In a Skype for Business Online PowerShell session, run the following cmdlet:
Get-CsTenant|ft identity
·        The resulting value will be in the following format:
OU=<guid>,OU=OCS Tenants,DC=lyncXX001,DC=local
·        The two- or three-digit code is the XX contained in the section DC=lyncXX001. If it’s a two-character code, it will be a digit followed by a number (such as 0a). If it’s a three-character code, it will be two letters followed by a digit (such as jp1). In all cases, you’ll see 001 immediately after the XX code.

The Move-CsUser command, as of Skype for Business 2015 CU8 and all versions of Skype for Business 2019, now supports both Legacy Authentication as well as Modern Authentication based OAuth authentication methods. The Modern Authentication method requires that you include the -useOAuth flag when running the command and will allow you to do full MFA based authentication when connecting to Office 365. This is the recommended version to use moving forward because the Legacy method is likely to get deprecated at some stage in the future.

Basic Legacy Authentication Method

The legacy authentication method is supported by all version of Lync 2013 and Skype for Business that supported Hybrid connectivity. I recommend that you specify the HostedMigrationOverrideUrl or otherwise the command will do the lyncdiscover steps for every user being moved, which is just going to make the moving of users take longer and potentially have more steps that could fail.

Move-CsUser -Identity -Target -MoveToTeams -Credential $cred -HostedMigrationOverrideUrl $url –Verbose

Modern Authentication Method (OAuth)

The OAuth method is supported from version Skype for Business 2015 CU8 onwards and all versions of Skype for Business 2019. This is the recommended way to authenticate when you’re using versions that support it. Note the use of the UseOAuth flag to make this work. I recommend that you specify the HostedMigrationOverrideUrl or otherwise the command will do the lyncdiscover steps for every user being moved, which is just going to make the moving of users take longer and potentially have more steps that could fail.

Move-CsUser -Identity -Target -MoveToTeams -HostedMigrationOverrideUrl $url -UseOAuth –Verbose

After running the OAuth method you will see a Modern Authentication window that you will use to enter your credentials:

TIP: Don’t Try and Run the OAuth method command via Remote PowerShell

You need to run this command directly on a server with the Skype for Business On-prem PowerShell Module installed. You cannot run the modern authentication method via a Remote PowerShell connection (which will be used for sites that are properly taking advantage of on-prem RBAC levels). If you try and run the Move command using the OAuth method you will get an error because the command will try and open the Modern Auth window on the server that you are remotely connected to and that will fail.

In addition to this, when you’re using Remote PowerShell the server Proxy settings do not seem to get used when you’re connecting. Be aware that this is another failure mode for this type of connection.

My Rules for using the Move-CsUser command to move users online:

·       If the account you’re authenticating with is not an onmicrosoft domain, then you need to use the HostedMigrationOverrideUrl flag.
·       Don’t specify the Credential flag and user the UseOAuth flag to use Modern Authentication to connect. This will support MFA and federation authentication methods. 
·       The Legacy Authentication method (with Credential flag) can actually be used for accounts with MFA assigned to them. The connection endpoint in O365 seems to currently bypass any MFA authentication. However, this may get deprecated at some point in the future, so don’t bank on it to be around forever.
·       Make sure when using OAuth that the IE security settings are not stopping the authentication window from rendering or working correctly.

Be careful of the Internet Explorer Security settings

Note: This applies for both the Online PowerShell module connection and the Move User command.

In many cases, servers being used to run these commands will be heavily secured and have a lot of Group Policies locking them down. One of the issues here is that if Internet Settings have been locked down too much then the webview that’s used to display the authentication screen may not render. When this happens you end up with a white window like this:

Depending on how locked down the server is, you may or may not be able to see the Internet Settings Security Tab. In the case of this kind of issue, the settings are likely locked down to the “High” level for the Internet Zone - like this:

If you are able to switch these settings back to the Medium-High setting then the Authentication window should start working again:

Cookies settings can also be an issue. Check that you have cookies allowed:

The Wrap Up

I hope this guide provides you with some more information about the details of using the Skype for Business these PowerShell commands. If you have any feedback, feel free to post below. Enjoy!

Read more →

Sunday, 10 May 2020

TechNet Gallery to GitHub Migration Tool

As you may or may not be aware Microsoft are making a move to close down the TechNet Gallery web site. This website is the location where I had previously posted all of my tools over the past few years and is also jam packed full of other great community tools as well. In the first stage of the shutdown, Microsoft has put the TechNet Gallery pages into a Read-Only mode where you can still edit existing posts but cannot create new posts. This first step is to give people time to download their posts and move them to another location before the final shutdown of the site.

I find this news to be quite concerning because I know that I still find useful resources on TechNet Gallery all the time. So I've decided to try and do something to help people move their content off TechNet gallery to a safe harbor before it's too late. To do this, I decided to put together a PowerShell tool that will both download content from TechNet Gallery and prepare it for upload directly onto GitHub. This post also describes the steps to uploading the files onto GitHub to make the process as easy as possible.

How does the tool work? Well, you feed it one or many TechNet Gallery URL(s) and it will download the posted file and all the text and images from the site into a folder for you. In addition to this, it will convert all of the text into a Markdown based README.MD file (and refactoring image URLs to move to GitHub) so it can be directly uploaded to GitHub to display the exact text that you had on your TechNet Gallery post (minus any code snippets). All you need to do after this is follow a simple process of creating a new GitHub repository and upload these files to it. You will then end up with your TechNet Gallery content re-hosted in a very similar format on GitHub.

The Differences Between TechNet Gallery and GitHub

TechNet Gallery was designed to be a relatively simple CMS style system that allowed you to upload a file (of any type) and put some blog post style text and images with the file to explain whatever you wanted about the file. This concept is fairly easy to understand and didn’t offer too many bells and whistles. GitHub on the other hand was designed to be a source code repository with versioning features and functionality built in. As a result, GitHub has a much bigger capability set and complexity level than TechNet Gallery.

What does that mean when moving files and content over from TechNet Gallery to GitHub? It means that you have more options for how you can post and manage your files. For example, you could simply use it as a location to put your files or you could potentially start using the Git application workflow to manage the versioning of your files. Using these more complex components of GitHub is out of scope for this blog post. You could quite easily “git init” the folder that the tool creates and then link this up to a remote GitHub repository as a way to upload the content. I will assume if you know how to use Git then you’ll be more than capable of doing this yourself, and if not, then you don't have to use these features or you can read up on them as you see fit.

Backup / Migration Procedure

For the purposes of this blog post I am going to make this the simplest procedure possible which does not require that you install and use Git. Instead the process will use the GitHub web interface to upload your files for storage on GitHub in a similar way to how you would have used TechNet Gallery.

Firstly you need to go and get the URL of your TechNet post. This will look something like this one for one of my posts:

Once you have this you will need to sign up for a GitHub account. This is free and offers you a heap of functionality without asking you any of your hard earned dollars (thank you Microsoft!). I’m not going to show you how you do this because it’s pretty straight forward. When you sign up you will be asked to create a GitHub account name. You will require this account name if you are migrating your images over to GitHub using the tool.

Head over to my GitHub repository and grab of a copy of the script I wrote for downloading the files and generating a file for use on GitHub. Click the link below to go to the repository:


When you run the tool you can either use PowerShell flags to input your information into the tool or not use any flags and the script will ask you to input the information that's required. The flags that the tool uses are as follows:

-MoveImagesToGitHub (Default TRUE) - When set to $false you can retain the original location of the images from the TechNet post in the GitHub file. If these originally pointed to an external location then you can keep them there but if you uploaded them to TechNet Gallery you will want to move them as they will disappear when the site is taken down.

-TechNetURLs - This flag is where you can input a comma separated list of all the TechNet URLs that you want to download. If you don't use this flag the tool will ask you for a URL when it runs.

-GitHubAccount -  This flag is used for updating image URLs with the GitHub account location where it's going to be stored. This will be the account name that you sign into GitHub with. If you don't use this flag and the script determines that it's required it will ask you for it.

-GitHubRepo (Default TechNet Post Title) - This is the Repo name that the files will be uploaded to. If you don't enter this then the TechNet title will be used. If you have a specific name you want to use then use this flag to set it.

To run the script with flags you will use the following format:
.\TechNet-Gallery-to-GitHub-Migrator.ps1 -TechNetURLs "", "" -GitHubAccount "<your account name>"

After you have run the script it will generate a new folder for each TechNet Gallery post in the root folder that you ran the script from. These folders will be named using the title of your TechNet post with dashes replacing spaces. This is a common naming convention for GitHub repositories (not the only way, but a common one). The script is designed based on the assumption that the repository that you create in GitHub will have this same name (and same format).

Sign into GitHub with your account. Within GitHub go to your Repositories page. In here you will see a green button marked “New”. Click this button to create a new repository:

To name the repository, copy and paste the name of the folder that the tool created (this is the same as the TechNet Gallery post title). I recommend you use this same name for your GitHub repository when you create it (unless of course you wrote weird or super verbose things in your title to try and up your SEO). Below I have copied the name of the folder:

The New Repository page on GitHub asks for the following information:

Fill in the repository name and description with the folder name that the tool created. Select “Public” repository type if you want others to be able to see it on the Internet. Once you have done this click the “Create repository” button.

You will now be taken to a page that tells you how you can connect to this repository using Git methods. However, we are just going to use an entirely web based creation process for simplicity. Click the “Uploading an existing file” link as highlighted below:

You will now be taken to a page for uploading your files. Drag and drop all the files from the folder (the script created) on the web browser window in the location shown below:

You should now see a list of your files in the page as seen below. Click the “Commit changes” button to upload the files:

You will see your newly created repository with all your files in it. The contents of the file will be displayed in all its glory below this as GitHub uses this as your repository’s information text by default. It should also render all the Markdown in the file nicely with headings, bolding, dot point and images being displayed. This should make the page look similar to what you would have seen on the TechNet Gallery page for your content!

 Tweaking or Changing the Text

Minor tweaking may be required on the document to perfect the layout. The good news is you can do any corrections you need to do in the GitHub web editor. Simply click on the file and then click the Edit button. This will take you to a text based editor in the web page where you can make your changes. In this example the Protocol Documentation heading is not quite rendering properly as being bold because there is a return carriage between the second set of asterisks. So I just need to simply move them up to the line that they heading is on and click the Commit Changes button at the bottom of the page.

Note: Code snippets in the TechNet Gallery text will not be carried over to the file (lots of people include their entire scripts in the body text which doesn't translate well to markdown). If you have put smaller lines of code examples in your text you will have to add them manually to the file.

And you’re done!

What Next?

The good news is that you have a publicly available backup of your TechNet Gallery content. It's up to you on how you would like to administer this moving forward on GitHub. As I mentioned earlier, you may choose to start using the Git workflow and downloading and managing your repo(s) with Git commands (commit, push, etc). You may also choose to use the Releases page in your repo to generate tagged and versioned releases. It will depend on the type of project that you are migrating as to how you may choose to do this. For a project that is not getting changed much you may just choose to put up and leave it. However, for a project that you are actively doing a lot of updates on you may choose to start using Git. There are many resources on the web that will explain Git and how it works. Git will be a lot to digest when you first start using it and it's something that you really need to start using in practice to get your head around. As they say; there's no better time to start something than right now, so hop to it!

The Wrap Up

I have migrated 14 of my tools that were up on TechNet Gallery using this process so the process has been trialed and worked successfully for me. As I mentioned earlier in the post; TechNet Gallery has loads of great content on it which I really hope does not disappear into the abyss when the site is closed down because people put the migration in the too hard basket. I really hope that this tool and blog post do something to make the process a bit simpler and give you a framework by which to migrate your tools as well. If you have any issues with the script, let me know.

Read more →

Popular Posts