I recognize there was a post similar to this already that was closed as a duplicate - unfortunatly the referenced thread duplicate is inactive and doesn't actually provide the solution. Searching high and low, I have not found a script example that accomplishes this.
Unfortunately our current backup deployment is only capable of working from within the Guest OS, so we are looking to augment that backup solution with one that picks up the vmx file, and the sizes of the vmdk file (there is a useful post of this), to an archive location that will be used for backup / recovery operations. Effectively so we can recreate the empty VMs in a recovery operation, without loss of the VM UUID, mac address, etc...
Would anybody have an example of a script of this capability?
- Backup all vmx files (and optionally nvram files) for each VM to a centralized location
- Log the VM VMDK size(s) and associated datastore location to a file in that same directory (bonus if we can use that file in conjunction with vmkfstools to recreate the vmdk files)
- Place each VM's files into a seperate directory (it would be a very nice bonus if this would replicate the vCenter inventory folder tree when it was saved)
vcenter\datacenter\cluster\vmname
Extra items that "would be nice"
- Automatically prune off files from VMs that no longer exist
- Script recreation and re-registering of the VMs (with some method of scope limiting method - regex, folder, cluster, etc..)
I don't have answers to all of your questions yet. But I will give you the ones that I can provide quick.
First the script to backup all the vmx files to one location. This version copies all the vmx files into the same folder. Because it contains square brackets and the forum software has problems with them, I will also attach the script to this post.
$Destination = c:\temp Get-VM | ` Get-View | ` ForEach-Object { $vmxfile = $_.Config.Files.VmPathName $dsname = $vmxfile.split(" ")[0].TrimStart("") $ds = Get-Datastore -Name $dsname New-PSDrive -Name ds -PSProvider VimDatastore -Root '/' -Location $ds Copy-DatastoreItem -Item "ds:\$($vmxfile.split(']')[1].TrimStart(' '))" -Destination $Destination Remove-PSDrive -Name ds }
To automatically prune off files from VM's that no longer exist you could empty the folder where you copy the vmx files into before you start the copy script.
For a script to register vmx file you should take a look at Luc's blogpost Raiders of the Lost VMX.
Regards, Robert
That is a great start. I'll see if I can add in some of the other functionality, and post it back to this thread.
I've added quite a bit of functionality. Please share back any improvements you make.
This can be setup to run via a Windows scheduled task.
Example: Script located in c:\powershell
RUN = c:\winnt\system32\windowspowershell\v1.0\powershell.exe -nologo -file "c:\powershell\backup-vm-files-v2.ps1"
Start in = c:\powershell
Run as = domain\user (utilize a user account here that has privileges to the vmware infrastructure you wish to protect)
Enjoy!
Great work klich!
Script works great on our internal network, however on a clients network that much smaller I am getting some errors?
On the client network, they only have one Datastore (which is local) and I am getting the following error when trying to run the script:
Attempted to divide by zero.At C:\powershell\backup-vm-files-v2.ps1:58 char:140+ write-progress -activity "Mounting datastores for $CleanDatacenterName" -status ("$i of " + $datastoount + " " + [math]::round(($i/ <<<< $datastores.Count*100),1) + "%") -percentcomplete ($i/$datastores.Count*100)+ CategoryInfo : NotSpecified: (:) [], RuntimeException+ FullyQualifiedErrorId : RuntimeException
Any advise? Im a bit stuck?
Sorry, switched companies, and it took awhile to get all of my account / profile moved over.
I don't recall ever testing it for a single datastore configuration. I'll review the code and take a look to see if there are any obvious issues.
I filter out backups for local datastores by default, since the environment this was designed for does not use any local storage.
This is the line that defines the datastores, and per the code-comment, make sure you remove the filter for the local datastores.
original line:
# Create PS Drives for Datacenter
$datastores = Get-Datastore -Datacenter $_ | Where-Object {$_.Name -notlike "*storage1*" -and $_.Name -notlike "local_*"} # filter out local vmfs volumes -- we don't run any on local disk, remove the filter if you do
with local datastore filter removed:
# Create PS Drives for Datacenter
$datastores = Get-Datastore -Datacenter $_ # filter out local vmfs volumes -- we don't run any on local disk, remove the filter if you do
Also, the script expect to be running against vCenter, or certain calls like 'Get-Datastore -Datacenter' will not function. These could be modified to work for a single / non-vCenter managed host if needed.
I had to change the syntax to get mine to work -
$Destination = 'c:\temp'
I thank you for script, maybe you are still active reading this post after several years. I would like to copy additionally the virtual disk descriptor files for backup and at the moment a little bit lost in the powershell syntax.
I think it should be not so hard to extend the script but I need some help in coding. Someone here who can help me?
Get-VM | `
Get-View | `
ForEach-Object {
$vmxfile = $_.Config.Files.VmPathName
$dsname = $vmxfile.split(" ")[0]
$ds_name = $dsname.Substring(1,$dsname.Length-2)
$ds = Get-Datastore -Name $ds_name
New-PSDrive -Name ds -PSProvider VimDatastore -Root '/' -Location $ds
Copy-DatastoreItem -Item "ds:\$($vmxfile.split(']')[1].TrimStart(' '))" -Destination $Destination
Remove-PSDrive -Name ds
}
verified on vsphere 6.7 u2 and powercli 11
I found the following in this forum in the past, should hopefully work for you to backup the .vmx files
foreach($Computer in $content){
$view = Get-View -ViewType VirtualMachine -Filter @{"Name"=$Computer.name}
$vmxfile = $view.Config.Files.VmPathName
$dsname = $vmxfile.split(" ")[0].TrimStart("[").TrimEnd("]")
$ds = Get-Datastore -Name $dsname
New-PSDrive -Name ds -PSProvider VimDatastore -Root '/' -Location $ds
Copy-DatastoreItem -Item "ds:\$($vmxfile.split(']')[1].TrimStart(' '))" -Destination $VmxBackupFolder
Remove-PSDrive -Name ds
}
to get the vmdk sizes, try something like
$report=@()
foreach($Computer in $content){
$hdd = 1
$Computer | Get-HardDisk | foreach {
$GeneralProp.Add("HDD$($hdd) Name",$_.Name)
$GeneralProp.Add("HDD$($hdd) Datastore",$_.FileName.split(" ")[0].TrimStart("[").TrimEnd("]"))
$GeneralProp.Add("HDD$($hdd) Path",$_.FileName.split(" ")[1].TrimStart("[").TrimEnd("]"))
$GeneralProp.Add("HDD$($hdd) Capacity",$_.CapacityGb)
$dsname = $_.Filename.split(" ")[0].TrimStart("[").TrimEnd("]")
$DataStoreReport += $_ | Add-Member -MemberType NoteProperty -Name DatastoreName -Value $dsname -PassThru
$hdd++
}
$report += New-Object -TypeName psobject -Property $GeneralProp
}
$report |
Sort-Object -Property {($_ | Get-Member -MemberType NoteProperty).Count } -Descending |
Export-Csv $outputfile -NoTypeInformation