Get-DeepLtranslation translating straight from your powershell

tt
I was doing my dutch course homework today, and i found it a bit tedious to use browser for translation. This + the fact that i want to write myself some dutch-polish quiz, so i can memorize words better led me to write this tiny function.

The DeepL translator website can be found here https://www.deepl.com/translator

This is a tiny function that would just use the ‘word/1 sentence’ mode. It worked today, not sure if it will be working in later months/years. This was made in really quick/dirty way, as i still need to write my homework today 😉 I wrote it in 15 minutes, so don’t expect fireworks, it does what it does, it translates 😉 You can use different languages using variables fromLang and toLang.

function get-DeepLtranslation ($sentence, $fromLang, $toLang)
{
#Languages available: PL,EN,NL,ES,IT,FR
$url = "https://www.deepl.com/jsonrpc"
$call = '{"jsonrpc":"2.0","method":"LMT_handle_jobs","params":{"jobs":[{"kind":"default","raw_en_sentence":"'+$sentence+'"}],"lang":{"user_preferred_langs":["EN","PL","NL"],"source_lang_user_selected":"'+$fromLang+'","target_lang":"'+$toLang+'"},"priority":-1},"id":15}'
$bytes = [System.Text.Encoding]::ASCII.GetBytes($call)
$web = [System.Net.WebRequest]::Create($url)
$web.Method = "POST"
$web.ContentLength = $bytes.Length
$web.ContentType = "application/x-www-form-urlencoded"
$stream = $web.GetRequestStream()
$stream.Write($bytes,0,$bytes.Length)
$stream.close()
$reader = New-Object System.IO.Streamreader -ArgumentList $web.GetResponse().GetResponseStream()
$answer = ($reader.ReadToEnd()|ConvertFrom-Json).result.translations.beams | select -ExpandProperty 'postprocessed_sentence'
$reader.Close()
return $answer
}

I am not sure why it does not work with the polish single word. IT does translate it though on the website(blue)

2t

When put in sentence that will work.

3t

What i also saw, is that sometimes calls to dict.deepl.com are being made.

I don’t have time right now to dig into this, but for some words you can utilize those:

https://dict.deepl.com/polish-english/search?ajax=1&query=jab%C5%82ko&source=polish&onlyDictEntries=1&translator=dnsof7h3k2lgh3gda&delay=300&jsStatus=0&kind=full&eventkind=keyup&forleftside=true

calls. Behind it’s this :

https://dict.deepl.com/english-polish/search?source=auto&query=%C5%82%C3%B3d%C5%BA

So you can get the translation like this:

(Invoke-WebRequest -Uri ‘https://dict.deepl.com/polish-english/search?ajax=1&query=jab%C5%82ko&source
=polish&onlyDictEntries=1&translator=dnsof7h3k2lgh3gda&delay=300&jsStatus=0&kind=full&eventkind=keyup&forleftside=true’).links[0].outerText
jabłko

That would have to be still converted to proper polish.

I think that something is going wrong when trying to translate words that have polish ‘ogonki’, and char encoding has something to do with it.

Advertisements

Migrating virtual center to another virtual center

!!! WARNING !!!
this is not finished ! DO NOT RUN THIS ON PRODUCTION SYSTEMS !!! UNLESS YOU HAVE TESTED IT IN DEV !!!

Gents, please do not treat this as a ready-to-go solution, you would have to understand the contents, in order how to apply this. Destroying your production is that last thing i want.
I had to write this to recover a VC after a major bug/failure. I had to create another VirtualCenter in order to fix the issue. The main goal of this script is to move ‘everything’ i had in the old virtual center server to the new one.

PLEASE NOTE !!!
DVS is not supported here at this moment

Before you comment this, yes, i know that there are already some software/script for doing this, but in my opinion they were not doing everything or not in the way i wanted to do it. That’s why i created this.
This is not completed ! I have tested it numerous times on dev platforms, for me it was working. The only part which is not here is the cluster configs and dvs. Script will not configure your virtual center, but just the ‘content’ including, folder (of any kind), dc, clusters, vapps. The placements + permissions. The annotations are written in previous posts as well as roles.
I know it’s messy, yes… Although i think i will not spend more time on this, unless i will have to do so. I just hope that it might help for people that had similar task to do, and they were lacking some features in their clone of virtual center.
I DO NOT GUARANTEE THE RESULTS OF THE SCRIPT. Gents, please test this first in your test/dev environments. I have been running this script at least 600-800 times, until i was happy with the outcome, where it worked for me. Please have in mind it will not take into consideration on DVS setup. I’ve come up with 2 solutions for dvs, but never implemented it in it. I have decided to write this on my own mainly to test myself if i am able to do so. There might be better ways of doing it(100% sure of that 😉 ). I have put some comments in the script so you can know what to expect at which moment, the execution of this script is divided in many parts. It’s because i never got to 100% with this script i left myself spots to understand where it can go wrong.
I am sorry in some way that i did not explain this entirely, but i would have spend serious amount of hours on that…
I will have to check if i have posted the role-cloning script on blog, because this is something that is expected to be in place for this to work.

#READ THIS VARIABLE FIRST!!!
#$ProjectNAme

