A PowerShell script to ease migration of File Servers in VMware from 2003 to 2012 R2

Now, that EOS for Windows Server 2003 is coming closer, we need to find easy ways to move away from that version.

File servers are relatively easy compared to other servers, that have locally installed software/services.

If you have Windows Server 2003 file servers, you could use several methods, for example:

  • Windows Server Migration Tools (not recommended on more than 100 GB of data)

  • Microsoft File Server Migration Toolkit (https://www.microsoft.com/en-us/download/details.aspx?id=10268)
    Uses DFS Replication, so be careful with a large number of small files, for example user profiles.

  • Simple ROBOCOPY

  • Backup source and restore on destination

  • SAN data migration

But here's another easy way.

If your file servers are virtual, you could simply make a copy of the virtual disk file and attach to a new server, where share information is imported from the source server, and then rename the new server to the source servers name.

With VMware the easiest way to accomplish this is making a clone of the source VM and then use the cloned VMDK's on the destation VM.

The share information can be exported from this Registry hive:
HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares

After attaching the cloned VMDK's to the destination server, assigning them the correct drive letters in Windows and shutting down the source server, the destination server can now take over the source server's name and IP address.

However, please note, that the clone will be an exact replica of the source server at the initiation of the cloning process.

Therefore we need to prevent users from making changes to the source server during the cloning process.
We do that by stopping and disabling the LanManServer service.

A PowerShell script to automate this process for you?
Well why not? :)

Below is an example of, how that could be done in VMware Vsphere PowerCLI.

We could have included automation of assigning the drive letters in Windows on the destination server.
That would include querying both VMware and Windows and making tables for comparison.
Time did not allow for that, so if you want that, I'll leave it up to you :) You can find example code for similar operations online, maybe you can use some of that.

Add-PSSnapin VMware.VimAutomation.Core

Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false

$VMWareVIServer = Read-Host "Type the name of the VMwareVIServer"

$SourceVMName = Read-Host "Type the single-label name of the 2003 server"

$SourceVMFQDN = Read-Host "The the FQDN of the 2003 server"

$CloneName = Read-Host "Type the name of the created 2003 clone"

$DestinationTempName = Read-Host "Type the current - temporary - name of the 2012 R2 server"

$MailRecipient = Read-Host "Type the mail-recepient for confirmation mail after cloning"

$MailSender = Read-Host "Type the senders email address"

$SMTPServer = Read-Host "Type the FQDN of the SMTP server?"

$ADCred = Get-Credential -Message "Type the account with which to perform AD/Windows computer tasks"

$VMwCred = Get-Credential -Message "Type the account with which to perform the VMware tasks"

 

Write-Host "*** Please wait 30-60 seconds, while we connect to VMware *** "

Connect-VIServer $VMWareVIServer -Credential $VMwCred -ErrorAction Stop

#Check that the typed in Source VM actually exist

Write-Host "**** Please wait 30-60 second, while we check that $SourceVMName exists in VMware ***"

$SourceVMObject = VMware.VimAutomation.Core\Get-VM | where {$_.name -eq $SourceVMName}

if ($SourceVMObject -eq $null)

    { 

    $Host.UI.WriteErrorLine("[-] VM $SourceVMName specified does not exist on this server!")

    Disconnect-VIServer * -Confirm:$false 

    exit 

    } 

#Check that the typed in Clone Name does not exit

Write-Host "**** Please wait 30-60 seconds, while we check that $CloneName does not already exist in VMware ***"

$CloneVMObject = VMware.VimAutomation.Core\Get-VM | where {$_.name -eq $CloneName}

if ($CloneVMObject -ne $null)

    { 

    $Host.UI.WriteErrorLine("[-] VM $CloneName already exists on this server")

    Disconnect-VIServer * -Confirm:$false 

    exit 

    } 

 

Function Clone-VM

{

#Stop and disable LanManServer service on SourceVM to ensure, that no files are updated during cloning

Invoke-Command -ComputerName $SourceVMFQDN -Credential $ADCred {Stop-Service LanManServer -Force -PassThru -ErrorAction Continue}



#Check that LanManServer service on SourceVM has been successfully stopped, and try once more if not. Exit script on second failed attempt.

$SourceService = Invoke-Command -ComputerName $SourceVMFQDN -Credential $ADCred {Get-Service LanManServer}

if($SourceService.Status -ne "Stopped")

    {

    Invoke-Command -ComputerName $SourceVMFQDN -Credential $ADCred {Stop-Service LanManServer -Force -PassThru -ErrorAction Continue}

    $Timeout = New-Timespan -Seconds 30

    $StopWatch = [diagnostics.stopwatch]::StartNew()

    While (($StopWatch.elapsed -lt $timeout) -and ((Invoke-Command -ComputerName $SourceVMFQDN -Credential $ADCred {Get-Service LanManServer}).Status -ne "Stopped") )

        {

            Start-Sleep -seconds 3

        }

    $StopWatch.Stop()

    $SourceService = Invoke-Command -ComputerName $SourceVMFQDN -Credential $ADCred {Get-Service LanManServer}

    if($SourceService.Status -ne "Stopped")

        {

        $Host.UI.WriteErrorLine("[-] LanManServer Service did not stop on source server $SourceVMName. Script exits")

        Send-MailMessage -To $MailRecipient -Subject "Cloning script for $SourceVMName failed" -Body "LanManServer Service did not stop on source server $SourceVMName. Script exits" -SmtpServer $SMTPServer -From $MailSender -Priority High -ErrorAction Continue

        exit 

        }

    }

Invoke-Command -ComputerName $SourceVMFQDN -Credential $ADCred {Set-Service LanManServer -StartupType Disabled -PassThru -ErrorAction Continue}

 

#Cloning of SourceVM and ensurance, that clone is powered off

$VMResourcePool = $SourceVMObject.ResourcePool

$ProcessStartTime = Get-Date

Write-Host "Cloning process started at"$ProcessStartTime

VMware.VimAutomation.Core\New-VM -VM $SourceVMName -Name $CloneName -ResourcePool $VMResourcePool

$CloningFinishTime = Get-Date

Write-Host "Clone created at"$CloningFinishTime

#Ensure that the clone is in a stopped state

VMware.VimAutomation.Core\Get-VM $CloneName | VMware.VimAutomation.Core\Stop-VM -Confirm:$false -RunAsync -ErrorAction SilentlyContinue

$ProcessFinishTime = Get-Date

Write-Host "Process finished at"$ProcessFinishTime

#Send email to MailRecipient when function finishes

Send-MailMessage -To $MailRecipient -Subject "Cloning of $SourceVMName to $CloneName has completed" -Body "Cloning of $SourceVMName to $CloneName has completed. Start Time: $ProcessStartTime. Finished at: $ProcessFinishTime" -SmtpServer $SMTPServer -From $MailSender -Priority High -ErrorAction Continue

}

 

 

#Ask for OK for initiation of cloning process

$Title = "Start Cloning?"

$Message = "Do you want to stop SMB access to $SourceVMName and start cloning $SourceVMName to $CloneName ?"

$Yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `

"Starts cloning process and then stops and disables LanManServer service on source server."

$No = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `

"Leaves the script without making any changes."

$Options = [System.Management.Automation.Host.ChoiceDescription[]]($Yes, $No)

$Result = $host.ui.PromptForChoice($Title, $Message, $Options, 1)

switch ($Result)

    {

    0 {Clone-VM}

    1 {exit}

    }

 

Disconnect-VIServer * -Confirm:$false