Copy Folders Permissions and Roles from vCenter

Copy Folders Permissions and Roles from vCenter

During a recent migration of a large environment including hundreds of folders and permissions, there was no way I was going to manually write them out again, especially as the disaster recovery site requires the exact same hierarchy. Below you will find the same script I used to copy out all permissions and folders ready to import to the new vCenter. Luckily following this process saved me a few days as well as my sanity. I’m hoping to gather a few scrips for ease of migration and building in a collection of migration automation series on this site so check back for other useful articles.

Just say thanks to PowerCLI experts, specially “Virtually Jason” for this particular PowerShell Script which can save your day

For your information, the script worked moving from VC 6.0 to VC 6.7 , although,  this may work with the other flavours of vSphere.

 

Following steps are for the source vCenter
  • Login to Source Virtual Center.
  • Open vSphere PowerCLI cmdlet
  • Connect Virtual Center Server using below command.

Connect-VIServer SourceVCenterName

There are two parts of this script;

  1. Get-SourceConfiguration from Source vCenter,
  2. Set-SourceConfiguration in Destination vCenter.
Ensure the Datacenter within vCenter is the same name at the new vCenter. This can be changed without any issue during the migration.
  • Save below highlighted Get-SourceConfiguration script in any location as “Get-SourceConfiguration.ps1” (c:\temp)
  • Go to PowerCLI and locate the file (> cd c:\temp)
  • Run the command .\Get-SourceConfiguration.ps1
  • The “Local Output Directory” will pop up asking where to save the .XML file. Save this (c:\temp)
  • The source vCenter Datacenter name is the VC you are copying from
  • Once complete, four files will output to the folder (c:\temp)
    • Folder details
    • Permissions on the vDC
    • folders and machines
    • Roles on VC
    • VM hierachy

 

**Datacentre of source and destination need temporary be the same name.**
**Set-ExecutionPolicy unrestricted**

Get-SourceConfiguration Script

  • Save below highlighted Get-SourceConfiguration script in any location as “Get-SourceConfiguration.ps1
#Get Data from Source vCenter
#Built to be used with Set-SourceSettings.ps1 to recreate those same settings in another vCenter.
#Does not support vApps or multiple datacenters in the same vCenter.
param
(
        $directory = $(read-host "Enter local output directory"),
        $datacenter = $(read-host "Enter datacenter"),
        [switch]$getTemplates
)
#Takes a VI Folder object and returns an array of strings that represents that folder's absolute path in the inventory
function get-folderpath
{
        param
        (
                $thisFolder
        )
        #Creates an array of folders back to the root folder
        if ($thisFolder.id -like "Folder*")
        {
                $folderArray = @()
                $folderArray += $thisFolder
                while ($folderArray[-1].parent.parent.id -match "Folder")
                {
                        $folderArray += $folderArray[-1].parent
                }
                [array]::Reverse($folderArray)
                #convert the array of folders to an array of strings with just the folder names
                $folderStrArray = @()
                $folderArray | %{$folderStrArray += $_.name}
                $folderStrArray
        }
        else
        {
                write-error "Unexpected input provided; does not appear to be a Folder."
        }
}

