VMware Cloud Community
klich
Enthusiast
Enthusiast

PowerCLI Script to Backup all VMX files

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..)

Tags (3)
10 Replies
RvdNieuwendijk
Leadership
Leadership

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

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
Reply
0 Kudos
klich
Enthusiast
Enthusiast

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.

Reply
0 Kudos
klich
Enthusiast
Enthusiast

I've added quite a bit of functionality.  Please share back any improvements you make.

  • Handles multiple vCenter servers
  • Saves nvram and vmx files to a clean folder structure
  • Automatically prunes files older than X days
  • Creates a summary configuration text file, with core configuration details of the VM
    • Number of CPU's
    • VM Path Location
    • RAM Size
    • VM Version
    • Hard drive(s) sizes

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!

Reply
0 Kudos
jambocool
Contributor
Contributor

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 " + $datasto
ount + " " + [math]::round(($i/ <<<< $datastores.Count*100),1) + "%") -percentcomplete ($i/$datastores.Count*100)
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException


Any advise? Im a bit stuck?

klich
Enthusiast
Enthusiast

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.

Reply
0 Kudos
klich
Enthusiast
Enthusiast

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.

Reply
0 Kudos
cfizz34vmware
Enthusiast
Enthusiast

I had to change the syntax to get mine to work -

$Destination = 'c:\temp'

Reply
0 Kudos
Karnickel25
Contributor
Contributor

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?

Reply
0 Kudos
John_yang
Contributor
Contributor

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

Reply
0 Kudos
piercj2
Enthusiast
Enthusiast

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