VMware Cloud Community
electricd7
Contributor
Contributor
Jump to solution

How do I register all VMX files found in a list of datastores with new names

Hello-

I am trying to come up with a way to search through a given list of datastores, and upon each find of a .VMX file, re-add that machine to inventory only I would like to prefix the name of the machine as something different. Ie, instead of "Machine1", I would like it to be registetred as "auto-Machine1".  So imagine I have an empty datacenter with 4 datastores stored in an array $arrDatastoreToInclude,.  I would like to loop through each of those datastores and add all the VMX files I find back to inventory.

I know that I can use the following to get the datastores I want:

$dsindatacenter = Get-DataCenter $DataCenterName | Get-Datastore | ?{$arrDatastoreToInclude -contains $_.Name}

But I have no idea how to scan those datastores for VMX files and what command to add them back into inventory.  Can anyone help?

1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Try the following, it's based on the script from the post Robert mentioned.

You will have to provide a folder (in $VMFolder) where the unregistered VMs will be registered.

The Set-VM cmdlet will take care of the rename.

$DatacenterName = "MyDatacenter" 
$arrDatastoreToInclude = "DS1","DS2","DS3","DS4"

$dc = Get-DataCenter $DataCenterName
$dsindatacenter =  Get-Datastore -Datacenter $dc | ?{$arrDatastoreToInclude -contains $_.Name} $VMFolder = "MyFolder"
$ESXHost
= Get-VMHost -Location $dc | select -First 1
foreach
($Datastore in $dsindatacenter) {     # Collect .vmx paths of registered VMs on the datastore
   
$registered = @{}     Get-VM -Datastore $Datastore | %{$_.Extensiondata.LayoutEx.File | where {$_.Name -like "*.vmx"} | %{$registered.Add($_.Name,$true)}}    # Set up Search for .VMX Files in Datastore
    New-PSDrive -Name TgtDS -Location $Datastore -PSProvider VimDatastore -Root '\' | Out-Null
   
$unregistered = @(Get-ChildItem -Path TgtDS: -Recurse |
        where {$_.FolderPath -notmatch ".snapshot" -and $_.Name -like "*.vmx" -and !$registered.ContainsKey($_.Name)})     Remove-PSDrive -Name TgtDS    #Register all .vmx Files as VMs on the datastore
  
foreach($VMXFile in $unregistered) {         New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location $VMFolder |         Set-VM -Name ("Auto-" + $_.Name)    } }

The unregistered VMs will be registered with the Displayname that is present in the VMX file.

If that would cause a conflict with already registered VMs, you would have to use the Name parameter on the New-VM cmdlet


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

View solution in original post

Reply
0 Kudos
26 Replies
RvdNieuwendijk
Leadership
Leadership
Jump to solution

Take a look at Luc's VMX Raiders Revisited script. You can easily modify that script to your needs.

Regards, Robert

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Try the following, it's based on the script from the post Robert mentioned.

You will have to provide a folder (in $VMFolder) where the unregistered VMs will be registered.

The Set-VM cmdlet will take care of the rename.

$DatacenterName = "MyDatacenter" 
$arrDatastoreToInclude = "DS1","DS2","DS3","DS4"

$dc = Get-DataCenter $DataCenterName
$dsindatacenter =  Get-Datastore -Datacenter $dc | ?{$arrDatastoreToInclude -contains $_.Name} $VMFolder = "MyFolder"
$ESXHost
= Get-VMHost -Location $dc | select -First 1
foreach
($Datastore in $dsindatacenter) {     # Collect .vmx paths of registered VMs on the datastore
   
$registered = @{}     Get-VM -Datastore $Datastore | %{$_.Extensiondata.LayoutEx.File | where {$_.Name -like "*.vmx"} | %{$registered.Add($_.Name,$true)}}    # Set up Search for .VMX Files in Datastore
    New-PSDrive -Name TgtDS -Location $Datastore -PSProvider VimDatastore -Root '\' | Out-Null
   
$unregistered = @(Get-ChildItem -Path TgtDS: -Recurse |
        where {$_.FolderPath -notmatch ".snapshot" -and $_.Name -like "*.vmx" -and !$registered.ContainsKey($_.Name)})     Remove-PSDrive -Name TgtDS    #Register all .vmx Files as VMs on the datastore
  
foreach($VMXFile in $unregistered) {         New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location $VMFolder |         Set-VM -Name ("Auto-" + $_.Name)    } }

The unregistered VMs will be registered with the Displayname that is present in the VMX file.

