System Center Virtual Machine Manager 2012 R2: Migrating Tenants and Clouds

We’re back with our series on System Center Virtual Machine Manager 2012 R2 (SCVMM 2012 R2)! In part one, I discussed upgrading to System Center Virtual Machine Manager 2012 R2. In part two, I gave an overview to migrating to SCVMM, and in part three, we went over migrating the hosts and library.

With all the resources for our new fabric now in place, its time to recreate all the meta-data which defines our environment. We will address SCVMM 2012 R2 and migrating tenants (roles), clouds, virtual machines, and library assets, along with all their respective associations.

Unlike the steps we have completed to date, we had the ability to primarily use loops to define the environment. However, now we will need to depend exclusively on the data that we’ll export from the original. We will now refer to as the source VMM environment as the foundation for our new environment, which we will reference as the target VMM environment.

Delegated Administrators

The first of the entities that I will create in my environment is actually quite simple. I only have a single delegated administrator, which is offered management of all my libraries and the hosts in the “Operations” group. To implement this, I use the following PowerShell

​ $UserRole = New-SCUserRole -Name "!Lab Administrators" -UserRoleProfile "DelegatedAdmin" -Description "Lab Management Team"
$scopeToAdd = @()
$scopeToAdd += Get-SCVMHostGroup -Name "Operations"
$scopeToAdd += Get-SCLibraryServer –ComputerName PDC-FS-SMB01
$scopeToAdd += Get-SCLibraryServer -ComputerName PDC-SC-VMM02
$scopeToAdd += Get-SCRunAsAccount -Name "SCVMM Agent Management"
Set-SCUserRole -AddMember @("DigiNerve\!grp IT Lab Administrators", "DigiNerve\!grp SCVMM Admins") -AddScope $scopeToAdd -UserRole $UserRole

Self-Service User Roles

Our first export will be the existing user roles (or as otherwise known in VMM, tenancies) from the source environment. This export will contain the name of the role and its description. In addition, the parent user role along with all the AD accounts that are members of this role, the clouds available to the tenant, and the permissions that the tenant is allowed to execute.

Note: This export is primarily coded to export from 2012 and 2012 SP1. In the R2 version Microsoft has finally configured the tenant roles to have per-cloud permissions; therefore, if you plan to export for the R2 environment, you will need to adjust the script to capture permissions per cloud.

Source Export

All the export scripts will create a simple CSV file. The reason I have not chosen to use XML for this is to make the process a lot easier for you to edit the file if you choose to modify what is needed to be migrated between the source and target environments.

Our first script creates a CSV file called UserRoles.csv, which contains all the main metadata for our user roles. As you can expect, this script is to be executed on the source VMM environment; when complete, the generated CSV file transferred to the new VMM environment for reloading once any necessary edits are completed.

​ $ExportedRoles = @() 
$Tenants = Get-SCUserRole | ?{$_.Profile -eq "SelfServiceUser"} 
foreach ($Role in $Tenants) 
   $ExportedRoles += $Role | select Name, Description, ParentUserRole, @{Name='Member0';Expression={$_.Members[0].name}}, @{Name='Member1';Expression={$_.Members[1].name}},  @{Name='Member2';Expression={$_.Members[2].name}}, @{Name='Member3';Expression={$_.Members[3].name}}, @{Name='Member4';Expression={$_.Members[4].name}}, @{Name='Member5';Expression={$_.Members[5].name}}, @{Name='Member6';Expression={$_.Members[6].name}}, @{Name='Member7';Expression={$_.Members[7].name}}, @{Name='Member8';Expression={$_.Members[8].name}}, @{Name='Member9';Expression={$_.Members[9].name}}, @{Name='Cloud0';Expression={$_.Cloud[0].name}}, @{Name='Cloud1';Expression={$_.Cloud[1].name}}, @{Name='Cloud2';Expression={$_.Cloud[2].name}}, @{Name='Cloud3';Expression={$_.Cloud[3].name}}, @{Name='Cloud4';Expression={$_.Cloud[4].name}}, @{Name='Cloud5';Expression={$_.Cloud[5].name}}, @{Name='Cloud6';Expression={$_.Cloud[6].name}}, @{Name='Cloud7';Expression={$_.Cloud[7].name}}, @{Name='Cloud8';Expression={$_.Cloud[8].name}}, @{Name='Cloud9';Expression={$_.Cloud[9].name}}, @{Name='Permission0';Expression={$_.VMPermission[0]}}, @{Name='Permission1';Expression={$_.VMPermission[1]}}, @{Name='Permission2';Expression={$_.VMPermission[2]}}, @{Name='Permission3';Expression={$_.VMPermission[3]}}, @{Name='Permission4';Expression={$_.VMPermission[4]}}, @{Name='Permission5';Expression={$_.VMPermission[5]}}, @{Name='Permission6';Expression={$_.VMPermission[6]}}, @{Name='Permission7';Expression={$_.VMPermission[7]}}, @{Name='Permission8';Expression={$_.VMPermission[8]}}, @{Name='Permission9';Expression={$_.VMPermission[9]}},@{Name='Permission10';Expression={$_.VMPermission[10]}}, @{Name='Permission11';Expression={$_.VMPermission[11]}}, @{Name='Permission12';Expression={$_.VMPermission[12]}}, @{Name='Permission13';Expression={$_.VMPermission[13]}}, @{Name='Permission14';Expression={$_.VMPermission[14]}}, @{Name='Permission15';Expression={$_.VMPermission[15]}}, @{Name='Permission16';Expression={$_.VMPermission[16]}} 
