When we enable Teams for Skype for Business Hybrid users the final stage of action is to move the actual on premise Skype for Business Account to Office 365 to make them to Teams only mode. As more organization are adopting the Microsoft Teams in a full fast track approach the last stage of migration is to move all the local accounts to Teams Only Mode.
This script will help in moving the users on batches to Teams Only Mode from an input csv file. It also provides the time taken to complete the batch on screen once the migration is completed.
Example below:

Measure-Command { [CmdletBinding()] param( [string] $UsersList = $(Read-Host -prompt ` “Input the CSV File with Location”)) $Users = Import-Csv $UsersList -Delimiter ";" #To Connect to Teams. Make sure you have the new Teams Module installed. $admin="enteryouradminaccount@domain.com"; $pwd = "enteryourpasswordhere"; $securepwd = ConvertTo-SecureString $pwd -AsPlainText -Force; $cred = New-Object Management.Automation.PSCredential ($admin.Replace('sip:', ''), $securepwd); Import-Module MicrosoftTeams Connect-MicrosoftTeams #Initialize parameters and variables. $sip= $users.SipAddress $count = $users.count write-host "We have found" $count "Users to Migrate" -foregroundcolor Yellow -backgroundcolor Black $pauseSeconds = 10 $Sleep = 20 Write-Host "Pausing for " $pauseSeconds " seconds to verify your count..." -ForegroundColor Yellow Start-Sleep -s $pauseSeconds #To Enable Logging and store them for failed migration and any errors. $transcriptname = “MoveCSUserStatus” + ` (Get-Date -format s).Replace(“:”,”-“) +”.txt” Start-Transcript $transcriptname #Take export of SFB enabled users before move. $Users | % {get-csuser -Identity $_.SipAddress} | Where-object {$_.Enabled -eq $True} | Select-object SamAccountName,sipaddress,Enabled,EnterpriseVoiceEnabled | Out-File SFBUsersBeforeMove.csv -append #Hosted Migration Override URL - Use the correct URL based on your tenant $URL= "https://adminof.online.lync.com/HostedMigration/hostedmigrationService.svc" #Initiate Move-CsUser Operation. foreach ($user in $users) { Move-CsUser -Identity $user.SipAddress -Target sipfed.online.lync.com -HostedMigrationOverrideUrl $URL -MoveToTeams -BypassAudioConferencingCheck -BypassEnterpriseVoiceCheck -Confirm:$False -credential $cred } #Pause for 20 seconds Start-Sleep -s $sleep #Validate the Move and complete Successfully Moved and Failed Users. $loop = foreach ($user in $users) { Get-CsOnlineUser -Identity $user.sipaddress | Select-object sipaddress,hostingprovider,TeamsUpgradeEffectiveMode,RegistrarPool} $loop| Out-File TeamsOnlyMigrationStatus.csv -append #Validate the meeting Migration status $loop = foreach ($user in $users) { Get-CsMeetingMigrationStatus -Identity $user.sipaddress | Select-Object UserPrincipalName,State,MigrationType,LastMessage,FailedMeetings} $loop| Out-File MeetingMigrationStatus.csv -append Stop-Transcript Write-Host "Migration Script Completed Please Refer Transcript File for any Errors" -ForegroundColor Green #Close the sessions. get-pssession | remove-pssession #Send Email report to Notify the Migration have completed - Mention your SMTP server #Send-MailMessage -from "username@domain.com" -to "admin@domain.com"-subject "TeamsOnlyMigrationTaskCompleted: No File" -body "Teams Only Migration Batch have been completed.Please refer log file Location for further information" -SmtpServer "Mention your SMTP Server" }
Notes:
- Make sure that you whitelist the traffic to office365 services to establish successful connection to the SFBO session.
- If there are multiple number of users recommended to split up the batches and execute them from 2 servers.
- Ensure the SSL traffic inspection, IP connection limits are excluded from Firewall/Proxy from the network side.
- Moving this from a shared bandwidth might be a bit slower and moving this from a temporary dedicated IP address might provide a better performance.
- This script uses -UseOauth switch. Make sure the Onpremise SFB servers are patched to the required version. Else use the legacy option by removing this switch. Recommended to run this first with few users list verify based on your environment and then later run for bulk users.
Regards
Sathish Veerapandian
Awsome! I am in the process of moving my hybrid SFB on-premises users to teams only mode in parts. In my hybrid environment if I search users in teams I can see all sfb on-premises and online users. Can’t I just change the mode for individual users to teams only instead of running this script? I believe they are homed in on-premises that’s why I must have to move them. Please correct me if I am wrong? Thanks
LikeLike
Hi Ally if you are running hybrid version of SFB and users are not moved SFB Online Unfortunately we cannot move them to Teams Only mode. So the first step is to move them to Online.
LikeLike
Hi Satish, Thanks for the clarification. Do you by any chance know how we move users from SFB on-prem (hybrid) to Teams after July 31, 2021 when SFB and online will be end of life? Has Microsoft defined any process that you are aware of?
Thanks
Ally
LikeLike
Hi Ally you can still move users directly from Skype on prem to Teams only after July 31st. Microsoft has moved all of the backend core components that was present in Skype Online to Teams. https://docs.microsoft.com/en-us/skypeforbusiness/hybrid/move-users-from-on-premises-to-teams
LikeLike
This is just what I am looking for, thanks, how does the CSV need to be formatted?
LikeLike
Hi the CSV needs to have SipAddress Column as well.
LikeLike
Hi Sathish, I guess the scripts are run from skype for business front end. Will this work for migration of thousands users. I use a quite similar script and it times out after 15 users, so I have to close the session and restart a new one.
LikeLike
Hi Daniel this is a known issue recently after upgrading the Teams PowerShell module. The only workaround that you can use is to use the Legacy Authentication parameter trick in the Script. YOu can use the below cmd in your script to use the Legacy Authentication.
Read-Host -Prompt “Enter your tenant password” -AsSecureString | ConvertFrom-SecureString | Out-File “cred.txt”
$User = “Adminaccount@domain.com”
$Pass = Get-Content “cred.txt” | ConvertTo-SecureString
$credential= new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminName, $Pass
LikeLike
Hi Sathish, Thanks for your reply. My account has MFA enforced would -Credentials work ? Have you seen admins with MFA enabled doing batch migrations without any or little intervention? I have been struggling for a solution for months. I opened a case with MS some time ago and they said that they don’t support in house scripts and I don’t see solutions in any article on the web. I came across yours and thought you may have experience or idea to tackle that. I doubt I’m the only one admin with MFA trying to migrate batches of users.
LikeLike
Hi Daniel
Not sure haven’t tried with an MFA enabled account. Are you trying with the newer version of Powershell Module. We had the issue with version 1.1.16 and upgraded to the latest version , post that we are not having any issues. You can try to run fiddler and parallelly run your script and see where and in which URL it gets failed and there could be some URLs getting blocked if you are behind the proxy make sure all the office 365 and IP ranges are whitelisted.
LikeLike
Hi Sathish,
Your script contains
Connect-MicrosoftTeams -Credential $mycred
Import-Module MicrosoftTeams
$sfbsession = New-CsOnlineSession
Import-PSSession $sfbsession
Is that correct/updated?
Should we not import the module, then connect?
On another side, the new teams module doesn’t include New-csonlinesession.
Connect-MicrosoftTeams is required to get the “CS” cmdleds, skype online connector has retired on feb.
Please advise
LikeLike
Hi Jean
yes you are correct when we use the new teams module we can ignore the New-Csonlinesession . I have updated the script now.
LikeLike
Thanks, however I still see references to new-csonlinesssion in the script.
$NewSession=$x/250
if($NewSession -eq 1) {
get-pssession | remove-pssession
Disconnect-MicrosoftTeams
Connect-MicrosoftTeams -Credential $mycred
Import-Module MicrosoftTeams
$sfbsession = New-CsOnlineSession
Import-PSSession $sfbsession
$NewSession=0
$x=0
Write-Host “Refreshing the Skype online Session” -ForegroundColor Green
}
Can you please also explain what $x/250 does?
Thanks
Jean
LikeLike
Hi Jean,
I have updated the script and you can use them now. Earlier i added a loop to refresh the skype online session after every 250 users movement. Now with the new Teams powershell module that is not required. You can use the legacy method and move the users by having the fiddler client open at the same time. That is the work around we have identified.
LikeLike
Thanks for taking the time to reply and modify the scripts.
It’s a very good work and is very much appreciated for sharing that!
Noticed a missing command and typo in a varaiable. If you have the chance to confirm that my finding is correct, that would be great. txs again
Missing “connect-microsofteams” after importing the module.
Variable $cred specified, but $MyCred used in the Move-csuser command.
I guess I won’t be able to use the script using legacy authentication because I’m MFA enabled.
LikeLike
Hey Jean
Thanks for the good catch. Yeah it was a quite busy day and missed to update them between the lines. Have updated the script. Yeah i would recommend to run them from a non-enabled MFA account for the legacy authentication to work. Even exporting the credentials as key file and using them in legacy authentication with an MFA enabled account does not work.
LikeLike
Hi Satish, By any chance do you have any working power shell scripts to get list of say 50 users from a csv file in SFB server. Actually I want to get-CsUser from the list and then in the second script disable-CsUsers some of those users. I found some but they are giving me errors. Appreciate your help.
LikeLike
I don’t think you’ve said exactly how the CSV file needs to be formatted. SipAddress is the only thing you mentioned, but that doesn’t work.
LikeLike
Hi Graham,
It works with the SIP address column only. Since I used this script in year 2020 for migrating more than 15,000 users. Not sure if something has changed with the new modules. Below is the example I took from the lab server.
“SipAddress”
“Ewald.Hollestelle@nl.exchangequery.com”
“Gautham.Antony@nl.exchangequery.com”
“jacob.benny@nl.exchangequery.com”
“Joe.Nash@nl.exchangequery.com”
May be can you share your error message that you are getting we could see what possibly is going wrong in that environment.
LikeLike
I receive the error “Move-CSuser:Management object not found for identity xxx@xxx.xxx“. And the x’s represent the SIP address for the user, which i verified in the on prem SFB console.
LikeLike
Interesting so im sure that there are no extra spaces on the CSV file. May be try the delimiter option in the script. Or it could be an issue that the SFB servers are unable to contact the SFB hybrid. Can you try with the -proxypool switch and make sure from the server where we are running this script has the connectivity to the SFB FE server and that server needs to have connectivity to Office 365 services. I remember one of my customer had this same issue and the solution was the management server from where the script was running did not have connectivity to Office 365 URLs. After correcting that the issue was solved.
LikeLike