$directory = $directory.trim("\") #" This comment is to fix the gistit syntax highlighting.
new-item $directory -type directory -erroraction silentlycontinue

if ((get-datacenter).count -gt 1){write-error "These scripts do not support multiple Datacenters in a single inventory"}

#Get Roles
get-virole | ? {$_.issystem -eq $false} | export-clixml $directory\$($datacenter)-roles.xml

#Get Permissions
$allPermissions = @()
$foundPermissions = get-vipermission
$i = 0
foreach ($thisPermission in $foundPermissions)
{
        write-progress -Activity "Getting permissions" -percentComplete ($i / $foundPermissions.count * 100)
        $objPerm = "" | select entity,type,Role,Principal,Propagate,folderType
        $objPerm.type = $thisPermission.entity.id.split("-")[0]
        $objPerm.Role = $thisPermission.role
        $objPerm.Principal = $thisPermission.Principal
        $objPerm.Propagate = $thisPermission.propagate
        #Create an absolute path for a folder, otherwise store the name of the entity
        if ($objPerm.type -eq "Folder")
        {
                $objPerm.entity = get-folderpath $thisPermission.entity
                $objPerm.folderType = $thisPermission.entity.type
        }
        else
        {
                $objPerm.entity = $thisPermission.entity.name
                $objPerm.folderType = ""
        }
        $allPermissions += $objPerm
        $i++
}
$allPermissions | export-clixml $directory\$($datacenter)-permissions.xml


#Get VM Folder Structure
$outFolders = @()
$i = 0
$foundFolders = get-datacenter $datacenter | get-folder | ? {$_.type.tostring() -eq "VM" -and $_.parent.id -notLike "Datacenter*"}
foreach ($thisFolder in $foundFolders)
{
        write-progress -Activity "Getting VM folder structure" -percentComplete ($i / $foundFolders.count * 100)
        $myFolder = "" | select path
        $myFolder.path = get-folderpath $thisFolder
        $outFolders += $myFolder
        $i++
}
$outFolders | export-clixml $directory\$($datacenter)-folders.xml

#Convert Templates to VMs (so that they can transition vCenters)
get-template | select name | export-clixml $directory\$($datacenter)-Templates.xml
if ($getTemplates){get-datacenter $datacenter | get-template | set-template -ToVM -confirm:$false}

#Get VM Locations
$outVMs = @()
$allVApps = get-datacenter $datacenter | get-vapp
$vAppVMs = $allVApps | get-vm
if ($vAppVMs)
{
        $allVMs = Get-VM | ? {!($vAppVMs.contains($_))}
        #Deal with vApps... maybe try this guy's technique to capture settings and make a best effort at recreating the vApp?
        # http://www.lukaslundell.com/2013/06/modifying-vapp-properties-with-powershell-and-powercli/
        $outVApps = @()
        foreach ($thisVApp in $allVApps)
        {
                write-error "Discovered VAPP: $($thisVApp.name) - vAPPs must be recreated manually."
                $myVApp = "" | select name,VMs
                $myVApp.name = $thisVApp.name
                $myVApp.VMs = ($thisVApp | get-vm).name
                $outVApps += $myVApp
        }
        $outVApps | export-clixml $directory\$($datacenter)-vApps.xml
}
else
{
        $allVMs = get-datacenter $datacenter | get-VM
}
$i = 0
foreach ($thisVM in $allVMs)
{
        write-progress -Activity "Getting VM locations" -percentComplete ($i / $allVMs.count * 100)
        $myVM = "" | select name,folderPath
        $myVM.name = $thisVM.name
        if ($thisVM.folder.name -eq "VM")
        {
                $myVM.folderPath = $NULL
        }
        else
        {
                $myVM.folderPath = get-folderpath $thisVM.folder
        }
        $outVMs += $myVM
        $i++
}
$outVMs | export-clixml $directory\$($datacenter)-VMs.xml

Following steps are for the destination vCenter

  • Login to Destination Virtual Center.
  • Open vSphere PowerCLI cmdlet
  • Connect Virtual Center Server using below command.

Connect-VIServer DestinationVCenterName

This is the second part of the process;

Set-SourceConfiguration in Destination vCenter.

 

**On a new connection – logon to new vCenter, input the folders or permissions
 **Set-ExecutionPolicy unrestricted**

copy the script below and save in to a new file as Set-SourceConfiguration.ps1

 

.\Set-SourceConfiguration.ps1 -Folders                                         (If Folders Export/Import is required)

.\Set-SourceConfiguration.ps1 -Permissions                                (If Permissions Export/Import is required)

.\Set-SourceConfiguration.ps1 -Roles                                          (If Roles Export/Import is required)

.\Set-SourceConfiguration.ps1 -VMs                                           (If VMs hierarchy Export/Import is required)


param
(
        $directory = $(read-host "Enter local input directory"),
        $datacenter = $(read-host "Enter datacenter"),
        [switch]$roles,
        [switch]$permissions,
        [switch]$folders,
        [switch]$vms
)

function make-ParentFolder
{
        Param
        (
                $inFolderArray
        )
        $parentFolder = get-datacenter $datacenter | get-folder "VM"
        foreach ($thisSubFolder in $inFolderArray)
        {
                if (!($parentFolder | get-folder $thisSubFolder -noRecursion -erroraction silentlycontinue))
                {
                        $ParentFolder = $parentFolder | new-folder $thisSubFolder
                }
                else
                {
                        $ParentFolder = $ParentFolder | get-folder $thisSubFolder -noRecursion
                }
        }
        $ParentFolder
}

$directory = $directory.trim("\") #" fix the gistit syntax highlighting

#Rebuild Folder Structure
if ($folders)
{
        $folderArray = import-clixml $directory\$($datacenter)-folders.xml
        $i = 0
        foreach ($thisFolder in $folderArray)
        {
                write-progress -Activity "Creating Folders" -percentComplete ($i / $folderArray.count * 100)
                make-ParentFolder -inFolderArray $thisFolder.path
                $i++
        }
}

#Rebuild Roles
if ($roles)
{
        $allRoles = import-clixml $directory\$($datacenter)-roles.xml
        $i = 0
        foreach ($thisRole in $allRoles)
        {
                write-progress -Activity "Creating Roles" -percentComplete ($i / $allRoles.count * 100)
                if (!(get-virole $thisRole.name -erroraction silentlycontinue))
                {
                        new-virole -name $thisRole.name -privilege (get-viprivilege -id $thisRole.PrivilegeList) -erroraction silentlycontinue
                }
                $i++
        }
}

#Rebuild Permissions
if ($permissions)
{
        $allPermissions = import-clixml $directory\$($datacenter)-permissions.xml
        $i = 0
        foreach ($thisPermission in $allPermissions)
        {
                write-progress -Activity "Creating Permissions" -percentComplete ($i / $allPermissions.count * 100)
                $target = ""
                if ($thisPermission.type -eq "Folder")
                {
                        #permission is assigned to a folder, use make-folder to get the precise folder
                        $target = make-Parentfolder -inFolderArray $thisPermission.entity
                }
                elseif ($thisPermission.type -eq "VirtualMachine")
                {
                        #permission is assigned to VM
                        $target = get-datacenter $datacenter | get-vm $thisPermission.entity
                }
                elseif ($thisPermission.type -eq "Datacenter")
                {
                        #permission is assigned to Datacenter
                        $target = get-datacenter $thisPermission.entity
                }
                else
                {
                        write-error "Unexpected permission target, $($thisPermission.type)"
                }
                
                if ($target)
                {
                        $target | new-vipermission -role $thisPermission.role -principal $thisPermission.principal -propagate $thisPermission.propagate
                }
                else
                {
                        write-error "Unable to find permission object $($thisPermission.entity)"
                }
                $i++
        }
}

#Replace VMs
if ($VMs)
{
        $allVMs = import-clixml $directory\$($datacenter)-VMs.xml
        $allVApps = $NULL
        $i = 0
        if (test-path $directory\vApps.xml){$allVApps = import-clixml $directory\$($datacenter)-vApps.xml}
        foreach ($thisVM in $allVMs)
        {
                write-progress -Activity "Placing VMs" -percentComplete ($i / $allVMs.count * 100)
                if ($foundVM = get-vm $thisVM.name)
                {
                        $ParentFolder = make-ParentFolder -inFolderArray $thisVM.folderPath
                        $foundVM | move-vm -destination $ParentFolder   
                }
                $i++
        }
        foreach ($thisVApp in $allVApps)
        {
                echo "===$($thisVApp.name)==="
                $thisvApp.VMs
        }
        #Convert Template VMs back to Templates
}

if (!($VMs -or $folders -or $permissions -or $roles))
{
        echo "Please use one or more of the -VMs, -Folders, -Permissions, or -Roles switches to do something"
}