Save to My DOJO
Table of contents
A Naming Issue
A common annoyance VMware administrators have to deal with from time to time is having to reconcile a virtual machine name with that of its holding folder – created on a datastore – whenever the vm is renamed. For instance, let’s suppose you clone a vm from a template and while doing so, you skip the vm naming part. By default, the vm name is set to New Virtual Machine. After you finish setting up the vm, you decide it’s best to rename the vm since New Virtual Machine isn’t exactly indicative of anything. The problem arises from the fact that when a vm is renamed, its folder name on the datastore remains as is; it is not updated to reflect the name change of the virtual machine. This conundrum is illustrated in Figure 1.
The issue is further exacerbated when a vm has been struck off the inventory, whether intentionally or not, and needs to be added back. You’re 100% sure of the vm’s name but, hard as you try, finding the corresponding datastore folder is next to impossible. Now, if you happen to own just a handful of vms, you could easily inspect the vmx file under each and every folder until you strike gold (see Fig.1 right-hand side). If on the other hand you have thousands of vms and scores of datastores to sift through, the task becomes exponentially daunting unless you can script yourself out of it; the subject perhaps for another PowerCLI post.
Despair not. The easiest solution to fixing the vm / folder name mismatch issue is simply to Storage vMotion the vm. This involves migrating the offending vm to a different datastore and back again, assuming you’d want to keep it on the original datastore.
The process of Storage vMotioning automatically renames the vm’s holding folder, and a few files under it, to match that currently assigned to the vm, which brings me to the subject of today’s post. How does one go about automating the process when there are a significant bunch of folders that need fixing other than to migrate each manually?
Yep, you’ve guessed right. It’s yet again time for another PowerShell / PowerCLI script!
The Script
The workflow behind today’s script is as follows. Using get-view, a detailed list of the hosted virtual machines is retrieved. For every virtual machine in the list, a number of vm properties are read. The script then checks if the vm folder matches the vm name. Now, to extract the vm folder I used the VmPathName property, the value of which is returned in the format shown in this next example;
[iSCSI_LUN_B] jason/jason.vmx -> [datastore] vmname/vmname.vmx
To retrieve the vm name, we need to split the string returned using “]” and “/” as delimiters which is achieved by using the Split() method twice. The result returned is an array of three strings, with the second one containing the value we’re after, hence the [1] at the end of the statement; remember that the index of the first element in an array is always 0. The trimstart() method simply removes any white space at the start of the string. This is the statement used (line 42 from the script below listed);
$DSpath = $($_.summary.Config.VmPathName.Split("]").Split("/").trimstart())[1]
If the vm folder name does not match that assigned to the vm, the script first compares the vm’s committed disk space with the amount of free space on the destination datastore and in doing so determines if the vm can be migrated or not. The script will also make sure that the source and destination datastores are not the same.
If all tallies, the user is prompted to type in YES to authorize the migration process, skipping to the next one if otherwise. I’m going to use pseudo-code to outline the basics of the script making reference to the corresponding code lines from the actual script.
Get a list of all VMs from vCenter Server or a host (Line 33) For each vm in the list do (Line 36) Calculate free space on destination datastore (Lines 38-39) Get current vm properties (Lines 42-46) If vm_folder != vm_name then (Line 48) If user chooses to migrate (Lines 61-64) Migrate to temp datastore (Lines 70-76) Migrate back to original datastore end if else skip to next vm (Line 85) End if End do
For the script to work, I’ll be making some assumptions these being;
- availability of a suitably sized datastore (say 100GB) to which vms can be migrated
- the environment is configured and licensed for Storage vMotion
- any affinity rules you may have set up are not taken into account by the script
Very Important: Be careful if you decide to run the script against a vSAN datastore as the witness folders (the ones with the long GUIDs) will be renamed when the vm is migrated back to the vSAN datastore. From the little testing I did, there doesn’t seem to be any repercussions but still, my experience with vSAN in production environments is limited, so you’ve been warned!
The script should be ideally run from with a PowerCLI console window but it will just as well run inside an IDE. Figure 3 shows the script’s output when run from command line.
Demo
I’ve put together the following video to demonstrate how the script works. In the video, I’ll be renaming a set of vms after which I run the script to see if it detects the naming discrepancies and whether it affects the required changes. You’ll also notice that I skip migrating the virtual machine called A just to show that a user has complete control over which vms to migrate. I also switch between vSphere client and Datastore Browser views to verify that folders and files are indeed being correctly renamed.
The Code
# A PowerCLI script that makes use of Storage VMotion to realign the files and folder names on a Datastore with the # name assigned to the virtual machine. # Jason Fenech (Sep '16) #----------------------------------------------------------[Libraries]----------------------------------------------- # Uncomment the 2 lines below if running script using PowerShell (not PowerCLI) # # Import-Module VMware.VimAutomation.Core -ErrorAction:SilentlyContinue # Import-Module VMware.VimAutomation.Storage -ErrorAction:SilentlyContinue #----------------------------------------------------------[Declarations]-------------------------------------------- #Change the following as required #################################################################################### $vCenter="ip address" $DSDest="destination datastore" $DSFreeSpace=0 $user="user" $pass="password" $auto=$true #Uncomment line 62 and comment line 61 to suppress user confirmation #################################################################################### clear #Connect to vCenter Server try{ Disconnect-VIServer * -Force -Confirm:$false -ErrorAction SilentlyContinue Connect-VIServer -Server $vCenter -User $user -Password $pass -ErrorAction Stop | Out-Null } catch{ Write-Host "Failed to connect to vCenter Server $vCenter" exit #Exit script on error } #Get virtual machine view $vms = get-view -viewtype VirtualMachine #Loop $vms | % { #Datastore Free Space $DSFreeSpace=(Get-Datastore -Name $DSDest).FreeSpaceGB $DSFreeSpace=[Math]::Round($DSFreeSpace,3) #Retrieve VM Name, size, DS folder and current DS $DSpath = $($_.summary.Config.VmPathName.Split("]").split("/").trimstart())[1] $VMDS = $_.config.DatastoreUrl.name $VMName = $_.Name $VMSize = ($_.Summary.Storage.Committed) / (1024*1024*1024); $VMSize = [Math]::Round($VMSize,3) if (!$DSpath.equals($VMName)) { Write-Host "-------------------------------------------------------------------------------------------------" -ForegroundColor DarkCyan Write-Host ("VM Name : " + $VMName); Write-Host ("VM Size : " + $VMSize + " GB"); Write-Host ("DS Path : " + $DSpath) -ForegroundColor DarkYellow; if (($VMSize -lt $DSFreeSpace) -and !($VMDS.Equals($DSDest))) #VM must fit on datastore and not reside on destination datastore { Write-Host ("Status : Migration possible (DS:" + $DSFreeSpace + " GB, VM:" + $VMSize + " GB)") -ForegroundColor Green #Let the user choose whether to migrate or not $ans=read-host "`nType YES to migrate" #$ans="YES" if ($ans.ToUpper() -eq "YES") { $DSOrig = $_.config.DatastoreUrl.name Write-Host "Moving vm to DS $DSDest ..." try { Move-VM -VM $VMName -Datastore $DSDest | Out-Null Write-Host "Moving vm back to DS $DSOrig ..." Move-VM -VM $VMName -Datastore $DSOrig | Out-Null #Re-retrieve vm's datastore path $DSpath = (get-vm -Name $VMName).extensiondata.summary.config.VmPathName Write-Host "New DS path is $DSpath" -ForegroundColor DarkYellow; } catch { Write-Host "Unexpected migration error!" exit } } else {Write-Host "Skipping migrating!" -ForegroundColor DarkYellow} } if ($VMSize -ge $DSFreeSpace) #Check if there's enough room on the datastore {Write-Host ("Warning : Not enough free space on DS to migrate vm!") -ForegroundColor Red} if ($VMDS.Equals($DSDest)) #Check if destination and source datastores are the same {Write-Host ("Warning : Cannot migrate vm to same datastore!") -ForegroundColor Red} Write-Host "-------------------------------------------------------------------------------------------------`n" -ForegroundColor DarkCyan } } Write-Host "Finished migrating!"
Conclusion
Once more, we have seen how PowerShell / PowerCLI is used to solve many of the problems you might come across on a regular basis. The script can be improved in a number of ways. For instance, adding something like $_.Name | out-file -Append -FilePath $logFile in the loop block (right after line 49), allows you to output to disk a list of vms with mismatched folder names. The resulting list can be amended as needed if you wish to target only a specific set of vms. The script itself can then be modified to read from the list and scheduled to run, say, after-hours or during low-peak utilization.
Anyway, I hope you’ll find the script useful and if you have any questions just drop me a comment in the box below.
[the_ad id=”4738″][the_ad id=”4796″]
Not a DOJO Member yet?
Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!