function traverse-HostView3 
{
param(
[Parameter(Mandatory=$true)]$originVC,
[Parameter(Mandatory=$true)]$root,
[Parameter(Mandatory=$true)]$type,
[Parameter(Mandatory=$true)]$destinationroot,
[Parameter(Mandatory=$true)]$destinationVC,
[Parameter(Mandatory=$true)]$DatabaseFile,
[string]$DestMorefDC
)

$permissionFile = $DatabaseFile+'-Permissions.csv'

#the type can be following :
#HostFolder - For the Host/Clusters view
#

#Datacenter Object does not contain ChildEntity property, it is a point where folders are split on
#VmFolder            
#HostFolder          
#DatastoreFolder     
#NetworkFolder       
#Hence when we encounter the datacenter object, we are switching root obj to become a HostFolder of that root/Datacenter

#"function start:: , passed root is now "+$root.name

"my root moref type is now "+$root.moref
"Child entities inside this root are: "+($root.ChildEntity -join ',')
#"Will start now the IF section"

################
################ WHAT TO DO IN ORDER TO GET THE TOP ROOT FOLDER -D1 , to get his permissions, since iteration starts from children ?!?!
################ Make entry at the verybottom for folder -d1 , and just take all settings from it, as 1 -off
if ($root.moref.type -eq 'Datacenter') 
{ 
$root = get-view -id $root.$type -server $originVC
}
if ($root.moref.type -eq 'ClusterComputeResource')
{
#break
#we are 'cheating' here to get the compliance for the ChildEntity. Since Cluster does not have ChildEntity that would describe all its hosts. We are creating a column with ChildEntity that include all hosts
#This will also make a situation that resourcepools will not be checked, since we redirected already path to Hosts, we can also add to Children resource pools later on.
$root =$root | Select *,@{n='ChildEntity';e={$_.Host}}
}

if ($root.moref.type -eq 'VirtualApp')
{
#we are 'cheating' here to get the compliance for the ChildEntity. Since Cluster does not have ChildEntity that would describe all its hosts. We are creating a column with ChildEntity that include all hosts
#This will also make a situation that resourcepools will not be checked, since we redirected already path to Hosts, we can also add to Children resource pools later on.
$root =$root | Select *,@{n='ChildEntity';e={$_.Vm}}
}

#if ($root.moref.type -eq 'Datastore') {break}

#"If section was finished, now we will be collecting children"

if ($root.ChildEntity)
{
    $children = get-view -id $root.ChildEntity -server $originVC
    foreach ($child in $children)
    {
       "!!!!!"+ $child.name + " :: "+ $child.moref
       # Switch [typ]
       switch ($child.moref.type) 
    { 
        'Datacenter' {
        "We hit Datacenter"
        $CreatedObject = Get-view  (get-view -id ($destinationroot.createdatacenter($child.name)) -server $destinationVC).HostFolder -server $destinationVC
        $CreatedDatacenter = get-view -id $CreatedObject.parent -Server $destinationVC 
        #sourcedatacenter = $child
        #Datacenter reference database
        "showing object"
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$child.moref.ToString()}},@{n='DestinationObjectMoref';e={$CreatedDatacenter.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        #$SourceDCPermission = g
        
        #$DCobject = get-view -id $child.parent -Server $originvc
        
        if ($child.Permission){ 
        write-host  "I saw permissions inside the DC object" 
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$CreatedDatacenter.Moref.ToString()}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }

        } 
        'Folder' {
        "We hit folder:"
        $CreatedObject = get-view $destinationroot.createfolder($child.name) -server $destinationVC
        #$CreatedObject = get-view (New-Folder -Server $destinationvc -name $child.name -Location ($destinationroot|Get-VIObjectByVIView)).Extensiondata
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$child.moref.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile        
        #sourceFolderPermissions
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        } 
        'ClusterComputeResource' {
        "We hit cluster"
        $CreatedObject = get-view $destinationroot.createcluster($child.name,(new-object VMware.Vim.ClusterConfigSpec)) -server $destinationVC
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$child.moref.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        #Permissions
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }

        } 
        'VirtualApp' {"We hit VirtualApp"
        #This can only be done, when hosts are attached to cluster.
        #Createvapp is method on default resource pool inside cluster.
        #VMware.Vim.ManagedObjectReference CreateVApp(string name, VMware.Vim.ResourceConfigSpec resSpec, VMware.Vim.VAppConfigSpec configSpec,VMware.Vim.ManagedObjectReference vmFolder)
        $child.vappconfig.EntityConfig | export-clixml -Encoding 'UTF8' -depth 2 -LiteralPath ('c:\'+$child.vappconfig.InstanceUuid+'EntityConfig')
        $child.Config.CpuAllocation | export-clixml -Encoding 'UTF8' -depth 2 -LiteralPath ('c:\'+$child.vappconfig.InstanceUuid+'CpuAllocation')
        $child.Config.MemoryAllocation | export-clixml -Encoding 'UTF8' -depth 2 -LiteralPath ('c:\'+$child.vappconfig.InstanceUuid+'MemoryAllocation')
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$child.moref.ToString()}},@{n='DestinationObjectMoref';e={$destinationroot.Moref.ToString()}},@{n='Objuuid';e={$child.VAppConfig.InstanceUuid}},@{n='DestMorefDC';e={}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={$child.owner.tostring()}}, @{n='vmmoref';e={}}  | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$child.name}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        }
        'HostSystem' {
        "We hit HostSystem"
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$root.moref.ToString()}},@{n='DestinationObjectMoref';e={$destinationroot.Moref.ToString()}},@{n='Objuuid';e={$child.Hardware.systeminfo.uuid}},@{n='DestMorefDC';e={$DestMorefDC}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$child.Hardware.systeminfo.uuid}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        } 
        'VirtualMachine' {
        #FOR VMS YOU HAVE TO SELECT .config.uuid property into the csv, in order to hit the proper vm. ## TODO !!!!!
        "We hit VirtualMachine"
        $vmtxpath=if ($child.config.template){$child.config.files.VmPathName}
        $vmtxHostRegistered = if ($vmtxpath) { (get-view $child.Runtime.Host -property name -Server $originvc).Name }
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$root.moref.ToString()}},@{n='DestinationObjectMoref';e={$destinationroot.Moref.ToString()}},@{n='Objuuid';e={$child.config.uuid}},@{n='DestMorefDC';e={$DestMorefDC}}, @{n='vmtxpath';e={$vmtxpath}}, @{n='vmtxHost';e={$vmtxHostRegistered}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={$child.moref.toString()}} | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile    
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$child.config.uuid}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        } 
        'Datastore' {"
        We hit Datastore"
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$root.moref.ToString()}},@{n='DestinationObjectMoref';e={$destinationroot.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={$DestMorefDC}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$child.name}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        }
        'StoragePod' {"
        We hit StoragePod"
        $CreatedObject = get-view $destinationroot.createstoragepod($child.name) -server $destinationVC
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$child.moref.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        }
        #The ComputeResource if for a single Host inside a folder for example
        #'ComputeResource' {"
        #We hit StoragePod"
        #$CreatedObject = get-view $destinationroot.createstoragepod($child.name) -server $destinationVC
        #'' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$child.moref.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={}} | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        #if ($child.permission){  
        #$child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$CreatedObject.Moref.ToString()}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        #}
        #}
        'Network' {
        "We hit network"
        '' | Select-object @{n='ObjectName';e={$child.name}},@{n='OriginObjectMoref';e={$root.moref.ToString()}},@{n='DestinationObjectMoref';e={$destinationroot.Moref.ToString()}},@{n='Objuuid';e={}},@{n='DestMorefDC';e={$DestMorefDC}},@{n='vmtxpath';e={}}, @{n='vmtxHost';e={}}, @{n='OwnerMoref';e={}}, @{n='vmmoref';e={}}   | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $DatabaseFile
        if ($child.permission){  
        $child.Permission | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$child.name}},@{n='DestMorefDC';e={$DestMorefDC}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $permissionFile
        }
        }  
        default {"The object could not be determined : please check";read-host}
    }
       traverse-HostView3 -root $child -type $type -originVC $originVC -destinationVC $destinationVC -destinationroot $CreatedObject -DatabaseFile 'c:\databasefile.csv' -DestMorefDC $DestMorefDC
       
    }
}

}



