VMware Cloud Community
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Register VMs in a datastore in the vCenter inventory

Hi to all the scripting guru's out there,

I'm putting together a DR solution for our VM's, we are currently using the IBM Storwize V7000 with Remote Copy to replicate some Datastores.

Now I have done some extensive testing and found that when you perform a switch from PROD to DR there is a a bit of a process to get the VM's up and running.

1. I have to do a full rescan of the HBAs. Under storage adapters you can see the assigned storage devices as mounted, however you still need to go to Storage and go the the "Add Storage" wizard to readd the Datastore with the option resignaturing the volume. So this part isn't so painful except it appends a different naming convention to the datastore name, example a datastore named prd_lun100 gets named snap-5a18365a-prd_lun100 so I have to rename the datastore back to the default.

2. I have to go through the datastores and add every virtual machine into inventory which is very tedious, and the very part I need to automate.

I tried this one liner, which I found here -> http://www.wooditwork.com/2011/08/11/adding-vmx-files-to-vcenter-inventory-with-powercli-gets-even-e...

New-VM -VMFilePath "[prd_lun100] SERVER01/SERVER01.vmx" -VMHost "VMHost01.local"

If possible I would like to expand on this, in the following ways:

1. Automate adding the datastores with the correct naming convention, by using either the naa identifier of the LUN or LUN ID#, possibly pull this info from a CSV list.

2. Add VM as per the one liner above but from a CSV list of some sort, however add is to a DRS Cluster rather ESXi Host, if possible prioritize adding VMs by some sort of groups flag in the CSV.

3. Power on VMs based on a priority.

I would really really appreciate if some one can help with this, I know probably a big ask, but scripting is not my forte and wouldn't know where to start.

Nicholas
Reply
0 Kudos
96 Replies
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Hi Luc,

I hate to bother you with this, but I was wondering if extra thing can be added to the script attached. Basically some of these replicated servers have virtual hard disks attached which are on non-replicated SAN volumes as they are used for DB backups etc, and we don't wan't to replicate backups.

So after the VM has been added to the DR site they wont be able to power them on becasue it can't find that missing disk, so we manully have to remove it after we add it to inventory before powering on. If you see the screenshot you will notice Hard Disk 3 is the disk not replicated, it also can't find information on the disk, it states that the provisioned size is 0MB and Maximum size is N/A.

My question is can we use this to check if the VM has this non existent disk and if so remove it before powering on?

missing-disk.jpg

Nicholas
Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Hi Luc,

Continuing from my previous question, I think we can use something like this to find what I would call an Orphaned Virtual Hard Disk

Get-HardDisk -VM $vm | where {$_.CapacityKB -eq 0}

I'm now going to try and figure out removing HardDisk this from the VMX config, but just wanted your feedback if you think I'm going down the right path?

Nicholas
Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Ok I came up with this which seems to work ok, what do you think?

$Cluster = "V7000 Cluster"
$Datastores = get-datastore "RC*"
$VMFolder = "DR_Folder"
$ESXHost = Get-Cluster $Cluster | Get-VMHost | select -First 1
foreach($Datastore in Get-Datastore $Datastores) {
  # Set up Search for .VMX Files in Datastore
  $ds = Get-Datastore -Name $Datastore | %{Get-View $_.Id}
  $SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
  $SearchSpec.matchpattern = "*.vmx"
  $dsBrowser = Get-View $ds.browser
  $DatastorePath = "[" + $ds.Summary.Name + "]"
  # Find all .VMX file paths in Datastore, filtering out ones with .snapshot
  $SearchResult = $dsBrowser.SearchDatastoreSubFolders($DatastorePath, $SearchSpec) | where {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath + ($_.File | select Path).Path}
  #Register all .vmx Files as VMs on the datastore
  foreach($VMXFile in $SearchResult) {
    $vm = New-VM -VMFilePath $VMXFile -VMHost $ESXHost -Location $VMFolder -ErrorAction SilentlyContinue
Get-hardDisk -VM $vm | where {$_.CapacityKB -eq 0} | Remove-HardDisk -Confirm:$false
if($vm){
      $newname = $vm.Name + "_Copy"
      Set-VM -VM $vm -Name $newname -confirm:$false
      if($vm.PowerState -ne "PoweredOn"){
        $vm = Start-VM -VM $vm -ErrorAction SilentlyContinue
      }
      Get-VMQuestion -VM $vm | Set-VMQuestion -Option "I moved it" -Confirm:$false
    }
  }
}
Nicholas
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I would just move that new line after the 'if($vm){' line, that way you don't risk getting errors when the registration of the VMX fails.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Thanks Luc,

Do you think this in the only, I can achieve what I'm trying to do?

Nicholas
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

That should work, but since I don't have a similar environment I can't actually test the script.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Hi Luc,

Just stuck on something, I need to filter serching Datastores to a particular Datacenter. I added some code but I dont think its quite filtering properly.

