I have worked on this for the last year or so, on and off, and wanted to share it with the community. It is written to move users from R2 to Lync. Instructions are simple. It will also handle moving users from Lync 2010 to Lync 2013
or even 2013 to 2013 or 2010 to 2010 if you want. It provides all the functionality I needed to move large batches of users from one version to another while creating seperate text files of successes and failures for each batch. Since MS didn't
release (at least that I could find), a move user script like they did for R2, I created one. I wrote the basis of this a long, long time ago in a server room far, far away.
Quick start:
There is a global variable for a working directory that needs to be set. It is currently set to e:\temp\migration as this is where my batches are located.
User Batch Files: These are text files with a list of users to be migrated. They need to be named in the format batch#.txt where # is a unique number. You can also use letters. So batch 1 will be named batch1.txt. Batch 2a will be
labeled batch2a.txt. The script will ask for the batch number.
The batch files can list users in the format of thier SIP URI with or without the SIP: in front.
The script will look up a list of all Lync pools and SBAs (at least it should) and ask which one you want to migrate the users too. If the list of pools and SBAs is very long, and in some installations it will, I am not sure what the behavior
will be. I will address that as our deployments progress. I guess I can ask if you are migrating to a pool or an SBA to narrow it down.
It will then ask for confirmation of your choices.
Disclaimer: This is provided "as is" and I take no responsability for any damage, etc, etc, etc that this may do. I am sharing this out of the sense of community so don't complain. Feel free to share it as long as you say that
you got it from that ubber cool guy "Mark Poulton." I hacked this together (I am not a programmer) so it probably could be done much much better. However, it works for me. Enjoy my friend.
I may or may not post updated versions as I improve this.
#
# Written by Mark Poulton
#
# The base of this script was taken from here
#
# http://www.itkegger.com/2012/04/03/migrating-users-from-ocs-to-lync-2010-script/
#
# This script will move users listed in a text file to the Lync 2013 Pools
#
# Format of the text file containing users to be moved is: sip:<SIPURI>
# (One user per line. No header)
#
# The list/TXT file should be located in the following directory
# NOTE: THIS IS ADJUSTABLE VIA A GLOBAL VARIABLE
#
# E:\Temp\Migration\Batch#.txt
#
# Migrations are done in batches. Each batch has a number.
# The text file should be in the format of Batch#.txt
# where # represents the batch number.
#
# Example: Batch 3 would be in the format of
# E:\Temp\Migration\Batch3.txt
#
# Update the $BatchNumber variable with the current batch number
# Everything else will work itself out
#
# Logging files are created based upon the batch number for historical purposes
#
#
Function Pause($M="Press any key to continue . . . "){If($psISE){$S=New-Object -ComObject "WScript.Shell";$B=$S.Popup("Click OK to continue.",0,"Script Paused",0);Return};Write-Host -NoNewline $M;$I=16,17,18,20,91,92,93,144,145,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183;While($K.VirtualKeyCode -Eq $Null -Or $I -Contains $K.VirtualKeyCode){$K=$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")};Write-Host}
###########################################################################
###########################################################################
### GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES ###
### GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES ###
### GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES ###
### GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES GLOBAL VARIABLES ###
###########################################################################
###########################################################################
#$ErrorActionPreference = "SilentlyContinue"
#
# Global path variable to where the user batch files are located.
#
$BatchPath = "E:\Temp\Migration"
Clear-Host
Write-Host " " -foregroundcolor yellow
Write-Host " This script will move users listed in a text file to the Lync 2013 Pools" -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " Format of the text file containing users to be moved is: " -foregroundcolor yellow
Write-Host " sip:<SIPURI> or <SIPURI> and any combination of the two " -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " (One user per line. No header)" -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " Migrations are done in batches. Each batch has a number." -foregroundcolor yellow
Write-Host " The text file should be in the format of Batch#.txt " -foregroundcolor yellow
Write-Host " where # represents the batch number." -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " The list/TXT file should be located in the following directory" -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " $BatchPath\Batch#.txt" -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " Example: Batch 3 would be in the format of" -foregroundcolor yellow
Write-Host " $BatchPath\Batch3.txt" -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
[console]::ForegroundColor = "DarkYellow"
$BatchNumber = Read-Host "Enter Batch Number"
[console]::ForegroundColor = "White"
#This will point to the TXT file that contains the users that need to be migrated
$BatchFilePath = "$BatchPath\Batch$BatchNumber.txt"
#This creates the Error log for troubleshooting
$FailedMove = "$BatchPath\FailedLegacyUserMove$BatchNumber.txt"
#This creates a log file to keep a record of all successful moves
$SuccessMove = "$BatchPath\SuccussfullyMigratedUser$BatchNumber.txt"
#
# The following section reads information via powershell using the get-cspool cmdlet
# and filters based upon it having a Registrar Service (should indicate a pool) &
# not being in the backcomp site (i.e. R2). If I find a better way to do this
# I will update it.
#
cls
Write-Host " " -foregroundcolor yellow
Write-Host "`tREADING LYNC POOL INFORMATION (No SBAs) - Be patient" -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
$Poolmenuitems = get-cspool | Where-Object {$_.Services -like "*Registrar*" -and $_.Site -notlike "*BackComp*" -and $_.Services -like "*User*"} | Sort-Object -Property Identity
cls
$count=0
Write-Host " " -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
$menu=@()
foreach($menuitem in $Poolmenuitems)
{
$count+=1
$menu+=$menuitem.fqdn
write-host "$count.) $($menuitem.Identity)"
}
write-host " " -ForegroundColor Yellow
write-host "Select the Destination Lync Pool" -ForegroundColor Yellow
Write-Host " " -foregroundcolor yellow
$selection = Read-Host "Which pool do you want to migrate the users to?"
$LyncPool = $menu[$selection-1]
#
# Confirming selections that user has made. If No, exiting script
#
cls
Write-Host "Use the following parameters? " -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host "User file: " $BatchFilePath -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host "Lync Pool to migrate users to: " $LyncPool -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
Write-Host " " -foregroundcolor yellow
$Response = ""
While ($Response -notmatch '^(Y|N)$')
{
$Response =
Read-Host "Continue (Y/N)?"
}
If ($Response.ToUpper() -eq "N")
{
Exit
}
#
# Making sure the user batch file exists. If it doesn't exist, writing message
# to screen and exiting the script
#
If (Test-Path $BatchFilePath)
{
# This will pull the users that need to be migrated from the TXT file
# Reading list of users from the text file.
$LegacyUser = Get-Content $BatchFilePath
cls
# Starting the migratoin process and informing.
Write-Host " "
Write-Host "Beginning migration for all users to pool $LyncPool"
Write-Host " "
Foreach ($User in $LegacyUser)
{
# Trimming the leading and trailing spaces from the user SIP URI
# Changing to upper case
# Removing SIP: if it exists at the beginning of the string
# Adding SIP: back into string
$SIP = $User.trim()
$SIP = $SIP.ToUpper()
$SIP = $SIP.replace("SIP:","")
#
# Checkin to see if the variable is blank. If so, skipping.
#
If ($SIP -ne "")
{
#$SIP.Length/3
#[MATH]::Floor([decimal]$SIP.length/3)
Switch ([MATH]::Floor(([decimal]$SIP.length+2)/8))
{
4 {$Tabs1 = "`t";Break}
3 {$Tabs1 = "`t`t";Break}
2 {$Tabs1 = "`t`t`t";Break}
1 {$Tabs1 = "`t`t`t`t";Break}
} #End Switch<#
Migrating User: []
12341234123412341234 Migrating User: -$SIP-
#>
Write-Host "Migrating User:`t" -ForegroundColor White -NoNewline
Write-Host "[" -ForegroundColor Cyan -NoNewline
Write-Host $SIP -ForegroundColor Yellow -NoNewline
Write-Host "]" -ForegroundColor Cyan -NoNewline
Write-Host $Tabs1 -NoNewline
Write-Host "Status: " -ForegroundColor White -NoNewline
$SIP = "SIP:" + $SIP
#pause
$ErrorActionPreference = "silentlycontinue"
move-CsLegacyUser –Identity $SIP –Target $LyncPool –Confirm:$false –ErrorVariable “MoveErr”
If ($MoveErr)
{
If ($MoveErr -match "Management object not found for identity")
{
Write-Host "SIP URI is incorrect" -ForegroundColor Cyan“Batch $BatchNumber - SIP URI $SIP does not exist” | Out-file -append -filepath $FailedMove
}
Else
{ #Move failed for the user. CHecking to see if user is already on Lync
$FinalCheck = get-csuser -OnLyncServer -Identity $SIP
If ($FinalCheck.RegistrarPool -ne $null) #User is on Previous Version if this is empty. Need to check if user is on this pool or not.
{
If ($($FinalCheck.RegistrarPool).ToString() -eq $LyncPool)
{
Write-Host "User is already on this pool" -ForegroundColor Cyan“Batch $BatchNumber - User $SIP was already on Lync pool $LyncPool" | Out-file -append -filepath $SuccessMove
}
Else #User is not on the destination pool. Will attempt to move now.
{
move-CsUser –Identity $SIP –Target $LyncPool -MoveConferenceData –Confirm:$false -WarningAction SilentlyContinue –ErrorVariable “MoveErr1”
If ($MoveErr1)
{
Write-Host "Failed" -ForegroundColor Red“Batch $BatchNumber - User $SIP Failed to move to pool $LyncPool” | Out-file -append -filepath $FailedMove
"`t`t--- $MoveErr1.exception.message" | Out-file -append -filepath $FailedMove" " | Out-file -append -filepath $FailedMove
}
Else
{
Write-Host "Lync User moved to new pool" -ForegroundColor Cyan“Batch $BatchNumber - User $SIP was already on Lync and was moved to pool $LyncPool" | Out-file -append -filepath $SuccessMove
}
} #End If ($($FinalCheck.RegistrarPool).ToString() -eq $LyncPool)
} #End If ($FinalCheck.RegistrarPool -ne $null)
Else #User is not on Lync and migration failed
{
Write-Host "Failed" -foregroundcolor Red“Batch $BatchNumber - User $SIP Failed to move to pool $LyncPool” | Out-file -append -filepath $FailedMove
" --- $MoveErr.exception.message" | Out-file -append -filepath $FailedMove" " | Out-file -append -filepath $FailedMove
}
} #End Else
} #End If ($MoveErr)
Else
{
Write-Host "Passed" -ForegroundColor Yellow“Batch $BatchNumber - User $SIP was moved to pool $LyncPool" | Out-file -append -filepath $SuccessMove
}
}#End If ($SIP -ne "")
}#End Foreach ($User in $LegacyUser)
} #End If (Test-Path $BatchFilePath)
Else
{
Write-Warning "The file containing the users to be migrated is not found at $BatchFilePath. Check the path ..."
}
Pause