$ExportedRoles | Export-Csv UserRoles.csv

Target Import

Now, after we have produced our export file and switched our focus over to the new VMM environment, the following script will load up the CSV file and loop through its content. Each row of the file is then processed and executed with the New-SCUserRole command to create the role or tenant in the target environment.

​ $Tenants = Import-Csv .\UserRoles.csv
foreach ($Role in $Tenants) 
   # Clean Up Null Fields
   if ( $Role.Description -eq $null) { $Description = "" } else { $Description = $Role .Description}

   # Determine the Parent for this new Role
   $ParentUserRoleID = Get-SCUserRole -Name $Role.ParentUserRole

   # Create the Users Role
   $UserRoleID = New-SCUserRole -Name $Role .Name -Description $Role.Description -UserRoleProfile "SelfServiceUser" -ParentUserRole $ParentUserRoleID 

    $MemberList = $null
   $MemberList = @() 
   if ( $Role.Member0 -ne "") { $MemberList += $Role.Member0 }
   if ( $Role.Member1 -ne "") { $MemberList += $Role.Member1 }
   if ( $Role.Member2 -ne "") { $MemberList += $Role.Member2 } 
   if ( $Role.Member3 -ne "") { $MemberList += $Role.Member3 } 
   if ( $Role.Member4 -ne "") { $MemberList += $Role.Member4 } 
   if ( $Role.Member5 -ne "") { $MemberList += $Role.Member5 }  
   if ( $Role.Member6 -ne "") { $MemberList += $Role.Member6 } 
   if ( $Role.Member7 -ne "") { $MemberList += $Role.Member7 } 
   if ( $Role.Member8 -ne "") { $MemberList += $Role.Member8 } 
   if ( $Role.Member9 -ne "") { $MemberList += $Role.Member9 } 

   $PermissionList = $null 
   $PermissionList = @() 
   if ( $Role.Permission0 -ne "") { $PermissionList += $Role.Permission0 } 
   if ( $Role.Permission1 -ne "") { $PermissionList += $Role.Permission1 } 
   if ( $Role.Permission2 -ne "") { $PermissionList += $Role.Permission2 } 
   if ( $Role.Permission3 -ne "") { $PermissionList += $Role.Permission3 } 
   if ( $Role.Permission4 -ne "") { $PermissionList += $Role.Permission4 } 
   if ( $Role.Permission5 -ne "") { $PermissionList += $Role.Permission5 } 
   if ( $Role.Permission6 -ne "") { $PermissionList += $Role.Permission6 } 
   if ( $Role.Permission7 -ne "") { $PermissionList += $Role.Permission7 } 
   if ( $Role.Permission8 -ne "") { $PermissionList += $Role.Permission8 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission9 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission10 }
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission11 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission12 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission13 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission14 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission15 } 
   if ( $Role.Permission9 -ne "") { $PermissionList += $Role.Permission16 } 

   Set-SCUserRole -UserRole $UserRoleID -Permission $PermissionList -AddMember $MemberList -ShowPROTips $false 

Self-Service User Roles VM Networks

The next step in regenerating our target environment, is to export all the VM networks that are granted to each tenant role.

Source Export

