Hi,
Does anyone know/have a way to find unregistered virtual machines?
Thanks in advance!
Apparently it wasn't my day yesterday
The attached file above (Find-unregistered-VMX-with-CSV-v4.ps1) should now be the correct version.
Sorry about that.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Did you have a look at ?
This script registers the guests but it shouldn't be too hard to replace the RegisterVM_Task method with a Write-Host that just list VMX file.
If it is, let me know and I will give you an adapted version of the script.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
If it's not a big deal, could you kindly help get your script to just output either to the console or a file which vms are unregistered? I'm deifnitely trying to learn posh as quickyl as possible. But your help is always appreciated.
Thanks LucD,
PS we should start a blog on "How many ways can we Thank and Compliment LucD" 😃
I have adapted the original script a bit to list just the VMX files of unregistered guests.
The script run through all your datacenters and for each datacenter through all the clusters.
In each cluster it scans every VMFS datastore for unregistered VMX files.
Get-Datacenter | % { $datacenter = $_ Write-Host "Datacenter" $_.Name $folder = Get-View ($_ | Get-Folder -Name "vm").ID $_ | Get-Cluster | % { $cluster = $_ Write-Host "`tCluster" $_.Name $pool = Get-View ($_ | Get-ResourcePool -Name "Resources").ID $esxImpl = Get-Cluster -Name $cluster | Get-VMHost | select -First 1 $esx = Get-View $esxImpl.ID $dsBrowser = Get-View $esx.DatastoreBrowser foreach($dsImpl in $dsBrowser.Datastore){ $ds = Get-View $dsImpl if($ds.Summary.Type -eq "NFS"){continue} $vms = @() foreach($vmImpl in $ds.Vm){ $vm = Get-View $vmImpl $vms += $vm.Config.Files.VmPathName } $datastorepath = "" Write-Host "`t`tDatastore" $ds.Summary.Name $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec $searchSpec.matchpattern = "*.vmx" $task = Get-View ($dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec)) while ($task.Info.State -eq "running" -or $task.Info.State -eq "queued"){ $task.UpdateViewData() sleep 5 } if($task.info.result -ne $null){ foreach ($file in $task.info.Result){ $found = $FALSE foreach($vmx in $vms){ if(($file.FolderPath + $file.File[0].Path) -eq $vmx){ $found = $TRUE } } if (-not $found -and $task.Info.Result[0].File -ne $null){ $vmx = $file.FolderPath + $file.File[0].Path Write-Host "`t`t" $vmx } } } } } }
Note1: if you want to also scan datastores that are not of the VMFS type you remove the line: if($ds.Summary.Type -eq "NFS")
Note2: if you only have standalone ESX hosts in your datacenter the script needs a few changes. Let me know if that is needed.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
I powered off a vm and unregistered it. When I run the script, it doesn't pick it up as an unregistred vm.
Am I doing something wrong? I'm running this script against an entire vCenter Server.
Thanks!
Are your datastores by any chance NFS ?
Is the VMX file on a datastore that is connected to one of the clusters ?
Does the script at least list all your datacenters and clusters correctly ?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
LucD,
The datastores are on SAN storage. The VMX file is located on one of the datastores. Our cluster use boot and datastors on SAN. Yes, it does lsit all the clusters and datacenters correctly.
Hi,
Thanks for the gr8 script, I was searhing for the same. I am not able to see any output of the script, can be generate the output to some file ?
Thanks in advance
Gurjit Dhillon
The script writes to the console with the Write-Host cmdlet.
Of course, if there no unregistered guests nothing will appear on screen.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi ,
I have tried this script on my all the clusters, I can see output come with lots of listing of satastore name. Can I also get the VM name along with the Datastore name and also can this out put be generated in Xls file ?
Many thanks
Gurjit Dhillon
The name of a VM doesn't have to correspond with the name of the .VMX file of that VM.
The "displayName" field in the .VMX file contains the name given to the VM.
It is difficult to extract the "displayName" field from a .VMX file when the VM is not registered.
The only way to this (in my opinion) is to:
*) register the VM from the .VMX file
*) get the VM's name
*) unregister the VM again
But this could give some problems (for example duplicate names for VMs).
The script higher up in this thread suffers from the problem the forum SW has with square brackets.
The line $dspath is incorrectly displayed. It should be: $datastorepath = "\[" + $ds.Info.Name + "\]"
Better to use the attached script instead of copying it from the browser.
See for a script to re-register VMs with the name in the "displayName" field.
The script below will create a CSV file with the same information you can see on the console.
If you don't want the console output, comment out the Write-Host cmdlets.
$report = @() Get-Datacenter | % { $datacenter = $_ Write-Host "Datacenter" $_.Name $folder = Get-View ($_ | Get-Folder -Name "vm").ID $_ | Get-Cluster | % { $cluster = $_ Write-Host "`tCluster" $_.Name $pool = Get-View ($_ | Get-ResourcePool -Name "Resources").ID $esxImpl = Get-Cluster -Name $cluster | Get-VMHost | select -First 1 $esx = Get-View $esxImpl.ID $dsBrowser = Get-View $esx.DatastoreBrowser foreach($dsImpl in $dsBrowser.Datastore){ $ds = Get-View $dsImpl if($ds.Summary.Type -eq "NFS"){continue} $vms = @() foreach($vmImpl in $ds.Vm){ $vm = Get-View $vmImpl $vms += $vm.Config.Files.VmPathName } $datastorepath = "" Write-Host "`t`tDatastore" $ds.Summary.Name $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec $searchSpec.matchpattern = "*.vmx" $task = Get-View ($dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec)) while ($task.Info.State -eq "running" -or $task.Info.State -eq "queued"){ $task.UpdateViewData() sleep 5 } if($task.info.result -ne $null){ foreach ($file in $task.info.Result){ $found = $FALSE foreach($vmx in $vms){ if(($file.FolderPath + $file.File[0].Path) -eq $vmx){ $found = $TRUE } } if (-not $found -and $task.Info.Result[0].File -ne $null){ $vmx = $file.FolderPath + $file.File[0].Path Write-Host "`t`t" $vmx $row = "" | Select Datacenter, Cluster, Datastore, VMXpath $row.Datacenter = $datacenter.Name $row.Cluster = $cluster.Name $row.Datastore = $ds.Name $row.VMXpath = $vmx $report += $row } } } } } } $report | Export-Csv "C:\Unregistered-VMX.csv" -NoTypeInformation
Use the attached script to avoid the square brackets problem.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi,
May be the name of the directory where the vmx file is placed can be used as VM name or VM name can be extrated from the vmx file, example vm name is test-vm.vmx, after extraxtion from vmx file, vm name will be "test-vm" or listing of vmx file along with vm name example test-vm.vmx will also do.
Thanks in advance.
Gurjit Dhillon
That can be done, but mind that the VM name does not always correspond with the name of the VMX file.
$report = @() Get-Datacenter | % { $datacenter = $_ Write-Host "Datacenter" $_.Name $folder = Get-View ($_ | Get-Folder -Name "vm").ID $_ | Get-Cluster | % { $cluster = $_ Write-Host "`tCluster" $_.Name $pool = Get-View ($_ | Get-ResourcePool -Name "Resources").ID $esxImpl = Get-Cluster -Name $cluster | Get-VMHost | select -First 1 $esx = Get-View $esxImpl.ID $dsBrowser = Get-View $esx.DatastoreBrowser foreach($dsImpl in $dsBrowser.Datastore){ $ds = Get-View $dsImpl if($ds.Summary.Type -eq "NFS"){continue} $vms = @() foreach($vmImpl in $ds.Vm){ $vm = Get-View $vmImpl $vms += $vm.Config.Files.VmPathName } $datastorepath = "" Write-Host "`t`tDatastore" $ds.Summary.Name $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec $searchSpec.matchpattern = "*.vmx" $task = Get-View ($dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec)) while ($task.Info.State -eq "running" -or $task.Info.State -eq "queued"){ $task.UpdateViewData() sleep 5 } if($task.info.result -ne $null){ foreach ($file in $task.info.Result){ $found = $FALSE foreach($vmx in $vms){ if(($file.FolderPath + $file.File[0].Path) -eq $vmx){ $found = $TRUE } } if (-not $found -and $task.Info.Result[0].File -ne $null){ $vmx = $file.FolderPath + $file.File[0].Path Write-Host "`t`t" $vmx $row = "" | Select Datacenter, Cluster, Datastore, VMname, VMXpath $row.Datacenter = $datacenter.Name $row.Cluster = $cluster.Name $row.Datastore = $ds.Summary.Name $row.VMname = (([regex]"(\w+)\.vmx").Match($file.File[0].Path)).Groups[1].Value $row.VMXpath = $vmx $report += $row } } } } } } $report | Export-Csv "C:\Unregistered-VMX.csv" -NoTypeInformation
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi,
I think it shows the Vm name along with the datastore, as shown below. But I got few error while execting the script. can you put some light on this error. I have attach the script I am running for your reference.
Unregistered VM - VMX file build-css-std-r2-sp2-stage-a/build-css-std-r2-sp2-stage-a.vmx
Cannot index into a null array.
At :line:26 char:37
+ if(($file.FolderPath + $file.File[ <<<< 0].Path) -eq $vmx){
Regards
Gurjit Dhillon
I suspect you are referring to the script in .
The problem you are seeing is probably caused by the fact that the foreach statement runs at least once through a loop although the array is $null.
The solution is to add a test before the loop starts.
The reason why the array is $null is probably because there are no .VMX files on that datastore.
This is the script with the extra test.
$folder = Get-View (Get-Datacenter -Name <datacenter> | Get-Folder -Name "vm").ID $pool = Get-View (Get-Cluster -Name <cluster> | Get-ResourcePool -Name "Resources").ID $esxImpl = Get-VMHost -Name <ESX-host> $esx = Get-View $esxImpl.ID $dsBrowser = Get-View $esx.DatastoreBrowser foreach($dsImpl in $dsBrowser.Datastore){ $ds = Get-View $dsImpl $vms = @() foreach($vmImpl in $ds.Vm){ $vm = Get-View $vmImpl $vms += $vm.Config.Files.VmPathName } $datastorepath = "" $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec $searchSpec.matchpattern = "*.vmx" $taskMoRef = $dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec) $task = Get-View $taskMoRef while ($task.Info.State -eq "running"){$task = Get-View $taskMoRef} if($task.info.result -ne $null){ foreach ($file in $task.info.Result){ $found = $FALSE foreach($vmx in $vms){ if(($file.FolderPath + $file.File[0].Path) -eq $vmx){ $found = $TRUE } } if (-not $found -and $task.Info.Result[0].File -ne $null){ $vmx = $file.FolderPath + $file.File[0].Path $params = @($vmx,$null,$FALSE,$pool.MoRef,$null) $folder.GetType().GetMethod("RegisterVM_Task").Invoke($folder, $params) } } } }
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I can still see the below error, I have used your new sciprt called register-vm3.ps1.
Type : Task
Value : task-285208
Cannot index into a null array.
At :line:28 char:38
+ if(($file.FolderPath + $file.File[ <<<< 0].Path) -eq $vmx){
Regards
Gurjit Dhillon
That can probably happen when there is a subfolder on the datastore that doesn't contain a .VMX file.
This script contains an extra test to skip that situation.
$folder = Get-View (Get-Datacenter -Name <datacenter> | Get-Folder -Name "vm").ID $pool = Get-View (Get-Cluster -Name <cluster> | Get-ResourcePool -Name "Resources").ID $esxImpl = Get-VMHost -Name <ESX-host> $esx = Get-View $esxImpl.ID $dsBrowser = Get-View $esx.DatastoreBrowser foreach($dsImpl in $dsBrowser.Datastore){ $ds = Get-View $dsImpl $vms = @() foreach($vmImpl in $ds.Vm){ $vm = Get-View $vmImpl $vms += $vm.Config.Files.VmPathName } $datastorepath = "" $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec $searchSpec.matchpattern = "*.vmx" $taskMoRef = $dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec) $task = Get-View $taskMoRef while ($task.Info.State -eq "running"){$task = Get-View $taskMoRef} if($task.info.result -ne $null){ foreach ($result in $task.info.Result){ if($result.File -ne $null){ $found = $FALSE foreach($vmx in $vms){ if(($result.FolderPath + $result.File[0].Path) -eq $vmx){ $found = $TRUE } } if (-not $found -and $task.Info.Result[0].File -ne $null){ $vmx = $result.FolderPath + $result.File[0].Path $params = @($vmx,$null,$FALSE,$pool.MoRef,$null) $folder.GetType().GetMethod("RegisterVM_Task").Invoke($folder, $params) } } } } }
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi,
Many thanks LUC , this version of script worked fine.I can see my unregister vm's are registered again on VC.
I have a small request, Can this script be modifed to just show the list of Vm's which are not registered on VC along, that mean not to registered any vm on VC with the Datastore name and if possible the list to export in xls file.
Regards
Gurjit Dhillon
In one of my previous replies in this thread I attached a script called Find-unregistered-VMX-with-CSV-v2.ps1 that finds the unregistered .VMX files and exports the results to a CSV file.
The attached script is the updated version with the extra check for folders that do not contain a .VMX file.
Get-Datacenter | % { $datacenter = $_ Write-Host "Datacenter" $_.Name $folder = Get-View ($_ | Get-Folder -Name "vm").ID $_ | Get-Cluster | % { $cluster = $_ Write-Host "`tCluster" $_.Name $pool = Get-View ($_ | Get-ResourcePool -Name "Resources").ID $esxImpl = Get-Cluster -Name $cluster | Get-VMHost | select -First 1 $esx = Get-View $esxImpl.ID $dsBrowser = Get-View $esx.DatastoreBrowser foreach($dsImpl in $dsBrowser.Datastore){ $ds = Get-View $dsImpl if($ds.Summary.Type -eq "NFS"){continue} $vms = @() foreach($vmImpl in $ds.Vm){ $vm = Get-View $vmImpl $vms += $vm.Config.Files.VmPathName } $datastorepath = "" Write-Host "`t`tDatastore" $ds.Summary.Name $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec $searchSpec.matchpattern = "*.vmx" $task = Get-View ($dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec)) while ($task.Info.State -eq "running" -or $task.Info.State -eq "queued"){ $task.UpdateViewData() sleep 5 } if($task.info.result -ne $null){ foreach ($file in $task.info.Result){ if($result.File -ne $null){ $found = $FALSE foreach($vmx in $vms){ if(($file.FolderPath + $file.File[0].Path) -eq $vmx){ $found = $TRUE } } if (-not $found -and $task.Info.Result[0].File -ne $null){ $vmx = $file.FolderPath + $file.File[0].Path Write-Host "`t`t" $vmx $row = "" | Select Datacenter, Cluster, Datastore, VMname, VMXpath $row.Datacenter = $datacenter.Name $row.Cluster = $cluster.Name $row.Datastore = $ds.Summary.Name $row.VMname = (([regex]"(\w+)\.vmx").Match($file.File[0].Path)).Groups[1].Value $row.VMXpath = $vmx $report += $row } } } } } } } $report | Export-Csv "C:\Unregistered-VMX.csv" -NoTypeInformation
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi Luc,
Hope you are doing fine.
I have not checked this script, I will be doing it today.Above you have mention in the directory script will check if they don’t have vmx file, but there are greater chances that vmx file resides on some
other directory on some other datastore. I believe this script should not behave like this. I was looking for all the VM which doesn’t have vmx file on any directory on any datastore.
Please correct me if I have not understood correctly.
Your support is highly appreciated.
Regards
Gurjit Dhillon