If that would cause a conflict with already registered VMs, you would have to use the Name parameter on the New-VM cmdlet


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

That looks like what i am looking for.  A couple of questions:

  -This script appears to add all the VMs to a single host.  We do have DRS so I guess it will kick in and v-motion the machines back off to keep it equailized, but is there an easy way to modify this so it will loop through the connected hosts and add vms in order?

   -I see that you are are setting the folder for these to live in.  Is this a requirement, or could I just eliminate the folders all together?

   -It appears that the script is looping through and excluding any VMs within the datastore array that are already registered before adding any.  Does that sounds right...just kinda new want to be sure i understand what is happening.

   -Finally, what is the purpose of using the Set-VM -Name after he New-VM call?  Is there a reason not to include the -Name in the New-VM call instead of calling Set-VM separately?

Thanks so much, this looks great!

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

1) Yes, the script only registers the lost VMs and for that it needs to pass a host.

When these VMs are powered on then DRS should indeed kick in.

2) I'm afraid you need to give a folder. Remember this is a "blue" folder.

If you want them in the root, you can use the hidden folder "vm"

3) Correct. It first finds the registered VMs on the datastore and uses that in the where-clause to exclude those VMS

4) I haven't tested that, but yes, that looks as if it might be possible.

But then you would have give the complete name. In the solution above the VM is registered with the name that is in the VMS file and the Set-VM adds a prefix to that name.


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Ok I am running the script as follows:

Add-PSSnapIn VMware.VimAutomation.Core -ErrorAction SilentlyContinue
$strVC = "vc.mydomain.local"
Connect-VIServer $strVC

#Loop through FlexClone volumes to add machines to inventory
    $volpath = @("netapp1-vmfs_nas3")
    $dc = Get-DataCenter $DataCenterName
    $dsindatacenter =  Get-Datastore -Datacenter $dc | ?{$volpath -contains $_.Name}
    $ESXHost = Get-VMHost -Location $dc | select -First 1
    foreach($Datastore in $dsindatacenter) {
        # Collect .vmx paths of registered VMs on the datastore
        $registered = @{}
        Get-VM -Datastore $Datastore | %{$_.Extensiondata.LayoutEx.File | where {$_.Name -like "*.vmx"} | %{$registered.Add($_.Name,$true)}}

       # Set up Search for .VMX Files in Datastore
        New-PSDrive -Name TgtDS -Location $Datastore -PSProvider VimDatastore -Root '\' | Out-Null
        $unregistered = @(Get-ChildItem -Path TgtDS: -Recurse |
            where {$_.FolderPath -notmatch ".snapshot" -and $_.Name -like "*.vmx" -and !$registered.ContainsKey($_.Name)})
        Remove-PSDrive -Name TgtDS
       #Register all .vmx Files as VMs on the datastore
       foreach($VMXFile in $unregistered) {
            #New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location "vm" |
            #Set-VM -Name ("Auto-" + $_.Name)
            Write-Host "New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location 'vm'"
       }
    }

I only modified the last couple lines so i could print out what would happen before actually running it.  Its been running for 10 minutes now and not seeing any output on screen.  The volume it should be scanning (netapp1-vmfs_nas3) is about 400GB and contains about 35 folders total.  I am pretty sure that is the part it is stuck on because when I killed it last time and tried to re-run it in ISE, it errored and said TgtDS was already in use.  How long should this take, and is there something I can change to show that its still working?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Most of the time the script will be in the Get-ChildItem code.

The datastore psprovider that comes with PowerCLI is not the fastest and it is apparently lacking support for the common parameters like Verbose and Debug. And don't forget that each item has to pass through a rather complex Where-clause

I'm afraid there isn't a lot you can do without dramatically changing the logic of the script (and making it even slower).

You could use an editor that allows you to pause the script and check if it is still making progress.


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Yea, I let it sit.  It took just over 22 minutes to do a single datastore.  I guess thats not terrible, but just wish it were faster...gotten used to sorting through via CIFS Smiley Happy  Thanks for help!

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Sorry I have one more question related to this.  In another part of my code, I am using CIFS to open the VMX files and replace a reference to a datastore with another (ie, the disks get copied over, but in a different location.)  Would there be an easy way to include this as part of the above code so I could do away with my CIFS calls all together.  I currently run the following code to do the replacements:

foreach ($path in $volpath)
    {
        $fclist = Get-ChildItem -Path "$DRRootPath$path" -recurse -include *.vmx
        foreach ($vm in $fclist)
        {
            #Replace pointer for pagefile volume
            (Get-Content $vm.fullname) |
            Foreach-Object {$_ -replace $ProdPageFileUUID, $DRPageFileUUID} |
            Set-Content $vm.fullname
        }
    }