Any thoughts?

$Cluster = "MyCluster"
$Datastores = Get-Datastore "MIRROR*"
$Datacenter = Get-Datacenter "MyDC"
$VMFolder = "DR_Folder"
$ESXHost = Get-Cluster $Cluster | Get-VMHost | select -First 1
foreach($Datastore in Get-Datastore $Datastores) {
  # Set up Search for .VMX Files in Datastore
  $ds = Get-Datacenter -Name $Datacenter | Get-Datastore -Name $Datastore | %{Get-View $_.Id}
  $SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
  $SearchSpec.matchpattern = "*.vmx"
  $dsBrowser = Get-View $ds.browser
  $DatastorePath = "[" + $ds.Summary.Name + "]"
  # Find all .VMX file paths in Datastore, filtering out ones with .snapshot
  $SearchResult = $dsBrowser.SearchDatastoreSubFolders($DatastorePath, $SearchSpec) | where {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath + ($_.File | select Path).Path}
  #Register all .vmx Files as VMs on the datastore
  foreach($VMXFile in $SearchResult) {
    $vm = New-VM -VMFilePath $VMXFile -VMHost $ESXHost -Location $VMFolder -ErrorAction SilentlyContinue
if($vm){
Get-hardDisk -VM $vm | where {$_.CapacityKB -eq 0} | Remove-HardDisk -Confirm:$false
      $newname = $vm.Name + "_Copy"
      Set-VM -VM $vm -Name $newname -confirm:$false
      if($vm.PowerState -ne "PoweredOn"){
        $vm = Start-VM -VM $vm -ErrorAction SilentlyContinue
      }
      Get-VMQuestion -VM $vm | Set-VMQuestion -Option "I moved it" -Confirm:$false
    }
  }
}
Nicholas
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

The problem is that this will most probably return more than 1 datastore for a datacenter.

So your $ds variables will be an array and the $ds.Browser reference will fail.

You can try to update the foreach statemenet. Something like this

foreach($Datastore in (Get-Datacenter MyDC | Get-Datastore "MIRROR"))


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Unfortunetely no luck.

Get-View : Cannot validate argument on parameter 'VIObject'. The argument is nu
ll or empty. Supply an argument that is not null or empty and then try the comm
and again.
At C:\newscripts\HRemoteCopy-RegisterVMX-V1.ps1:12 char:24
+   $dsBrowser = Get-View <<<<  $ds.browser
    + CategoryInfo          : InvalidData: (:) [Get-View], ParameterBindingVal
   idationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutom
   ation.ViCore.Cmdlets.Commands.DotNetInterop.GetVIView
You cannot call a method on a null-valued expression.
At C:\newscripts\HRemoteCopy-RegisterVMX-V1.ps1:15 char:55
+   $SearchResult = $dsBrowser.SearchDatastoreSubFolders <<<< ($DatastorePath,
$SearchSpec) | where {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath +
($_.File | select Path).Path}
    + CategoryInfo          : InvalidOperation: (SearchDatastoreSubFolders:Str
   ing) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
New-VM : Cannot validate argument on parameter 'VMFilePath'. The argument is nu
ll or empty. Supply an argument that is not null or empty and then try the comm
and again.
At C:\newscripts\HRemoteCopy-RegisterVMX-V1.ps1:19 char:29
+     $vm = New-VM -VMFilePath <<<<  $VMXFile -VMHost $ESXHost -Location $VMFol
der -ErrorAction SilentlyContinue
    + CategoryInfo          : InvalidData: (:) [New-VM], ParameterBindingValid
   ationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutom
   ation.ViCore.Cmdlets.Commands.NewVM
Nicholas
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Can you attach the complete script ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Hi Luc,

Here it is

$Cluster = "MyCluster"
$Datastores = Get-Datastore "MIRROR*"
$VMFolder = "DR_Folder"
$ESXHost = Get-Cluster $Cluster | Get-VMHost | select -First 1
  foreachforeach($Datastore in (Get-Datacenter "MyDC" | Get-Datastore "MIRROR")) {
  # Set up Search for .VMX Files in Datastore
  $ds = Get-Datastore -Name $Datastore | %{Get-View $_.Id}
  $SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
  $SearchSpec.matchpattern = "*.vmx"
  $dsBrowser = Get-View $ds.browser
  $DatastorePath = "[" + $ds.Summary.Name + "]"
  # Find all .VMX file paths in Datastore, filtering out ones with .snapshot
  $SearchResult = $dsBrowser.SearchDatastoreSubFolders($DatastorePath, $SearchSpec) | where {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath + ($_.File | select Path).Path}
  #Register all .vmx Files as VMs on the datastore
  foreach($VMXFile in $SearchResult) {
    $vm = New-VM -VMFilePath $VMXFile -VMHost $ESXHost -Location $VMFolder -ErrorAction SilentlyContinue
if($vm){
Get-hardDisk -VM $vm | where {$_.CapacityKB -eq 0} | Remove-HardDisk -Confirm:$false
      $newname = $vm.Name + "_Copy"
      Set-VM -VM $vm -Name $newname -confirm:$false
      if($vm.PowerState -ne "PoweredOn"){
        $vm = Start-VM -VM $vm -ErrorAction SilentlyContinue
      }
      Get-VMQuestion -VM $vm | Set-VMQuestion -Option "I moved it" -Confirm:$false
    }
  }
}
Nicholas
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Try it like this