$originvc = 'your.original.vc'
$destinationVC = 'your.new.vc'
connect-viserver $originVC -Credential (Get-credential)
connect-viserver $destinationVC -credential (get-credential)
$pscred = Get-Credential

$rootFolder = get-view -id ($global:DefaultVIServers |? {$_.name -eq $originvc}).extensiondata.content.rootfolder -Server $originvc
$destinationroot = get-view -id ($global:DefaultVIServers |? {$_.name -eq $destinationvc}).extensiondata.content.rootfolder -Server $destinationvc

traverse-HostView3 -root $rootFolder -type 'HostFolder' -originVC $originVC -destinationVC $destinationVC -destinationroot $destinationroot -DatabaseFile 'c:\databasefile.csv'



##You start first by running through Host and Clusters View, since you have to recreate the entire main structure for datacenters.
##Remember that after each run , in case you went into trouble to clear the database file, or you different file.
##
##
##Tutaj podajemy root folder w source VC, jako folder do konkretnego DC.networkFolder , tak samo w destination , nakladamy folder dc.networkfolder
#NETWORK FOLDERS:
foreach($dc in (import-csv 'c:\databasefile.csv' -Encoding 'UTF8' |? {$_.OriginObjectMoref -like "Datacenter-*"})  )
{
traverse-HostView3 -root (get-view (get-view $dc.OriginObjectMoref -server $originVC).NetworkFolder -Server $originVC) -type 'NetworkFolder' -originVC $originVC -destinationVC $destinationVC -destinationroot (get-view (get-view $dc.DestinationObjectMoref -server $destinationVC).NetworkFolder -Server $destinationVC) -DatabaseFile 'c:\databasefile.csv' -DestMorefDC ($dc.DestinationObjectMoref) 
}

#VM FOLDERS:


foreach($dc in (import-csv 'c:\databasefile.csv' -Encoding 'UTF8' |? {$_.OriginObjectMoref -like "Datacenter-*"})  )
{
traverse-HostView3 -root (get-view (get-view $dc.OriginObjectMoref -server $originVC).VmFolder -Server $originVC) -type 'VmFolder' -originVC $originVC -destinationVC $destinationVC -destinationroot (get-view (get-view $dc.DestinationObjectMoref -server $destinationVC).VmFolder -Server $destinationVC) -DatabaseFile 'c:\databasefile.csv' -DestMorefDC ($dc.DestinationObjectMoref) 
}

#Storage FOLDERS:
foreach($dc in (import-csv 'c:\databasefile.csv' -Encoding 'UTF8' |? {$_.OriginObjectMoref -like "Datacenter-*"})  )
{
traverse-HostView3 -root (get-view (get-view $dc.OriginObjectMoref -server $originVC).DatastoreFolder -Server $originVC) -type 'DatastoreFolder' -originVC $originVC -destinationVC $destinationVC -destinationroot (get-view (get-view $dc.DestinationObjectMoref -server $destinationVC).DatastoreFolder -Server $destinationVC) -DatabaseFile 'c:\databasefile.csv' -DestMorefDC ($dc.DestinationObjectMoref) 
}

###
###  COPY ROOT VC PERMISSION HERE
### 
### THIS PART IS ONLY IF YOUR LOCAL SSO DOMAIN CHANGES, MODIFY THIS IF IT IS THE SAME
$sourceSSODomain = 'VSPHERE.LOCAL'
$destinationSSODomain = 'TEST.LOCAL'

$tpermissionFile = 'databasefile.csv-Permissions.csv'
$VCSourceRootPermissions = (get-view -id 'Folder-group-d1' -server $originvc).permission |?{$_.Principal -notmatch "vpxd-|vsphere-webclient-"} 
#IF you don't want to change the local sso domain , hash the line below:
$VCSourceRootPermissions|? {$_.principal -match $sourceSSODomain} | %{$_.principal = [regex]::replace($_.Principal,$sourceSSODomain,$destinationSSODomain)}

$VCSourceRootPermissions | select @{n='OriginObjectMoref';e={$_.Entity.ToString()}},@{n='DestinationObjectMoref';e={$_.Entity.ToString()}}, Principal,RoleId,Propagate,Group | Export-Csv -NoTypeInformation -Append -Encoding 'UTF8' -LiteralPath $tpermissionFile


##
## END OF THE COPY OF VC PERMISSION
##



##
##Before replaying permissions you have to be sure that the SSO domain is the same for permissions, therefore we will replace old SSO domain with new SSO domain.
##
$RoleDB = Import-Csv -Encoding UTF8 -LiteralPath 'C:\RoleDB.csv'
$sourceSSODomain = (Get-AdvancedSetting -Entity ($global:DefaultVIServers|?{$_.Name -eq $originvc}) -Name 'config.vpxd.sso.default.admin').value.split('@')[1].ToUpper()
$destinationSSODomain = (Get-AdvancedSetting -Entity ($global:DefaultVIServers|?{$_.Name -eq $destinationvc}) -Name 'config.vpxd.sso.default.admin').value.split('@')[1].ToUpper()
$tpermissionFile = 'c:\databasefile.csv-Permissions.csv'
$permissions = import-csv -Encoding UTF8 -LiteralPath $tpermissionFile 
$permissions |% { $_.principal = [regex]::replace($_.Principal,$sourceSSODomain,$destinationSSODomain)  }
$permissions | export-csv -Encoding UTF8 -LiteralPath $tpermissionFile -NoTypeInformation

##
## REPLAY PERMISSIONS
##
$RoleDB = Import-Csv -Encoding UTF8 -LiteralPath 'C:\RoleDB.csv'
#$rolehash = @{}
#$roleDB | % { $roleHash += @{$_.SourceRoleId = get-virole -id $_.DestinationRoleID -Server $destinationVC}  }
#RoleHash is now [ID_SOURCE_ROLE]  || [ROLE_OBJECT_ON_DESTINATION]
#OriginObjectMoref      : Folder-group-v450
#DestinationObjectMoref : Folder-group-v972
#DestMorefDC            : Datacenter-datacenter-953
#Principal              : VSPHERE.LOCAL\greg
#RoleId                 : -1
#Propagate              : True
## FOLDERS DCs
## FOLDERS Hs
#### We Will need authorizationmanager from the destination VC now. method SetEntityPermissions         Method     void SetEntityPermissions(VMware.Vim.ManagedObjectReference entity, VMware.Vim.Permission[] permission)
##Entity     :
#Principal  :
#Group      : False
#RoleId     : 0
#Propagate  : False
##
##