Seems like somewhere inside the New-PSDrive and Remove-PSDrive block in your code, I should be able to do the same replacement.  I am just not sure how I would make the change.  Can you assist?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

You could try something like this

Add-PSSnapIn VMware.VimAutomation.Core -ErrorAction SilentlyContinue 
$strVC = "vc.mydomain.local"
Connect-VIServer
$strVC #Loop through FlexClone volumes to add machines to inventory
    $volpath = @("netapp1-vmfs_nas3")     $dc = Get-DataCenter $DataCenterName
    $dsindatacenter =  Get-Datastore -Datacenter $dc | ?{$volpath -contains $_.Name}     $ESXHost = Get-VMHost -Location $dc | select -First 1
    foreach($Datastore in $dsindatacenter) {         # Collect .vmx paths of registered VMs on the datastore
       
$registered = @{}         Get-VM -Datastore $Datastore | %{$_.Extensiondata.LayoutEx.File | where {$_.Name -like "*.vmx"} | %{$registered.Add($_.Name,$true)}}        # Set up Search for .VMX Files in Datastore
       
New-PSDrive -Name TgtDS -Location $Datastore -PSProvider VimDatastore -Root '\' | Out-Null
        $unregistered = @()         Get-ChildItem -Path TgtDS: -Recurse |             where {$_.FolderPath -notmatch ".snapshot" -and $_.Name -like "*.vmx" -and !$registered.ContainsKey($_.Name)} | %{                 Get-Content $_.Fullname | %{                     $_ -replace $ProdPageFileUUID, $DRPageFileUUID
                } |                
Set-Content $_.Fullname                 $unregistered += $_
            }        
Remove-PSDrive -Name TgtDS
       #Register all .vmx Files as VMs on the datastore
      
foreach($VMXFile in $unregistered) {             #New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location "vm" |
            #Set-VM -Name ("Auto-" + $_.Name)
            Write-Host "New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location 'vm'"
       }     }


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Yea I tried something similar and got an error.  When i try it as you have it written it comes up with this error:

Get-Content : Cannot use interface. The IContentCmdletProvider interface is not implemented by this provider.

Its like the provider didn't include much or something?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Yes, I was afraid of that, the datastore provider that comes with PowerCLI doesn't all the features one can expect from a psprovider.

An alternative could be to use the Copy-DatastoreItem cmdlet.

First copy the VMX file to a local directory on the PC, do the changes to the file and then copy the VMX file back to the datastore.

Tedious I agree, but that should work.


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Can that be all done within the same piping or would I have to change something?? the Copy-DatastoreItem looks simple enough, but I am not sure how to implement it within the string like you currently have.

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

I have a problem occuring with the rename step.  I have it running as you have written:

   foreach($VMXFile in $unregistered) {
        New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location $VMFolder |
        Set-VM -Name ("Auto-" + $_.Name)
   }

The problem is that it renames the first file to "Auto-" and doesn't include the original name??  I *think* it is supposed to be getting the name from the New-VM command, but it doesn't seem to be working.  What am I doing wrong?
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

You're not doing anything wrong, my code was wrong.

Try it like this

foreach($VMXFile in $unregistered) {
    New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location $VMFolder | %{
        Set-VM -VM $_ -Name ("Auto-" + $_.Name)
    }
}


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Yes that seems to work, but prompts me for authorization to rename.  I tried to put in Confirm:$false after the ) and before the } but it didn't like that....is there a way to make it not prompt for rename?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I'm afraid that the account you are using is missing a privilege on the vCenter.

Does your account have the Administrator role on the vCenter ?


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

Reply
0 Kudos
electricd7
Contributor
Contributor
Jump to solution

Sorry it was something silly. the working string with no confirmation is as follows (thanks for all the help!):

New-VM -VMFilePath $VMXFile.DatastoreFullPath -VMHost $ESXHost -Location $vmFolder | %{Set-VM -VM $_ -Confirm:$false -Name ("dr-" + $_.Name)}

Reply
0 Kudos
switch1
Contributor
Contributor
Jump to solution

Is it possible to just scan all mounted datastores and add any found vmx to inventory (excluding snapshots)? I need to setup an environment to mount storage snapshots add the VM's to inventory and backup with VADP. I'm a powerscli noob and having no luck.

Thanks

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Does 'Get-Datastore' return all the datastores you want to scan ?


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

Reply
0 Kudos