$Cluster = "MyCluster" 
$DatastoreName = "MIRROR*"
$VMFolder = "DR_Folder"
$ESXHost = Get-Cluster $Cluster | Get-VMHost | select -First 1

foreachforeach
($Datastore in (Get-Datacenter "MyDC" | Get-Datastore -Name $DatastoreName) {   # Set up Search for .VMX Files in Datastore   $ds = Get-View $Datastore.Id
  $SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
  $SearchSpec.matchpattern = "*.vmx"
 
$dsBrowser = Get-View $ds.browser
 
$DatastorePath = "[" + $ds.Summary.Name + "]"
  # Find all .VMX file paths in Datastore, filtering out ones with .snapshot   $SearchResult = $dsBrowser.SearchDatastoreSubFolders($DatastorePath, $SearchSpec) | where {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath + ($_.File | select Path).Path}   #Register all .vmx Files as VMs on the datastore   foreach($VMXFile in $SearchResult) {     $vm = New-VM -VMFilePath $VMXFile -VMHost $ESXHost -Location $VMFolder -ErrorAction SilentlyContinue
    if($vm){       Get-hardDisk -VM $vm | where {$_.CapacityKB -eq 0} | Remove-HardDisk -Confirm:$false
      $newname = $vm.Name + "_Copy"
      Set-VM -VM $vm -Name $newname -confirm:$false
      if($vm.PowerState -ne "PoweredOn"){         $vm = Start-VM -VM $vm -ErrorAction SilentlyContinue
      }       Get-VMQuestion -VM $vm | Set-VMQuestion -Option "I moved it" -Confirm:$false
    }   } }


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
nicholas1982
Hot Shot
Hot Shot
Jump to solution

Hi Luc,

That works, I just had to make a minor correction on line 6, and I also decided to add a Datacenter Name variable.

Thanks again Smiley Happy

Nicholas
Reply
0 Kudos
bahizi
Contributor
Contributor
Jump to solution

Hi LucD,

I came a cross this great script, so i was wondering how my csv file would look like

Here's what I did I don't know if it's correct

pastedImage_0.png

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

The script doesn't need a CSV file as input.
You only need to provide one or more datastores.
Unless you are referring to another script (not the last one in this thread)?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
bahizi
Contributor
Contributor
Jump to solution

I'm referring to this script below but mostly the Register all .vmx part with an input

$targetVMX = Import-Csv C:\vmxnames.csv -UseCulture

$Cluster
= "LON_PROD1"
$Datastores
= "lonservers*"
$VMFolder = "LondonAppServers"
$ESXHost
= Get-Cluster $Cluster | Get-VMHost | select -First 1
foreach
($Datastore in Get-Datastore $Datastores) {
  
# Set up Search for .VMX Files in Datastore
   $ds = Get-Datastore -Name $Datastore | %{Get-View $_.Id}
  
$SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
   $SearchSpec.matchpattern = "*.vmx"
   $dsBrowser = Get-View $ds.browser
   $DatastorePath = "[" + $ds.Summary.Name + "]"
  
# Find all .VMX file paths in Datastore, filtering out ones with .snapshot (Useful for NetApp NFS)
   $SearchResult = $dsBrowser.SearchDatastoreSubFolders($DatastorePath, $SearchSpec) | where {$_.FolderPath -notmatch ".snapshot"} | %{$_.FolderPath + ($_.File | select Path).Path}
  
#Register all .vmx Files as VMs on the datastore
   foreach($VMXFile in $SearchResult) {
    
if($targetVMX -contains $VMXFile){
     
New-VM -VMFilePath $VMXFile -VMHost $ESXHost -Location $Folder -RunAsync
    }
   }

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

If you have the orphaned VMX files already in a CSV, you can just run the New-VM on each entry.
But note that you also need an ESXi node to register the VM.

You could put that in the CSV as well, or you could register all entries on a fixed, hardcoded ESXi node.

Note that the VMX path needs to be in the correct format.

See example 11 on the NewVM cmdlet's online help page.

Something like this

# CSV file layout

# 'Path'

# '[DS1] VM1/VM1.vmx'

# '[DS2] VM2/VM2.vmx'

#

$vmxs = Import-Csv -Path vmxpaths.csv -UseCulture

$esx = Get-VMHost -Name MyEsx

foreach ($vmx in $vmxs) {

  New-VM -VMFilePath $vmx.Path -VMHost $esx -RunAsync

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos