Backup All ESXi Configurations with VMware PowerCLI

Rebuilding a ESXi host can take a long time especially if you have a complicated environment. VMware uses Host Profiles however this feature is all the way at the top of the licensing with Enterprise Plus. There is an alternative if you know a little Powershell and install VMware’s PowerCLI you can use Powershell style command to interact with VMware vCenter.

This script simply gets each ESXi host from the vCenter server and then runs the backup configuration command against it. This will generate a file for each of your ESXi servers that can be restored using the Set-VMHostFirmware command in PowerCLI. This script requires that VMware PowerCLI is installed on the workstation where it is executed. It will prompt you for credentials to login on the vCenter server at the beginning of execution. Be sure to update the $vCenter variable with your vCenter address.


# This script initiates VMware PowerCLI
. "C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Scripts\Initialize-PowerCLIEnvironment.ps1"
# Specify vCenter Server, vCenter Server prompts for username and vCenter Server user password

# Get local execution path
$localpath = Get-Location

Write-Host "Connecting to vCenter Server $vCenter" -foreground green
Connect-viserver $vCenter -WarningAction 0

# Get list of all ESXi hosts known by vCenter
$AllVMHosts =  Get-VMHost

ForEach ($VMHost in $AllVMHosts)
    Write-Host " "
    Write-Host "Backing Up Host Configuration: $VMHost" -foreground green
    Get-VMHostFirmware -VMHost $VMHost -BackupConfiguration -DestinationPath $localpath

Write-Host "Files Saved to: $localpath";
Write-Host "Press any key to close ..."

Console Output

D:\Powershell\vSphere> & '.\Backup All ESXi Configurations.ps1'
          Welcome to the VMware vSphere PowerCLI!

Log in to a vCenter Server or ESX host:              Connect-VIServer
To find out what commands are available, type:       Get-VICommand
To show searchable help for all PowerCLI commands:   Get-PowerCLIHelp
Once you've connected, display all virtual machines: Get-VM
If you need more help, visit the PowerCLI community: Get-PowerCLICommunity

       Copyright (C) 1998-2012 VMware, Inc. All rights reserved.

Connecting to vCenter Server vcenter.domain.local

Name                           Port  User
----                           ----  ----
vcenter.domain.local                 443   root

Backing Up Host Configuration: vmhost-1.domain.local

Url  : http://vmhost-1.domain.local/downloads/configBundle-vmhost-1.domain.local.tgz
Data : D:\Powershell\vSphere\configBundle-vmhost-1.domain.local.tgz
Host : vmhost-1.domain.local

Backing Up Host Configuration: vmhost-2.domain.local

Url  : http://vmhost-2.domain.local/downloads/configBundle-vmhost-2.domain.local.tgz
Data : D:\Powershell\vSphere\configBundle-vmhost-2.domain.local.tgz
Host : vmhost-2.domain.local

Backing Up Host Configuration: vmhost-3.domain.local

Url  : http://vmhost-3.domain.local/downloads/configBundle-vmhost-3.domain.local.tgz
Data : D:\Powershell\vSphere\configBundle-vmhost-3.domain.local.tgz
Host : vmhost-3.domain.local

Files Saved to: D:\Powershell\vSphere

Press any key to close ...


Read More

Create DPM Backup List using Powershell

Our auditors were curious about what exactly our Microsoft Data Protection Manager server was backing up. So I did a bit of digging around in the DPM powershell commandlet and came up with this little command.


get-dpmdatasource | where {$_.Protected -eq "True"} | select productionservername, name, objecttype, protectiongroupname | Sort-Object productionservername, name | export-csv dpmserver-backup-list.csv

The CSV is rather basic but provides a nice easy list with enough detail to know what exactly is being backed up on each of the servers. Good luck keeping the auditors happy.

CSV output

ProductionServerName			Name				ObjectType					ProtectionGroupName	master				SQL Server 2008 database	SQL Data	model				SQL Server 2008 database	SQL Data	msdb				SQL Server 2008 database	SQL Data	PaperData			SQL Server 2008 database	SQL Data			C:\					Volume						Domain Controllers			System Protection	System Protection			Domain Controllers			C:\					Volume						Domain Controllers			System Protection	System Protection			Domain Controllers	Administration		Storage group				Exchange Databases	Developers			Storage group				Exchange Databases	Helpdesk			Storage group				Exchange Databases	Other				Storage group				Exchange Databases	Test				Storage group				Exchange Databases		HAData				SQL Server 2012 database	SQL Cluster Data		Test				SQL Server 2012 database	SQL Cluster Data

Read More

Use Powershell to Batch Convert Videos using Handbrake

I recently downloaded a large amount of training video from the good old interweb, but they were all in the awful WMV format. After playing around with Handbrake a bit I knew it was the tool for the job, however it will not recursively add folders to its encoding queue and with several hundred videos nested a few layers deep I wasn’t about to add all of them by hand.

So opened up notepad and got to work writing some code to query the file system for all the WMV in a specific folder and any sub folders and then queue them up to pass into HandbrakeCLI. It also does a nice clean header and tracks progress so you can estimate how long it might have to go. It will just place the new converted file in the same folder as the current one. You will want to adjust the HandBrakeCLI arguments to encode your video with the quality and settings you desire, these are pretty aggressive and mostly to save space while re-encoding video created with screen capture software.


$filelist = Get-ChildItem D:\Video\ -filter *.wmv -recurse

$num = $filelist | measure
$filecount = $num.count

$i = 0;
ForEach ($file in $filelist)
    $oldfile = $file.DirectoryName + "\" + $file.BaseName + $file.Extension;
    $newfile = $file.DirectoryName + "\" + $file.BaseName + ".mp4";
    $progress = ($i / $filecount) * 100
    $progress = [Math]::Round($progress,2)

    Write-Host -------------------------------------------------------------------------------
    Write-Host Handbrake Batch Encoding 
    Write-Host "Processing - $oldfile"
    Write-Host "File $i of $filecount - $progress%"
    Write-Host -------------------------------------------------------------------------------
    Start-Process "C:\Program Files\HandBrake\HandBrakeCLI.exe" -ArgumentList "-i `"$oldfile`" -t 1 --angle 1 -c 1 -o `"$newfile`" -f mp4  -O  --decomb --modulus 16 -e x264 -q 32 --vfr -a 1 -E lame -6 dpl2 -R Auto -B 48 -D 0 --gain 0 --audio-fallback ffac3 --x264-preset=veryslow  --x264-profile=high  --x264-tune=`"animation`"  --h264-level=`"4.1`"  --verbose=0" -Wait -NoNewWindow

Console Output

Handbrake Batch Encoding
Processing - D:\Video\subfolder\Installing IIS on Windows Server Core.wmv
File 10 of 100 - 10.00%
HandBrake 0.9.9 (2013052900) - MinGW x86_64 -
8 CPUs detected
Opening D:\Video\subfolder\Installing IIS on Windows Server Core.wmv...
libbluray/bdnav/index_parse.c:162: indx_parse(): error opening D:\Video\subfolde
r\Installing IIS on Windows Server Core.wmv/BDMV/index.bdmv
libbluray/bdnav/index_parse.c:162: indx_parse(): error opening D:\Video\subfolde
r\Installing IIS on Windows Server Core.wmv/BDMV/BACKUP/index.bdmv
libbluray/bluray.c:1725: nav_get_title_list(D:\Video\subfolder\Installing IIS on
 Windows Server Core.wmv) failed (000000000035D900)
libdvdnav: Using dvdnav version 4.1.3
libdvdread: Encrypted DVD support unavailable.
libdvdnav:DVDOpenFileUDF:UDFFindFile /VIDEO_TS/VIDEO_TS.IFO failed
libdvdnav:DVDOpenFileUDF:UDFFindFile /VIDEO_TS/VIDEO_TS.BUP failed
libdvdread: Can't open file VIDEO_TS.IFO.
libdvdnav: vm: failed to read VIDEO_TS.IFO
Input #0, asf, from 'D:\Video\subfolder\Installing IIS on Windows Server Core.wmv':
    title           : Video1
    artist          : 
    WMFSDKVersion   : 11.0.5721.5251
    WMFSDKNeeded    :
    IsVBR           : 1
    VBR Peak        : 1437
    Buffer Average  : 1077
  Duration: 00:57:33.22, start: 0.000000, bitrate: 135 kb/s
    Stream #0.0(eng): Audio: wmav2, 44100 Hz, 1 channels, fltp, 48 kb/s
    Stream #0.1(eng): Video: wmv3 (Main), yuv420p, 800x600, 74 kb/s, 15 fps, 15
tbr, 1k tbn
Scanning title 1 of 1, preview 10, 100.00 %+ title 1:
  + stream: D:\Video\subfolder\Installing IIS on Windows Server Core.wmv
  + duration: 00:57:33
  + size: 800x600, pixel aspect: 1/1, display aspect: 1.33, 15.000 fps
  + autocrop: 0/0/0/0
  + chapters:
    + 1: cells 0->0, 0 blocks, duration 00:57:33
  + audio tracks:
    + 1, English (wmav2) (1.0 ch) (iso639-2: eng)
  + subtitle tracks:
x264 [warning]: --psnr used with psy on: results will be invalid!
x264 [warning]: --tune psnr should be used if attempting to benchmark psnr!
x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.1 Cache64
x264 [info]: profile High, level 4.1
Encoding: task 1 of 1, 52.54 % (80.50 fps, avg 83.86 fps, ETA 00h04m53s))

Read More

Audit Windows Network Settings with Powershell

We have been consolidating IT groups at the university for several years now. During this time we have to convert both clients and servers to use our central division Active Directory and other centralized services. However gathering all of the networking information can be quite the task and prone to error. One of the easiest ways I have found to gather all of this information is by running a script to generate CSV file of these settings.

I used this existing script I found over on and took it a few steps further.

I added that ability to query Active Directory and find all the computers within an OU and the ability to adjust the filter. This can be handy if you want to find just windows servers or windows clients or just plain windows. I also fixed the output for multiple DNS servers or gateways to a CSV file as well as added some standard header and footers to make the screen output a bit cleaner. This script does require you to have the Active Directory Powershell Module Installed. It will save the CSV to the local directory from which the script is executed and report the path at the end of the screen output. This script should be run with a highly privileged user as it will need to query multiple remote computer using WMI and access Active Directory.


Import-Module ActiveDirectory

$localpath = Get-Location;
$CSVFileName = $localpath.Path + "\Department-Network-Information.csv";

$ComputerName = Get-ADComputer -SearchBase "OU=Department,OU=Division,DC=domain,DC=local" -Filter {OperatingSystem -Like "Windows*"} -Property "Name";

$Results = @()

foreach ($Computer in $ComputerName)
    if(Test-Connection -ComputerName $Computer.Name -Count 1 -ea 0) 
        $Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computer.Name | ? {$_.IPEnabled};
        foreach ($Network in $Networks) 
            $IPAddress  = $Network.IpAddress[0];
            $SubnetMask  = $Network.IPSubnet[0];
            $DefaultGateway = $Network.DefaultIPGateway;
            $DNSServers  = $Network.DNSServerSearchOrder;
            $IsDHCPEnabled = $false;
                $IsDHCPEnabled = $true;
            $MACAddress  = $Network.MACAddress;

            if ($DNSServers) 
                $StringDNSServers = [string]::join("; ",$DNSServers);
                $StringDNSServers = " ";

                $StringDefaultGateway = [string]::join("; ",$DefaultGateway);
                $StringDefaultGateway = " ";

            $ReturnedObj = New-Object -Type PSObject;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.Name.ToUpper();
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name IPAddress -Value $IPAddress;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name SubnetMask -Value $SubnetMask;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name Gateway -Value $StringDefaultGateway;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name IsDHCPEnabled -Value $IsDHCPEnabled;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name DNSServers -Value $StringDNSServers;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name MACAddress -Value $MACAddress;
            $Results += $ReturnedObj;

$Results | export-csv $CSVFileName -notype;

Write-Host "File Saved to: $CSVFileName";
Write-Host "Press any key to close ..."

Screen Output Example

ComputerName  : Computer1
IPAddress     :
SubnetMask    :
Gateway       :
IsDHCPEnabled : True
DNSServers    :;
MACAddress    : 18:13:73:2A:98:FA

ComputerName  : Computer2
IPAddress     :
SubnetMask    :
Gateway       :
IsDHCPEnabled : True
DNSServers    :;
MACAddress    : F8:B1:56:AC:FB:2E

File Saved to: D:\Powershell-Scripts\Department-Network-Information.csv

Press any key to close ...

CSV Output


Read More

Powershell File Sharing Permissions Report

Often I am asked to verify folder permissions for a user in a specific place out on one of our servers. Typically this requires browsing out the folder and putting eyes on the permissions dialog box looking for a group on which the user is a member and then documenting it in the ticket. A very painful long boring process. This is where Powershell comes and saves the day. I wrote a very simple script to bring that information to me. It also gives nice output that I can directly copy into tickets to answer what groups has rights to what shares.

This prompts the user to “Enter a UNC Path” once entered goes and grabs the NTFS permissions as well as the SMB Share permissions

Powershell Code


$path = Read-host “Enter a UNC Path: ”
$pathparts = $path.split("\")
$ComputerName = $pathparts[2]
$ShareName = $pathparts[3]

Write-Host "File Sharing Permissions Report - $path"

$acl = Get-Acl $path

Write-Host "File/NTFS Permissions"

foreach($accessRule in $acl.Access)
    Write-Host "   " $accessRule.IdentityReference $accessRule.FileSystemRights
Write-Host "Share/SMB Permissions"

    $Share = Get-WmiObject win32_LogicalShareSecuritySetting -Filter "name='$ShareName'" -ComputerName $ComputerName
        $obj = @()
        $ACLS = $Share.GetSecurityDescriptor().Descriptor.DACL
        foreach($ACL in $ACLS){
            $User = $ACL.Trustee.Name
            if(!($user)){$user = $ACL.Trustee.SID}
            $Domain = $ACL.Trustee.Domain
                2032127 {$Perm = "Full Control"}
                1245631 {$Perm = "Change"}
                1179817 {$Perm = "Read"}
            Write-Host "   $Domain\$user  $Perm"

Example Output


Enter a UNC Path: : \\filesrv\Working Groups
File Sharing Permissions Report - \\filesrv\Working Groups

File/NTFS Permissions

    BUILTIN\Administrators FullControl
    DOMAIN\Domain Admins FullControl
    DOMAIN\Domain Users ReadAndExecute, Synchronize
    DOMAIN\Folder - File Server Admins FullControl

Share/SMB Permissions

   DOMAIN\Domain Admins  Full Control
   DOMAIN\Domain Users  Full Control

Read More