2010-01-20

vCenter PowerCLI Migration Script

As I promised in a previous post I wanted to migrate from a vCenter to whole new machine

Process was:

  • Export folders
  • Export VM locations in Folders
  • Export Permissions
  • Export Custom Attributes
  • Create Folders on the new vCenter
  • Disable DRS/HA
  • Remove ESX hosts from Source vCenter and add to Destination vCenter
  • Enable DRS/HA again
  • Move all vm’s to correct folders
  • Apply the permissions back
  • Apply custom attributes and notes

Here is the script

   1: #load Vmware Module
   2: Add-PSSnapin VMware.VimAutomation.Core
   3:  
   4: #Change to multi-mode vcenter management
   5: Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Confirm:$false
   6:  
   7: #Get vCenter Server Names
   8: $sourceVI = Read-Host "Please enter the name of the source Server"; 
   9: $destVI = Read-Host "Please enter the name of the destination Server"
  10:  
  11: $creds = get-credential
  12:  
  13: $datacenter = Read-Host "Please give the name of the datacenter you would like to run against"
  14:  
  15:  
  16: #Connect to Source vCenter
  17: connect-viserver -server $sourceVI -credential $creds
  18: connect-viserver -server $destVI -credential $creds -NotDefault:$false
  19:  
  20:  
  21: filter Get-FolderPath {
  22:     $_ | Get-View | % {
  23:         $row = "" | select Name, Path
  24:         $row.Name = $_.Name
  25:  
  26:         $current = Get-View $_.Parent
  27:         $path = $_.Name
  28:         do {
  29:             $parent = $current
  30:             if($parent.Name -ne "vm"){$path = $parent.Name + "\" + $path}
  31:             $current = Get-View $current.Parent
  32:         } while ($current.Parent -ne $null)
  33:         $row.Path = $path
  34:         $row
  35:     }
  36: }
  37:  
  38: ## Export all folders
  39: $report = @()
  40: $report = get-datacenter $datacenter -Server $sourceVI| Get-folder vm | get-folder | Get-Folderpath
  41:         ##Replace the top level with vm
  42:         foreach ($line in $report) {
  43:         $line.Path = ($line.Path).Replace($datacenter + "\","vm\")
  44:         }
  45: $report | Export-Csv "c:\Folders-with-FolderPath-$($datacenter).csv" -NoTypeInformation
  46:  
  47: ##Export all VM locations
  48: $report = @()
  49: $report = get-datacenter $datacenter -Server $sourceVI| get-vm | Get-Folderpath
  50:  
  51: $report | Export-Csv "c:\vms-with-FolderPath-$($datacenter).csv" -NoTypeInformation
  52:  
  53:  
  54: #Get the Permissions  
  55:  
  56: $folderperms = get-datacenter $datacenter -Server $sourceVI | Get-Folder | Get-VIPermission
  57: $vmperms = Get-Datacenter $datacenter -Server $sourceVI | get-vm | Get-VIPermission
  58:  
  59: $permissions = get-datacenter $datacenter -Server $sourceVI | Get-VIpermission
  60:         
  61:         $report = @()
  62:               foreach($perm in $permissions){
  63:                 $row = "" | select EntityId, FolderName, Role, Principal, IsGroup, Propagate
  64:                 $row.EntityId = $perm.EntityId
  65:                 $Foldername = (Get-View -id $perm.EntityId).Name
  66:                 $row.FolderName = $foldername
  67:                 $row.Principal = $perm.Principal
  68:                 $row.Role = $perm.Role
  69:                 $row.IsGroup = $perm.IsGroup
  70:                 $row.Propagate = $perm.Propagate
  71:                 $report += $row
  72:             }
  73:     
  74:             foreach($perm in $folderperms){
  75:                 $row = "" | select EntityId, FolderName, Role, Principal, IsGroup, Propagate
  76:                 $row.EntityId = $perm.EntityId
  77:                 $Foldername = (Get-View -id $perm.EntityId).Name
  78:                 $row.FolderName = $foldername
  79:                 $row.Principal = $perm.Principal
  80:                 $row.Role = $perm.Role
  81:                 $row.IsGroup = $perm.IsGroup
  82:                 $row.Propagate = $perm.Propagate
  83:                 $report += $row
  84:             }
  85:  
  86:             foreach($perm in $vmperms){
  87:                 $row = "" | select EntityId, FolderName, Role, Principal, IsGroup, Propagate
  88:                 $row.EntityId = $perm.EntityId
  89:                 $Foldername = (Get-View -id $perm.EntityId).Name
  90:                 $row.FolderName = $foldername
  91:                 $row.Principal = $perm.Principal
  92:                 $row.Role = $perm.Role
  93:                 $row.IsGroup = $perm.IsGroup
  94:                 $row.Propagate = $perm.Propagate
  95:                 $report += $row
  96:             }
  97:  
  98:         $report | export-csv "c:\perms-$($datacenter).csv" -NoTypeInformation
  99:  
 100: ##Export VM Custom Attributes and notes
 101:  
 102: $vmlist = get-datacenter $datacenter -Server $sourceVI| get-vm 
 103: $Report =@()
 104:     foreach ($vm in $vmlist) {
 105:         $row = "" | Select Name, Notes, Key, Value, Key1, Value1
 106:         $row.name = $vm.Name
 107:         $row.Notes = $vm | select -ExpandProperty Notes
 108:         $customattribs = $vm | select -ExpandProperty CustomFields
 109:         $row.Key = $customattribs[0].Key
 110:         $row.Value = $customattribs[0].value
 111:         $row.Key1 = $customattribs[1].Key
 112:         $row.Value1 = $customattribs[1].value    
 113:         $Report += $row
 114:     }
 115:  
 116: $report | Export-Csv "c:\vms-with-notes-and-attributes-$($datacenter).csv" -NoTypeInformation
 117:    
 118:     
 119: ##Disconnect-VIServer -Server $sourceVI -force -confirm:$false
 120:  
 121:  
 122: #connect to Destination Server
 123: ##connect-viserver -server $destVI -credential $creds -confirm:$false
 124:  
 125:  
 126: ##IMPORT FOLDERS
 127: $vmfolder = Import-Csv "c:\Folders-with-FolderPath-$($datacenter).csv" | Sort-Object -Property Path
 128:  
 129: foreach($folder in $VMfolder){
 130:     $key = @()
 131:     $key =  ($folder.Path -split "\\")[-2]
 132:     if ($key -eq "vm") {
 133:         get-datacenter $datacenter -Server $destVI | get-folder vm | New-Folder -Name $folder.Name
 134:         } else {
 135:         get-datacenter $datacenter -Server $destVI | get-folder vm | get-folder $key | New-Folder -Name $folder.Name 
 136:         }
 137: }
 138:  
 139: ##ESX host migration
 140:  
 141: #Switch off HA
 142: Get-Cluster $datacenter -Server $sourceVI  | Set-Cluster -HAEnabled:$false -DrsEnabled:$false -Confirm:$false
 143:  
 144: #Remove ESX hosts from old vcenter
 145: $Myvmhosts = get-datacenter $datacenter -Server $sourceVI | Get-VMHost 
 146: foreach ($line in $Myvmhosts) {
 147: Get-vmhost -Server $sourceVI -Name $line.Name | Set-VMHost -State "Disconnected" -Confirm:$false
 148: Get-VMHost -server $sourceVI -Name $line.Name | Remove-VMHost -Confirm:$false
 149: }
 150: #add ESX hosts into new vcenter
 151: foreach ($line in $Myvmhosts) {
 152:     Add-VMHost -Name $line.name  -Location (Get-Datacenter $datacenter -server $destVI) -user root -Password trunk@1 -Force
 153: }
 154:  
 155: #Turn on HA and DRS on 
 156: Set-Cluster -Server $destVI Cluster1 -DrsEnabled:$true -HAEnabled:$true -Confirm:$false
 157:  
 158: Disconnect-VIServer $sourceVI -Confirm:$false
 159:  
 160: ##workaround for non working new-vipermissions
 161:            
 162: function New-VIAccount($principal) {
 163:     $flags = [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Public -bor [System.Reflection.BindingFlags]::DeclaredOnly -bor [System.Reflection.BindingFlags]::Instance
 164:     
 165:     $method = $defaultviserver.GetType().GetMethods($flags) | where { $_.Name -eq "VMware.VimAutomation.Types.VIObjectCore.get_Client" }
 166:     $client = $method.Invoke($global:DefaultVIServer, $null)
 167:     Write-Output (New-Object VMware.VimAutomation.Client20.PermissionManagement.VCUserAccountImpl -ArgumentList $principal, "", $client)
 168: }
 169:  
 170: ##move the vm's to correct location
 171: $VMfolder = @()
 172: $VMfolder = import-csv "c:\VMs-with-FolderPath-$($datacenter).csv" | Sort-Object -Property Path
 173: foreach($guest in $VMfolder){
 174:     $key = @()
 175:     $key =  Split-Path $guest.Path | split-path -leaf
 176:     Move-VM (get-datacenter $datacenter -Server $destVI  | Get-VM $guest.Name) -Destination (get-datacenter $datacenter -Server $destVI | Get-folder $key) 
 177: }
 178:  
 179:  
 180: ##Import VM Custom Attributes and Notes
 181: $NewAttribs = Import-Csv "C:\vms-with-notes-and-attributes-$($datacenter).csv"
 182:  
 183:     foreach ($line in $NewAttribs) {
 184:         set-vm -vm $line.Name -Description $line.Notes -Confirm:$false
 185:         Set-CustomField -Entity (get-vm $line.Name) -Name $line.Key -Value $line.Value -confirm:$false
 186:         Set-CustomField -Entity (get-vm $line.Name) -Name $line.Key1 -Value $line.Value1 -confirm:$false
 187:     
 188:     }
 189:     
 190:  
 191: ##Import Permissions
 192: $permissions = @()
 193: $permissions = Import-Csv "c:\perms-$($datacenter).csv"
 194:  
 195: foreach ($perm in $permissions) {
 196:     $entity = ""
 197:     $entity = New-Object VMware.Vim.ManagedObjectReference
 198:     
 199:     switch -wildcard ($perm.EntityId)
 200:         {
 201:              Folder* { 
 202:              $entity.type = "Folder"
 203:              $entity.value = ((get-datacenter $datacenter | get-folder $perm.Foldername).ID).Trimstart("Folder-")
 204:              }
 205:              VirtualMachine* { 
 206:              $entity.Type = "VirtualMachine"
 207:              $entity.value = ((get-datacenter $datacenter | Get-vm $perm.Foldername).Id).Trimstart("VirtualMachine-")             
 208:             }
 209:         }
 210:     $setperm = New-Object VMware.Vim.Permission
 211:     $setperm.principal = $perm.Principal
 212:         if ($perm.isgroup -eq "True") {
 213:             $setperm.group = $true
 214:             } else {
 215:             $setperm.group = $false
 216:             }
 217:     $setperm.roleId = (Get-virole $perm.Role).id
 218:     if ($perm.propagate -eq "True") {
 219:             $setperm.propagate = $true
 220:             } else {
 221:             $setperm.propagate = $false
 222:             }
 223:                 
 224:     $doactual = Get-View -Id 'AuthorizationManager-AuthorizationManager'
 225:     $doactual.SetEntityPermissions($entity, $setperm)
 226: }
 227:     
 228: ##Error Checking
 229: ################
 230:  
 231: ##Gather all info for New Vcenter        
 232: ##Export all folders
 233: $report = @()
 234: $report = Get-folder vm -server $destVI | get-folder | Get-Folderpath
 235:         ##Replace the top level with vm
 236:         foreach ($line in $report) {
 237:         $line.Path = ($line.Path).Replace("DC1\","vm\")
 238:         }
 239: $report | Export-Csv "c:\Folders-with-FolderPath_dest.csv" -NoTypeInformation
 240:  
 241: ##Export all VM locations
 242: $report = @()
 243: $report = get-vm -server $destVI | Get-Folderpath
 244:  
 245: $report | Export-Csv "c:\vms-with-FolderPath_dest.csv" -NoTypeInformation
 246:  
 247:  
 248: #Get the Permissions    
 249: $permissions = Get-VIpermission -Server $destVI
 250:         
 251:         $report = @()
 252:               foreach($perm in $permissions){
 253:                 $row = "" | select EntityId, FolderName, Role, Principal, IsGroup, Propopgate
 254:                 $row.EntityId = $perm.EntityId
 255:                 $Foldername = (Get-View -id $perm.EntityId).Name
 256:                 $row.FolderName = $foldername
 257:                 $row.Principal = $perm.Principal
 258:                 $row.Role = $perm.Role
 259:                 $report += $row
 260:             }
 261:         $report | export-csv "c:\perms_dest.csv" -NoTypeInformation
 262:  
 263: ##Export VM Custom Attributes and notes
 264:  
 265: $vmlist = get-vm -Server $destVI
 266: $Report =@()
 267:     foreach ($vm in $vmlist) {
 268:         $row = "" | Select Name, Notes, Key, Value, Key1, Value1
 269:         $row.name = $vm.Name
 270:         $row.Notes = $vm | select -ExpandProperty Notes
 271:         $customattribs = $vm | select -ExpandProperty CustomFields
 272:         $row.Key = $customattribs[0].Key
 273:         $row.Value = $customattribs[0].value
 274:         $row.Key1 = $customattribs[1].Key
 275:         $row.Value1 = $customattribs[1].value    
 276:         $Report += $row
 277:     }
 278:  
 279: $report | Export-Csv "c:\vms-with-notes-and attributes_dest.csv" -NoTypeInformation
 280:  
 281: ##compare the source and destination - this part is not yet finished
 282: write-output "Folder-paths"
 283: Compare-Object -ReferenceObject (import-csv C:\vms-with-FolderPath.csv) (import-csv C:\vms-with-FolderPath_dest.csv) -IncludeEqual
 284:  
 285:  
 286: write-output "Notes & Attributes"
 287: Compare-Object -ReferenceObject (import-csv "C:\vms-with-notes-and attributes.csv") (import-csv "C:\vms-with-notes-and attributes_dest.csv") -IncludeEqual
 288:  
 289: write-output "Permissions"
 290: Compare-Object -ReferenceObject (import-csv C:\perms.csv | select * -ExcludeProperty EntityId) (import-csv C:\perms_dest.csv | select * -ExcludeProperty EntityId) -IncludeEqual
 291: Disconnect-VIServer -Server $destVI -Force -confirm:$false
 292:     

The script is commented pretty well throughout the script, I will update with more and a walkthrough of the script later.

Give me a shout if you have any questions with the script

The script can also be downloaded below

Save