$DestAM = get-view -id ($global:DefaultVIServers|?{$_.Name -eq $destinationvc}).extensiondata.content.AuthorizationManager -Server $DestinationVC

##
## HOSTS VIEW FOLDERS
##
Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "Folder-group-h*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}

##
## DATACENTERS NOW
##

Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "Datacenter-datacenter-*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)  
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}

##
## CLUSTERS NOW
##

Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "ClusterComputeResource-domain-c*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)  
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}

##
## NETWORK VIEW FOLDERS
##
Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "Folder-group-n*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}

##
## VM VIEW FOLDERS
##
Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "Folder-group-v*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}

##
## STORAGE FOLDERS VIEW FOLDERS
##
Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "Folder-group-s*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}

##
## STORAGE PODS VIEW FOLDERS
##
Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "StoragePod-group-p*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
$DestAM.SetEntityPermissions($entity.DestinationObjectMoref, $DestinationObjectPermission)
}


#Adding Hosts to cluster
Foreach ($cluster in ((import-csv -LiteralPath 'c:\databasefile.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "ClusterComputeResource-domain-c*"}) |?{$_.Objuuid} | Group-Object -Property destinationObjectMoref).group) 
{ 
$VMhostsInCluster = $cluster
$Clusterdestination = $VMhostsInCluster[0].DestinationObjectMoref
$location = get-view -id  $Clusterdestination -server $destinationVC| Get-VIObjectByVIView
foreach ($vmhost in $VMhostsInCluster) 
{
 Add-VMHost -Name $vmhost.ObjectName -Location $location -Credential $pscred -Force -Server $destinationVC
 }

}
#make sure that all pwd are the same

##
##Once all hosts are in place in the VC , we attach our templates
##
foreach ($vmtemplate in  (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.OriginObjectMoref -like "Folder-group-v*" -and $_.vmtxpath})){
$location = get-view -id $vmtemplate.DestinationObjectMoref -server $destinationVC | Get-VIObjectByVIView
New-Template -Name $vmtemplate.ObjectName -TemplateFilePath $vmtemplate.vmtxpath -Location $location -vmhost $vmtemplate.vmtxHost
}


##
## VMHOSTS PERMISSIONS
##
Foreach ($entity in (import-csv -LiteralPath 'c:\databasefile.csv-permissions.csv' -Encoding UTF8 | ?{$_.OriginObjectMoref -like "HostSystem-host-*"})){
$DestinationObjectPermission = New-Object VMware.vim.Permission
$DestinationObjectPermission.Principal = $entity.Principal
$DestinationObjectPermission.Group = [System.Convert]::ToBoolean($entity.Group)
$DestinationObjectPermission.RoleId = ($roleDB|?{$_.SourceRoleId -eq ($entity.RoleId)}).DestinationRoleId
$DestinationObjectPermission.Propagate = [System.Convert]::ToBoolean($entity.Propagate)
$DestinationObjectPermission
#Here our destinationObjectMoref is actually vm host uuid value , not moref. We couldn't have moref as it was unknown.
$DestinationVMHost = get-view -ViewType HostSystem -Filter @{'Hardware.SystemInfo.Uuid'=$entity.DestinationObjectMoref} -Property Name -Server $destinationVC
#$destinationVMHost
$DestAM.SetEntityPermissions($DestinationVMHost.moref, $DestinationObjectPermission)
}



##
## Moving object to their correct location
##
##
## NETWORK VIEW ENTITIES
##!!!!!!!!!!!!!!!!!!!!!!!!!! We should move only those which are not located at the datacenter, otherwise , waste of time.
$DCnetworkFolderIDs = @((get-view -id ((import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.OriginObjectMoref -like "Folder-group-n*" -and $_.DestMorefDC -like "Datacenter-datacenter-*"}) |group-object -Property DestMorefDC).Name -Server $destinationVC).NetworkFolder |% {$_.ToString()})
$allNetworksInFolders = (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.OriginObjectMoref -like "Folder-group-n*" -and $_.DestMorefDC -like "Datacenter-datacenter-*"}) | ? {$DCnetworkFolderIDs -notcontains $_.DestinationObjectMoref}
Foreach ($entity in $allNetworksInFolders){
#DestinationObjectMoref : Folder-group-n1575
$dof = get-view -id $entity.DestinationObjectMoref -server $destinationVC
$ntwkmoref = (get-view -server $destinationVC -searchroot $entity.DestMorefDC -viewtype 'Network' -filter @{'name'=$entity.ObjectName}).moref
$dof.MoveIntoFolder($ntwkmoref)
}

## VM VIEW ENTITIES
##!!!!!!!!!!!!!!!!!!!!!!!!!! We should move only those which are not located at the datacenter, otherwise , waste of time.
Foreach ($entity in (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.OriginObjectMoref -like "Folder-group-v*" -and $_.DestMorefDC -like "Datacenter-datacenter-*"})){
#DestinationObjectMoref : Folder-group-n1575
'Object'
$entity

$dof = get-view -id $entity.DestinationObjectMoref -server $destinationVC
'Destination'
$dof.name
$vmmoref = (get-view -server $destinationVC -searchroot $entity.DestMorefDC -viewtype 'Virtualmachine' -filter @{'Config.Uuid'=$entity.Objuuid}).moref
'VM Object'
$vmmoref
$dof.MoveIntoFolder($vmmoref)
}