Using a modified version of our first script, we will create a new CSV file called VMNetworks.csv which lists all of the networks assigned to a role

​ $ExportedVMNetworks = @() 
$VMNetworks = Get-SCVMNetwork 
foreach ($VMNetwork in $VMNetworks) 
   $ExportedVMNetworks += $VMNetwork | select Name, @{Name='GrantedToList0';Expression={$_.GrantedToList[0].name}}, @{Name='GrantedToList1';Expression={$_.GrantedToList[1].name}},  @{Name='GrantedToList2';Expression={$_.GrantedToList[2].name}}, @{Name='GrantedToList3';Expression={$_.GrantedToList[3].name}}, @{Name='GrantedToList4';Expression={$_.GrantedToList[4].name}}, @{Name='GrantedToList5';Expression={$_.GrantedToList[5].name}}, @{Name='GrantedToList6';Expression={$_.GrantedToList[6].name}}, @{Name='GrantedToList7';Expression={$_.GrantedToList[7].name}}, @{Name='GrantedToList8';Expression={$_.GrantedToList[8].name}}, @{Name='GrantedToList9';Expression={$_.GrantedToList[9].name}}, @{Name='GrantedToList10';Expression={$_.GrantedToList[10].name}}, @{Name='GrantedToList11';Expression={$_.GrantedToList[11].name}},  @{Name='GrantedToList12';Expression={$_.GrantedToList[12].name}}, @{Name='GrantedToList13';Expression={$_.GrantedToList[13].name}}, @{Name='GrantedToList14';Expression={$_.GrantedToList[14].name}}, @{Name='GrantedToList15';Expression={$_.GrantedToList[15].name}}, @{Name='GrantedToList16';Expression={$_.GrantedToList[16].name}} 
$ExportedVMNetworks | Export-Csv VMNetworks.csv

Target Import

On the target system, we repeat a similar looping process to read each line of the CSV, which will then select all the VM Networks we defined as we built out the target fabric, and assign these to the relevant tenants.

​ $VMNetworkList = Import-Csv .\VMNetworks.csv 
foreach ($VMNetwork in $VMNetworkList) 
   $GrantedToList = $null
   $GrantedToList = @()
   if ($VMNetwork.GrantedToList0 -ne "") { $GrantedToList += $VMNetwork.GrantedToList0 } 
   if ($VMNetwork.GrantedToList1 -ne "") { $GrantedToList += $VMNetwork.GrantedToList1 } 
   if ($VMNetwork.GrantedToList2 -ne "") { $GrantedToList += $VMNetwork.GrantedToList2 } 
   if ($VMNetwork.GrantedToList3 -ne "") { $GrantedToList += $VMNetwork.GrantedToList3 } 
   if ($VMNetwork.GrantedToList4 -ne "") { $GrantedToList += $VMNetwork.GrantedToList4 } 
   if ($VMNetwork.GrantedToList5 -ne "") { $GrantedToList += $VMNetwork.GrantedToList5 } 
   if ($VMNetwork.GrantedToList6 -ne "") { $GrantedToList += $VMNetwork.GrantedToList6 } 
   if ($VMNetwork.GrantedToList7 -ne "") { $GrantedToList += $VMNetwork.GrantedToList7 } 
   if ($VMNetwork.GrantedToList8 -ne "") { $GrantedToList += $VMNetwork.GrantedToList8 } 
   if ($VMNetwork.GrantedToList9 -ne "") { $GrantedToList += $VMNetwork.GrantedToList9 } 
   if ($VMNetwork.GrantedToList10 -ne "") { $GrantedToList += $VMNetwork.GrantedToList10 } 
   if ($VMNetwork.GrantedToList11 -ne "") { $GrantedToList += $VMNetwork.GrantedToList11 } 
   if ($VMNetwork.GrantedToList12 -ne "") { $GrantedToList += $VMNetwork.GrantedToList12 } 
   if ($VMNetwork.GrantedToList13 -ne "") { $GrantedToList += $VMNetwork.GrantedToList13 } 
   if ($VMNetwork.GrantedToList14 -ne "") { $GrantedToList += $VMNetwork.GrantedToList14 } 
   if ($VMNetwork.GrantedToList15 -ne "") { $GrantedToList += $VMNetwork.GrantedToList15 } 
   if ($VMNetwork.GrantedToList16 -ne "") { $GrantedToList += $VMNetwork.GrantedToList16 } 

   $NetworkName = Get-SCVMNetwork -Name $VMNetwork.Name 
   Grant-SCResource -Resource $NetworkName  -UserRoleName $GrantedToList 