##
## Creating Vapps, moving VMs into Vapps, Applying Vapp start order
##
Foreach ($entity in (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.OriginObjectMoref -like "VirtualApp-resgroup-v*" -and $_.OwnerMoref})){
#entity is now
#ObjectName             : LABS_Greg
#OriginObjectMoref      : VirtualApp-resgroup-v241
#DestinationObjectMoref : Folder-group-v4284
#Objuuid                : 5038914a-df12-abcc-77aa-2d2991ccaa2e
#DestMorefDC            :
#vmtxpath               :
#vmtxHost               :
#OwnerMoref             : ClusterComputeResource-domain-c7

#First we prepare the configs for our Vapp entity
$EntityMemoryAllocationXML = Import-Clixml -LiteralPath ('C:\'+$entity.Objuuid+'MemoryAllocation')
$EntityCpuAllocationXML = Import-Clixml -LiteralPath ('C:\'+$entity.Objuuid+'CpuAllocation')
$EntityConfig = Import-Clixml -LiteralPath ('C:\'+$entity.Objuuid+'EntityConfig')
$resSpec = New-Object VMware.Vim.ResourceConfigSpec
$resSpec.cpuAllocation = New-Object VMware.Vim.ResourceAllocationInfo
$resSpec.cpuAllocation.reservation = $EntityCpuAllocationXML.Reservation
$resSpec.cpuAllocation.expandableReservation = $EntityCpuAllocationXML.expandableReservation
$resSpec.cpuAllocation.limit = $EntityCpuAllocationXML.limit
$resSpec.cpuAllocation.shares = New-Object VMware.Vim.SharesInfo
$resSpec.cpuAllocation.shares.shares = $EntityCpuAllocationXML.shares.shares
$resSpec.cpuAllocation.shares.level = $EntityCpuAllocationXML.shares.level
$resSpec.memoryAllocation = New-Object VMware.Vim.ResourceAllocationInfo
$resSpec.memoryAllocation.reservation = $EntityMemoryAllocationXML.Reservation
$resSpec.memoryAllocation.expandableReservation = $EntityMemoryAllocationXML.expandableReservation
$resSpec.memoryAllocation.limit = $EntityMemoryAllocationXML.limit
$resSpec.memoryAllocation.shares = New-Object VMware.Vim.SharesInfo
$resSpec.memoryAllocation.shares.shares = $EntityMemoryAllocationXML.shares.shares
$resSpec.memoryAllocation.shares.level = $EntityMemoryAllocationXML.shares.level

$configSpec = New-Object VMware.Vim.VAppConfigSpec
$configSpec.InstanceUuid = $entity.Objuuid
$vmFolder = $Entity.DestinationObjectMoref


#(import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8| ?{$_.OriginObjectMoref -eq $data.OwnerMoref -and !$_.Objuuid})
#$ClusterResourcePool = (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8| ?{$_.OriginObjectMoref -eq $data.Objuuid -and !$_.Objuuid}).DestinationObjectMoref

$ClusterResourcePool = get-view -id (get-view -id (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8| ?{$_.OriginObjectMoref -eq $entity.OwnerMoref -and !$_.Objuuid}).DestinationObjectMoref -server $destinationVC).ResourcePool -Server $destinationVC

$CreatedVapp = get-view -id  $ClusterResourcePool.CreateVApp($entity.ObjectName, $resSpec, $configSpec, $vmFolder) -Server $destinationVC

if ( $CreatedVapp.vappconfig.InstanceUuid -ne $entity.Objuuid ) { Write-Error "We have failed to created vapp with the same uuid"}

#Moving vms into the vAPP
$VMsOldMorefs = $EntityConfig.Key|%{$_.toString()}
$OldVMs = import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? { $VMsOldMorefs -contains $_.vmmoref }
$newVMs = $oldVMs.Objuuid | % {get-view -viewtype virtualmachine -Filter @{'config.uuid'=$_} -Server $destinationVC}
$createdvapp.MoveIntoResourcePool($newVMs.moref)
#Let's make proper order in vapp

foreach ($entry in $EntityConfig)
{
$oldkey = (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.vmmoref -eq $entry.Key.ToString() }).Objuuid
$newkey = (get-view -viewtype virtualmachine -Filter @{'config.uuid'=$oldkey} -Server $destinationVC).moref
$entry.key=$newkey

}

$newconfig = new-object VMware.Vim.VAppConfigSpec
foreach ($entry in $EntityConfig)
{

$newEntityconfig =  new-object VMware.Vim.VAppEntityConfigInfo
$newEntityconfig.Key = $entry.key
$newEntityconfig.Tag = $entry.tag
$newEntityconfig.StartOrder = $entry.StartOrder
$newEntityconfig.StartDelay = $entry.StartDelay
$newEntityconfig.WaitingForGuest = $entry.WaitingForGuest
$newEntityconfig.StartAction = $entry.StartAction
$newEntityconfig.StopDelay = $entry.StopDelay
$newEntityconfig.StopAction = $entry.StopAction
$newEntityconfig.DestroyWithParent = $entry.DestroyWithParent

$newConfig.EntityConfig += $newEntityconfig

}

$CreatedVapp.UpdateVAppConfig($newConfig)
}
#we have now updated entityconfig

For the vapps part :

Foreach ($entity in (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.OriginObjectMoref -like "VirtualApp-resgroup-v*" -and $_.OwnerMoref})){
#entity is now
#ObjectName             : LABS_Greg
#OriginObjectMoref      : VirtualApp-resgroup-v241
#DestinationObjectMoref : Folder-group-v4284
#Objuuid                : 5038914a-df12-abcc-77aa-2d2991ccaa2e
#DestMorefDC            :
#vmtxpath               :
#vmtxHost               :
#OwnerMoref             : ClusterComputeResource-domain-c7

#First we prepare the configs for our Vapp entity
$EntityMemoryAllocationXML = Import-Clixml -LiteralPath ('C:\'+$data.Objuuid+'MemoryAllocation')
$EntityCpuAllocationXML = Import-Clixml -LiteralPath ('C:\'+$data.Objuuid+'CpuAllocation')
$EntityConfig = Import-Clixml -LiteralPath ('C:\'+$data.Objuuid+'EntityConfig')
$resSpec = New-Object VMware.Vim.ResourceConfigSpec
$resSpec.cpuAllocation = New-Object VMware.Vim.ResourceAllocationInfo
$resSpec.cpuAllocation.reservation = $EntityCpuAllocationXML.Reservation
$resSpec.cpuAllocation.expandableReservation = $EntityCpuAllocationXML.expandableReservation
$resSpec.cpuAllocation.limit = $EntityCpuAllocationXML.limit
$resSpec.cpuAllocation.shares = New-Object VMware.Vim.SharesInfo
$resSpec.cpuAllocation.shares.shares = $EntityCpuAllocationXML.shares.shares
$resSpec.cpuAllocation.shares.level = $EntityCpuAllocationXML.shares.level
$resSpec.memoryAllocation = New-Object VMware.Vim.ResourceAllocationInfo
$resSpec.memoryAllocation.reservation = $EntityMemoryAllocationXML.Reservation
$resSpec.memoryAllocation.expandableReservation = $EntityMemoryAllocationXML.expandableReservation
$resSpec.memoryAllocation.limit = $EntityMemoryAllocationXML.limit
$resSpec.memoryAllocation.shares = New-Object VMware.Vim.SharesInfo
$resSpec.memoryAllocation.shares.shares = $EntityMemoryAllocationXML.shares.shares
$resSpec.memoryAllocation.shares.level = $EntityMemoryAllocationXML.shares.level

$configSpec = New-Object VMware.Vim.VAppConfigSpec
$configSpec.InstanceUuid = $entity.Objuuid
$vmFolder = $Entity.DestinationObjectMoref


#(import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8| ?{$_.OriginObjectMoref -eq $data.OwnerMoref -and !$_.Objuuid})
#$ClusterResourcePool = (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8| ?{$_.OriginObjectMoref -eq $data.Objuuid -and !$_.Objuuid}).DestinationObjectMoref

$ClusterResourcePool = get-view -id (get-view -id (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8| ?{$_.OriginObjectMoref -eq $data.OwnerMoref -and !$_.Objuuid}).DestinationObjectMoref -server $destinationVC).ResourcePool -Server $destinationVC

$CreatedVapp = get-view -id  $ClusterResourcePool.CreateVApp($data.ObjectName, $resSpec, $configSpec, $vmFolder) -Server $destinationVC

if ( $CreatedVapp.vappconfig.InstanceUuid -ne $entity.Objuuid ) { Write-Error "We have failed to created vapp with the same uuid"}

#Moving vms into the vAPP
$VMsOldMorefs = $EntityConfig.Key|%{$_.toString()}
$OldVMs = import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? { $VMsOldMorefs -contains $_.vmmoref }
$newVMs = $oldVMs.Objuuid | % {get-view -viewtype virtualmachine -Filter @{'config.uuid'=$_} -Server $destinationVC}
$createdvapp.MoveIntoResourcePool($newVMs.moref)
#Let's make proper order in vapp

foreach ($entry in $EntityConfig)
{
$oldkey = (import-csv -LiteralPath C:\databasefile.csv -Encoding UTF8 | ? {$_.vmmoref -eq $entry.Key.ToString() }).Objuuid
$newkey = (get-view -viewtype virtualmachine -Filter @{'config.uuid'=$oldkey} -Server $destinationVC).moref
$entry.key=$newkey

}

$newconfig = new-object VMware.Vim.VAppConfigSpec
foreach ($entry in $EntityConfig)
{

$newEntityconfig =  new-object VMware.Vim.VAppEntityConfigInfo
$newEntityconfig.Key = $entry.key
$newEntityconfig.Tag = $entry.tag
$newEntityconfig.StartOrder = $entry.StartOrder
$newEntityconfig.StartDelay = $entry.StartDelay
$newEntityconfig.WaitingForGuest = $entry.WaitingForGuest
$newEntityconfig.StartAction = $entry.StartAction
$newEntityconfig.StopDelay = $entry.StopDelay
$newEntityconfig.StopAction = $entry.StopAction
$newEntityconfig.DestroyWithParent = $entry.DestroyWithParent

$newConfig.EntityConfig += $newEntityconfig

}

$CreatedVapp.UpdateVAppConfig($newConfig)
}
#we have now updated entityconfig

Clone-CustomAttributes using PowerCLI

There is nothing to explain i guess in this function. Just copies the definitions of custom attributes between 2 virtual center servers. It expects that you are connected to both virtual centers.

Function Clone-CustomAttributes 
{
<#
    .SYNOPSIS
        Copies custrom attributes used for annotations , just the definitions.
  
    .DESCRIPTION
        Copies custrom attributes used for annotations , just the definitions.
  
    .PARAMETER  sourceVC
        Specify the Virtual Center from which it will download the custom attributes.

    .PARAMETER  destinationVC
        Specify the Virtual Center to which it will apply the custom attribues.
          
    .PARAMETER  TargeType
        Specify for which kind of attributes this list will be generated: VirtualMachine,ResourcePool, 
        Folder,VMHost,Cluster,Datacenter. Global is not included in this version.

    .EXAMPLE
        PS C:\> Clone-CustomAttributes -sourceVC 'VC01.biz' -destinationVC 'vc02.biz' -TargetType 'VirtualMachine'
        Will create the custom attribute definitions for type VirtualMachine which belong to VC01 on VC02.

    .NOTES
        NAME:  Export-CustomAttributes
          
        AUTHOR: Grzegorz Kulikowski
          
        NOT WORKING ? #powercli @ irc.freenode.net 
          
    .LINK
  
https://psvmware.wordpress.com
  
#>
param(
[Parameter(Mandatory=$true)]$sourceVC, 
[Parameter(Mandatory=$true)]$destinationVC, 
[Parameter(Mandatory=$true)][VMware.VimAutomation.ViCore.Types.V1.AnnotationManagement.CustomAttributeTargetType]$targetType

) 
    $SourceCustomAttr = @{}
    #I have special filter not to much some names, as i do not wan't them on my new VC Instance.
    Get-CustomAttribute -Server $sourceVC -TargetType $targetType  | ? {$_.Name -notmatch "PnC|vrm|FA.|Xd"} | % { $SourceCustomAttr+=@{$_.Key=$_.Name}}
    Foreach ($CustomAttribute in $SourceCustomAttr.GetEnumerator()) 
    {
        New-CustomAttribute -Name $CustomAttribute.Value -TargetType $targetType -Server $destinationVC
    }
}

Export-CustomAttributes using PowerCLI

Ok , exporting values of custom attributes , in other words our custom annotations for vms.
When running with specific -Attribute parameter :

When running without the -Attribute parameter it will grab all annotations for the specific target type (VirtualMachine,ResourcePool, Folder,VMHost,Cluster,Datacenter).

I have not implemented the ‘global’ target type here. Might be the case that i will do it later on.
The idea behind is to save the report to a file , and then with the import function , apply to vms that were imported to the new VC.

Function Export-CustomAttributes
{
<#
    .SYNOPSIS
        Returns VM report with custom attributes for vms that have currently custom attributes applied.
  
    .DESCRIPTION
        Returns VM report with custom attributes for vms that have currently custom attributes applied.
        Can be ran with the -Attribute parameter to specify which exactly attributes should be recorded.
        Cmdlet expects that we are already connected to a specified virtual center system. The sourceVC
        parameter is needed to distinguish between VC if you are connected to more than 1 VC. It also 
        used as the identificator of VC connection if you are connected to a single VC instance.
  
    .PARAMETER  sourceVC
        Specify the Virtual Center from which it will download the report.
          
    .PARAMETER  TargeType
        Specify for which kind of attributes this list will be generated: VirtualMachine,ResourcePool, 
        Folder,VMHost,Cluster,Datacenter. Global is not included in this version.

    .PARAMETER  Attribute
        Specify for which attributes this list will be generated, you can check which one you have by 
        running get-customattributes cmdlet. Attributes inside the specific TargetType only.
 
    .EXAMPLE
        PS C:\> $CA = Export-CustomAttributes -sourceVC 'VC004.domain.biz' -targetType 'virtualmachine' -Attribute 'ApplicationOwner','Function'
        Will get 2 custom attribute for all virtualmachine that have currently customattributes

    .EXAMPLE
        PS C:\> $CA = Export-CustomAttributes -sourceVC 'VC004.domain.biz' -targetType 'virtualmachine'
        Will get all custom attributes from virtualmachine type for all virtualmachine that have currently customattributes
         

    .NOTES
        NAME:  Export-CustomAttributes
          
        AUTHOR: Grzegorz Kulikowski
          
        NOT WORKING ? #powercli @ irc.freenode.net 
          
    .LINK
  
https://psvmware.wordpress.com
  
#>
param(
[Parameter(Mandatory=$true)][string]$sourceVC, 
[Parameter(Mandatory=$true)][VMware.VimAutomation.ViCore.Types.V1.AnnotationManagement.CustomAttributeTargetType]$targetType, 
[string[]]$Attribute
)
#▅▇█▓▒░Don't forget to implement the global option as per :http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc/vim.CustomFieldsManager.FieldDef.html
#▅▇█▓▒░Right now the $targetType can't be null, so we can't take 'globals' , globals are the ones which are empty.
    
    $SourceCustomAttr = @{}
    if ($Attribute) 
    {
        Get-CustomAttribute -Server $sourceVC -TargetType $targetType -Name $Attribute | % { $SourceCustomAttr+=@{$_.Key=$_.Name}}
    } else 
        {
            #This is custom to the environment, depending on which plugins you were installing to your VC, you might have different special attributes, which might not be needed on the other side.
            Get-CustomAttribute -Server $sourceVC -TargetType $targetType  | ? {$_.Name -notmatch "PnC|vrm|FA.|Xd"} | % { $SourceCustomAttr+=@{$_.Key=$_.Name}}
        }
    #get only those that have custom attributes     
    $SourceVms = Get-View -ViewType virtualmachine -Property 'CustomValue','Name' -Server $sourceVC | ?{$_.customvalue}
    $ReportSourceVms = $SourceVms | Select Moref,Name,CustomValue
    
    Foreach ($VM in $ReportSourceVms) 
    {
        foreach ($CustomAttribute in $SourceCustomAttr.GetEnumerator()) 
        {
            Add-Member -InputObject $VM -MemberType NoteProperty -Name $CustomAttribute.Value -Value ($VM.CustomValue|?{$_.Key -eq $CustomAttribute.Name}).value
        }
    }
    return $ReportSourceVms | Select-Object * -ExcludeProperty CustomValue
} 

Get-VMHostTimeReport Reporting time from vmhost system

I wanted to check if all of my vmhost system are keeping time with ntp. I wrote recently how to query time from vmhost system using esxcli. Today i want to show how to do this without esxcli, and also produce nice report and a summary which will help investigate issue with host time. I am comparing host time with local time o/s that is converted to UTC. If you are not sure whether your time is accurate then it might be a problem. Solution for this is to query remote utc time. In internet you can find sites that offer time web services that can be easily integrated to this script.
Have in mind that property DiffToUTC is in seconds.
I have tried to optimize this report as much as i can. It was possible to execute this report in 1 minute and 8 seconds. But it was not that readable and did not contain all of this information. On 100 vmhost+ it should fit in 1 – 2 minutes. Before i had approach with obtaining time using esxcli, but that was slower then this approach.
If you know how to query it faster, post a comment. Have in mind that this function is not perfect. I believe that there are better ways to show weather vmhost system is out of time or not. Anyway, this function helps a lot in diagnosing problems time on esx/esxi host systems.
It will state if ntpd is running or not, or for example if you have >100 host you can spot a pattern for ntp servers. Sometimes it is easy to overlook something, for example ntp servers:
172.16.x.y
72.16.x.y
Where you can easily see that you had a typo.
Sometimes you are just not aware that ntp service is running.
Or sometimes… 😉
Few screenshots from running this function:
From this screenshot where the report was stored in $myreport, we can see that we have some issues with host time, as there is a difference of 76 second compared to my local os time.
srh2
If you see DiffToUTC like 0.0xxxxx that would mean that you are ok. If you get readings > 1 seconds that could indicate something is wrong.
We can also do report for a single vmhost system.
srh1
We can do a full report and using the -summary switch, make function to return some description about the report.
trsum
Documentation for
HostDateTimeSystem -> Managed Object – HostDateTimeSystem
HostServiceSystem -> Managed Object – HostServiceSystem
I have added now option to check your local time which will be converted to UTC and compare it to UTC time taken from internet. Internet connection should be in place in order to use it. That was added if you suspect that your local time might not be correct and you would like to check it with other source. Please also read disclaimer,usage restrictions before using this time web service. So if you spot that your time differs to much from time taken from that ‘internet returned time’, it might indicate some issues, maybe the web service has issues, or our system.
Function below:

function Get-VMHostTimeReport {
<#
	.SYNOPSIS
		Gets time from VM Hosts and checks with local time(to utc).

	.DESCRIPTION
		This function might help investigating issues with vm host time. If it is running without any
		parameter it checks time for all hosts registered in virtual center to which user is currently
		connected. Using parameter SingleVMHost will produce report for single vm host system.
		VMHost should be the name of the host, string.
		Report returns colums : Name (vmhost system name), VMHostTime (Time from vmhost),
		UTCTime (this is the utc time from our local os), NTPServers ( if any are in the vmhost
		configuration), NTPServiceRunning (checks if the ntp service is running on the vmhost),
		DiffToUTC (that's the difference in seconds between time reported by vmhost and our os)
		By default it sorts report by from lowest to highest time difference reported.
		

	.PARAMETER  SingleVMHost
		Specify single vmhost name that is registered in VC. This should be a string.
		
	.PARAMETER  Summary
		Indicate if you would like to receive short summary about produced report.

	.PARAMETER  CheckTimeFromInternet
		Indicate if you would like to see in summary information about your local time and remote 
		time. Time from remote web service will be checked and comapred to your system utc time.

	.EXAMPLE
		PS C:\> Get-VMHostTimeReport
		Will produce report for all vmhosts that are registered within VirtualCenter to which user
		is currently connected. It is possible to close the report into a variable for example:
		$timereport=Get-VMHostTimeReport
		You can then export this report to csv if needed for example, or view it again :
		$timereport | format-table -autosize
		For viewing convenience
		
		
	.EXAMPLE
		PS C:\> Get-VMHostTimeReport -SingleVMHost 'myesxhost.local.lan'
		Will produce report for given vmhost that is registered within VirtualCenter to which user
		is currently connected.
		

	.EXAMPLE
		PS C:\> Get-VMHostTimeReport -Summary
		Will produce report . and show a small summary which might indicate if there is a problem
		with time sync on vmhost systems. Example of the summary below:
		UTC time from the current system :Min and Max times during reporting period
		Min: 9/3/2013 4:17:38 PM
		Max: 9/3/2013 4:19:20 PM
		While function was creating this report, first date that was returned by local os was the Min
		and the last date that was returned by local os was the Max value.
		VMHosts reported Times :Min and Max date / time while creating report
		Min: 9/3/2013 4:16:35 PM
		Max: 9/3/2013 4:19:20 PM
		Our vmhost systems reported their date/time. If this time span is too big, this might indicate 
		issues with vmhost ntp sync.
		Time Difference between VMHost and UTC from local os time Min, Max, Avg
		Min: 0.03075
		Max: 76.20985
		Avg: 1.36604993421053
		This is summary for comparing UTC vm host time to UTC time from local os. If you see 
		big Max value >1/2 sec that it might indicate that there is an issue with vmhost ntp time sync
		If a switch parameter CheckTimeFromInternet is present in the summary section there will
		be small report generated about your local time converted to UTC and time taken from
		http://www.earthtools.org
		You can then quickly see if there is an issue with your local time

	.NOTES
		NAME:  Get-VMHostTimeReport
		
		AUTHOR: Grzegorz Kulikowski
		
		NOT WORKING ? #powercli @ irc.freenode.net 
		
		THANKS: http://www.earthtools.org

	.LINK

https://psvmware.wordpress.com

#>

   param(
   [string]$SingleVMHost,
   [switch]$Summary,
   [switch]$CheckTimeFromInternet
   )
$TimeReport=@()
if ($SingleVMHost) { $VMHosts=Get-View -ViewType HostSystem -Filter @{'name'=$SingleVMHost} }
else{
$VMHosts=get-view -viewtype hostsystem -property name,ConfigManager.DateTimeSystem,ConfigManager.ServiceSystem -Filter @{'runtime.ConnectionState'='connected'}
}
Foreach($VMHost in $VMHosts){
$VMHostDateTimeSystem=get-view -id $VMHost.ConfigManager.DateTimeSystem
$VMHostServiceSystem=get-view -id $VMHost.ConfigManager.ServiceSystem
$VMHostTime=$VMHostDateTimeSystem.QueryDateTime()
$NtpServiceState=($VMHostServiceSystem.ServiceInfo.Service|Where-Object {$_.Key -eq 'ntpd'}).Running
$NtpServers=$VMHostDateTimeSystem.DateTimeInfo.NtpConfig.Server
$UTCTime=(Get-Date).ToUniversalTime() 
$TimeReport+=$vmhost| Select-Object -Property Name, @{n='VMHostTime';e={$VMHostTime}},@{n='UTCTime';e={$UTCTime}},@{n='NTPServers';e={$NtpServers}},@{n='NTPServiceRunning';e={$NtpServiceState}},@{n='DiffToUTC';e={[Math]::Round([math]::abs(($VMHostTime - $UTCTime).TotalSeconds),5)}}
}
if($Summary){
$SummaryUTCTime=$TimeReport|Measure-Object -Property UTCTime -Min -Max
$SummaryVMHostTime=$TimeReport|Measure-Object -Property VMHostTime -Min -Max
$SummaryDiffToUTC=$TimeReport|Measure-Object -Property DiffToUTC -Min -Max -Average
Write-Host "UTC time from the current system :Min and Max date/time while creating this report."
Write-Host "Min: $($SummaryUTCTime.Minimum.ToString())"
Write-Host "Max: $($SummaryUTCTime.Maximum.ToString())"
Write-Host "VMHosts reported Times :Min and Max date/time while creating this report"
Write-Host "Min: $($SummaryVMHostTime.Minimum.ToString())"
Write-Host "Max: $($SummaryVMHostTime.Maximum.ToString())"
Write-Host "Time Difference between VMHost and UTC from local os time Min, Max, Avg"
Write-Host "Min: $($SummaryDiffToUTC.Minimum.ToString())"
Write-Host "Max: $($SummaryDiffToUTC.Maximum.ToString())"
Write-Host "Avg: $($SummaryDiffToUTC.Average.ToString())"
if($CheckTimeFromInternet){
[datetime]$TimeFromInternet=(Invoke-RestMethod -Uri 'http://www.earthtools.org/timezone/52.35000/4.86660').timezone.utctime
$CurrentSystemTimeUTC=(Get-Date).ToUniversalTime()
Write-Host "We took UTC time from internet and compared it to your local time converted to UTC time"
$TimeDiff=[math]::abs(($CurrentSystemTimeUTC-$TimeFromInternet).TotalSeconds)
Write-Host "Reported local time converted to UTC $CurrentSystemTimeUTC"
Write-Host "Reported time taken from internet(http://www.earthtools.org/webservices.htm) $TimeFromInternet"
Write-Host "Difference: $TimeDiff seconds"
}
}
return $TimeReport | Sort-Object -Property DiffToUTC
}

When was vm created, how vm was created and who has created this vm ?

I wanted to know where it is possible, who has created virtual machine. When the virtual machine was created and how it was created.
The idea is very simple. As an input i will take a virtual machine, and the output should be an object with few properties. VM can be created in several ways, right ? So i need to search for different events. When vm is being created/deployed it will create an event for this fact. Those events are as follows:

VmBeingCreatedEvent – Vm is created manually. Right-click New-VM. When we do VM in this way, a second event joins VmRegisteredEvent. So To check for vms there were manually created, we have to browse for events and check if 2 types of events have occured.
VmBeingDeployedEvent – When vm was deployed from template it will make this type of event
VmRegisteredEvent – When vm was registered, for example, open datastore browser, right click on vmx – register.
VmClonedEvent – When vm was cloned.
Continue reading

get-vievent too slow ? :) BOOSTING get-vievent !

There was quite interesting question on communities today. I think it’s worth to share it with everybody what and how 😉
Right so, let’s say you want to get some events from entities using get-vievent:

DESCRIPTION
Retrieves information about the events on a vSphere server. An event is any action in the vCenter Server system or ESX host. The cmdlet collects events that correspo
ned by the cmdlet parameters. Filters are additive and the Entity. Start, and Finish parameters filter the events both by the entity and the timestamp properties. To
om the default one, use the -Server parameter.

Continue reading