Export the Clouds

With the Roles in place with their associated networks, we will need focus on the Clouds, the process we will use should now be starting to feel familiar,

Source Export

Keeping the scripts simple, the next CSV we will generate is called Clouds.csv, and contains most of the important cloud metadata. Information that we will place in this file includes the name and description of the cloud, the primary user role, all the associated logical networks, and any other attached resource assigned to each of the clouds.

​ $ExportedClouds = @() 
$Clouds = Get-SCCloud 
foreach ($Cloud in $Clouds) 
   $ExportedClouds += $Cloud | select Name, Description, ParentUserRole, @{Name='LogicalNetworks0';Expression={$_.LogicalNetworks[0].name}}, @{Name='LogicalNetworks1';Expression={$_.LogicalNetworks[1].name}},  @{Name='LogicalNetworks2';Expression={$_.LogicalNetworks[2].name}}, @{Name='LogicalNetworks3';Expression={$_.LogicalNetworks[3].name}}, @{Name='LogicalNetworks4';Expression={$_.LogicalNetworks[4].name}}, @{Name='Resources0';Expression={$_.Resources[0].name}}, @{Name='Resources1';Expression={$_.Resources[1].name}}, @{Name='Resources2';Expression={$_.Resources[2].name}}, @{Name='Resources3';Expression={$_.Resources[3].name}}, @{Name='Resources4';Expression={$_.Resources[4].name}} 
$ExportedClouds | Export-Csv Clouds.csv

Target Import

On the target system, in a quite similar manner to the previous loads we completed, simply iterate through the content of our CSV file. Using some static information such as our port classifications, and storage classifications, we use both the Set-SCCloud and New-SCCloud commands in a job format to establish and define the target clouds. Also, to keep this moving, we allow VMM to run the procedure asynchronously.

​ $Clouds = Import-Csv .\Clouds.csv 
foreach ($Cloud in $Clouds) 
   # Clean Up Null Fields  
   if ($Cloud.Description -eq $null) { $Description = "" } else { $Description = $Cloud.Description} 

   $JobGUID = ([System.Guid]::NewGuid()) 
   $jobID = $JobGUID.Guid  
   $resources = @()  

   if ($Cloud.LogicalNetworks0 -ne "") { $resources += Get-SCLogicalNetwork -Name $Cloud.LogicalNetworks0 } 
   if ($Cloud.LogicalNetworks1 -ne "") { $resources += Get-SCLogicalNetwork -Name $Cloud.LogicalNetworks1 } 
   if ($Cloud.LogicalNetworks2 -ne "") { $resources += Get-SCLogicalNetwork -Name $Cloud.LogicalNetworks2 } 
   if ($Cloud.LogicalNetworks3 -ne "") { $resources += Get-SCLogicalNetwork -Name $Cloud.LogicalNetworks3 } 
   if ($Cloud.LogicalNetworks4 -ne "") { $resources += Get-SCLogicalNetwork -Name $Cloud.LogicalNetworks4 } 

   $resources += Get-SCPortClassification -Name "High bandwidth" 
   $resources += Get-SCPortClassification -Name "Low bandwidth" 
   $resources += Get-SCPortClassification -Name "Medium bandwidth" 

   $resources += Get-SCStorageClassification -Name "Remote Storage" 

   $addCapabilityProfiles = @()  
   $addCapabilityProfiles += Get-SCCapabilityProfile -Name "Hyper-V" 
   Set-SCCloud -JobGroup $JobID -RunAsynchronously -AddCloudResource $resources -AddCapabilityProfile $addCapabilityProfiles 

   $hostGroups = @() 
   $hostGroups += Get-SCVMHostGroup –Name "Operations" 
   New-SCCloud -JobGroup $JobID -VMHostGroup $hostGroups -Name $Cloud.Name -Description $Cloud.Description -RunAsynchronously 


Next Steps

At this point we are about three-quarters of the way through to completing our migration activities. You should be able to perceive the flexibility with which the migration path offers you as you get to pick and select which elements from the source VMM environment you wish to have reestablished in the destination VMM environment.

In the next batch of steps, we will enable the delegation of the new clouds to their respective tenants, reapply the quotas on our clouds, and of course finally update our virtual machines so that they are assigned back to their respective owners, tenants, and clouds.