Browsed by
Category: PowerCLI

Configure scratch location with PowerCLI

Configure scratch location with PowerCLI

I encountered a number of clusters that had /scratch location configured incorrectly, many due to LUN migrations to new storage frames, and some that were never changed from default. For consistent configuration, due to the number of hosts & clusters involved, a script was needed.

I found the following via Google, which appears to be created by fellow vExpert “Virtual NomadAskar Kopbayev:
Automating configuration of a scratch location for ESXi with PowerCLI

I had to tweak just a few things to work for my environment:

# original source by vmnomad -
# modified by @vMiklm - - 19 January 2018
# Example use:
# PS> .\set-scratch.ps1 $vCenter $Cluster $Datastore $Folder
# PS> .\set-scratch.ps1 vcenter.local clusteresx08 SharedNFS01 scratch/clusteresx08

#Collect the vCenter, Cluster, Scratch_datastore & Folder
Param([String]$vCenter, [String]$Cluster, [String]$Datastore, [String]$Folder)

#Function to use multiple colors in one command
function Write-Color([String[]]$Text, [ConsoleColor[]]$Color) {
    for ($i = 0; $i -lt $Text.Length; $i++) {
        Write-Host $Text[$i] -Foreground $Color[$i] -NoNewLine

#defining array variables
$vmhost_array =@()
$dir = @()
$reboot_servers = @()

#Validating input
if (!$vCenter){
  Write-Color  -Text "Please provide valid vCenter name using ","'-vCenter' ","option, exiting.." -Color Gray,Red,Gray

if (!$Cluster){
  Write-Color  -Text "Please provide valid cluster name using ","'-Cluster' ","option, exiting.." -Color Gray,Red,Gray

if (!$Datastore){
  Write-Color  -Text "Please provide valid Datastore name using ","'-Datastore' ","option, exiting.." -Color Gray,Red,Gray

if (!$Folder){
  Write-Color  -Text "Please provide valid scratch folder name using ","'-Folder' ","option, exiting.." -Color Gray,Red,Gray

#Getting the path of the script
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition

#Connecting to vCenter server
Write-Color -Text "`nConnecting to ", $vCenter -Color Gray, Red
Connect-VIserver $vCenter | Out-Null

#Validating connection to vCenter
  Write-Color -Text "`nConnection to ",$vCenter," failed, exiting.." -Color Yellow,Red,Yellow
} elseif($ -ne $vCenter){
    Write-Color -Text "Connected to wrong vCenter ", $ ", exiting.." -Color Yellow,Red,Yellow
  } else {
  Write-Color -Text "Connection to vCenter ", $vCenter, " succeeded" -Color Green,Red,Green

#Getting the list of the ESXi hosts in the $Cluster
$vmhost_array = get-cluster -name $cluster | Get-VMhost

#Mounting datastore to be used as a scratch location
New-PSDrive -Name "DS" -Root \ -PSProvider VimDatastore -Datastore (Get-VMHost -Name $vmhost_array[0] | Get-Datastore $datastore) | out-null
Set-Location DS:\$folder

#Collect the list of the folders
$dir = dir

#Check if the scratch folders exist for the ESXi hosts and create missing folders
Foreach ($vmhost in $vmhost_array)
If ($ -contains ${
  Write-Color -Text "`n Creating scratch folder for ", $vmhost -Color Green,Red
  mkdir $vmhost | out-null

#Getting Scratch datastore [was getting UUID, didn't work, vCenter will convert it anyway -MM]
$dstorep = Get-VMhost $vmhost | Get-Datastore $Datastore

#Check if the ESXi host is already configured with correct scratch location
Foreach ($vmhost in $vmhost_array){
  $row = '' | Select Server_Name
  $configured_scratch = (Get-VMhost $vmhost | Get-AdvancedSetting -Name "ScratchConfig.ConfiguredScratchLocation").value
  $current_scratch = (Get-VMhost $vmhost | Get-AdvancedSetting -Name "ScratchConfig.CurrentScratchLocation").value
  $correct_scratch = "/vmfs/volumes/"+$dstorep+"/"+$folder+"/"+$vmhost
# Write-Host "`n Correct scratch is" $correct_scratch
# Write-Host "`n Configured Scratch on" $vmhost "is" $configured_scratch
# Write-Host "`n Current Scratch on" $vmhost "is" $current_scratch
  If (($configured_scratch -eq $correct_scratch) -and ($current_scratch -eq $correct_scratch)) {
    Write-Color -Text "`n ESXi host ", $vmhost, " was already configured with the correct scratch location" -Color Green,Red,Green
  } elseif($configured_scratch -eq $correct_scratch) {
  Write-Color -Text "`n The ESXi host", $vmhost, " was already configured correctly, `n but it hasn't been restared after the configuration change" -Color Yellow,Red,Yellow
  $row.Server_Name = $vmhost.Name
  $reboot_servers += $row
  } else {
    Get-VMhost $vmhost | Get-AdvancedSetting -Name "ScratchConfig.ConfiguredScratchLocation" | Set-AdvancedSetting -Value "$correct_scratch" -Confirm:$false | out-null
    Write-Host -Fore:Red "`n ESXi host" $vmhost "is configured with the correct scratch location"
    $row.Server_Name = $vmhost.Name
    $reboot_servers += $row

#Provide output with the list of ESXi servers to be rebooted for the configration change to take effect
Write-Host -Fore:Green "`n The configuration of the scratch location for ESXi servers in cluster" $cluster "is complete"
Write-Host -Fore:Green "`n The following ESXi hosts have to be rebooted for the configuration change to take effect:"
foreach ( $server in $reboot_servers ) {
Write-Host -Fore:Red `n $server.Server_Name

#Exporting the list of ESXi hosts to be rebooted
$exportfilename =  "Servers_to_reboot.csv"
$exportfilepath = Join-Path -Path $scriptPath -ChildPath $exportFileName
$reboot_servers | Export-Csv -Path $exportFilePath -NoTypeInformation -Force
Write-Host "`n This list of these servers has also been exported to" $exportfilepath

#Change location back to original
Set-Location $scriptPath


Change vCenter Role for a list of VMs

Change vCenter Role for a list of VMs

Use case: An existing Active Directory group needs to be re-assigned a different Role with more restrictive permissions on a given list of VMs.

Assumption: New (restricted) role has already been created in vCenter. This is to quickly update the list of VMs with an existing Role.

$ADGroup = 'DOMAIN\ADM-VMManagers'
$NewRole = "VMManagers-RestrictedRole"

# Change this variable to the local path to your text list of VMs
$serverList = Get-Content e:\Powershell\RestrictedRoleVMs-list.txt

foreach ($vmName in $serverList) {
    New-VIPermission -Entity $vmName -Principal $ADGroup -Role $NewRole -Propagate:$false -Confirm:$false

To get a list of inventory objects with the new Role assigned:

Get-VIPermission | where { $_.Role -eq 'VMManagers-RestrictedRole' } | Select entity, role, principal

References: [1], [2]

Using PowerShell for VM Snapshot Creation & Cleanup

Using PowerShell for VM Snapshot Creation & Cleanup

There is often a use case for creating snapshots of a list of VMs in a VMware virtual environment. For example, when upgrading vRealize Operations Manager, the documentation recommends taking a snapshot of the VMs in the cluster before upgrading. With a growing number of nodes in our vROps cluster, I finally wrote some PowerShell to automate the snapshot creation and removal process. When shared with my peers in another IT group, they had another use case where they wished to skip any VMs larger than a given size (1 TB in this instance).

 Read a list of VMs from a text file; check disk usage and take snapshot if less than 1 TB
 @vMiklm - 2017-08-08

# vCenter Server name (comma separate for multiple)

# Input :: Change this to the local path to your text list of VMs to check & snapshot
$serverList = Get-Content "e:\temp\vmInputList.txt"

# Output :: Filename for output list of successful snapshot VMs
$outputFile = 'e:\temp\vmOutputList-20170808.txt'

# snapshotName = Descriptive name of Snapshot (includes system date)
$snapshotName = "VM Snapshot - " + $snapshotDate

# snapshotDesc = Description of snapshot including responsible user & delete by date (using system date + 7 days)
$snapshotDesc = "USERNAME - Delete after " + $snapshotDate

# Threshold Size is the maximum size, in GB, of the VMs to snapshot. 1024 GB = 1 TB
$thresholdSize = 1024

$snapshotServerList = @()

foreach ($server in $serverList) 
    # initialize the sum variable to zero
    $diskSizeTotal = 0
    $Disks = Get-HardDisk -VM $server

    foreach($disk in $Disks) 
        $DiskName = $Disk.Name          
        $DisksizeinGB = ($Disk.CapacityKB * 1024)/1GB

        # use this sum variable to keep the running total of disk size in GB

    if ($diskSizeTotal -gt $thresholdSize)
        echo $server" : "$diskSizeTotal" GB is greater than 1 TB. Snapshot skipped"
        echo $server" : "$diskSizeTotal" GB is less than 1 TB."
        # Take Snapshot
        New-Snapshot -VM $server -Name $snapshotName -Description $snapshotDesc
        # Add server to list array of servers with Snapshot taken; this list will be output to file to allow cleanup of snapshots

# Output list of servers that had Snapshot taken; this file should then be used as input for the snapshot cleanup script
foreach ($serverinList in $snapshotServerList) 
    echo $serverinList | Out-File -Append $outputFile

And here’s the accompanying script to remove snapshots when no longer required. Assumption is that the $outputFile from the above “take snapshot” script will be used as input ($serverList) for the “remove snapshot” script below.

   Read a list of VMs from a text file and remove ALL snapshots for listed VMs
   @vMiklm - - 2017-08-08


# Change this to the local path to your list of VMs to remove snapshots
# If used with the above snapshots script, this is same file as $outputFile
$serverList = Get-Content "e:\temp\vmOutputList-20170808.txt"

foreach ($server in $serverList) 
  $snapsList = Get-VM $server | Get-Snapshot
  foreach ($snapshot in $snapsList) 
    Remove-Snapshot $snapshot -Confirm:$false -RunAsync

Code is presented for example, reference, and training. You may have to modify extensively to make any of it work in your environment. I make no claims of being a developer. I have learned what little I know by seeing how others have solved problems in PowerShell (and PHP, C#, etc.), so this is a small effort to contribute back to the community. There are certainly other ways to do this, and likely BETTER ways, but this is what I have made. Feedback & suggestions are welcome in the comments. No support, warranty, guarantee, or anything else is given with any code found on this site. Use at your own risk.

VMware: Multi-NIC vMotion Configuration with PowerShell

VMware: Multi-NIC vMotion Configuration with PowerShell

Changed configuration of numerous VMware clusters to utilize multi-NIC vMotion. As with all my PS, it’s quick & dirty and cobbled from a couple of example scripts. Assumes existing vmkernel port group named “vMotion”

   Configure multi-NIC vMotion
.DESCRIPTION 08/19/2015
   Credit to examples from &

$viserver = "vCenter.local"
$cluster = "CLUSTERNAME"
$vswitchName = "vSwitch1"
$VMotionVLan = "908"
$vSwitch2Nics = "vmnic1","vmnic3"
$VMotionPortGroupName1 = "vMotion-01"
$VMotionPortGroupName2 = "vMotion-02"

Connect-VIServer $viserver

Foreach ($esxhost in (Get-Cluster -name $cluster | Get-VMHost))
  $vswitch = Get-VirtualSwitch -VMHost $esxhost -Name $vswitchName

  # Remove the original "vMotion" VMkernel Port group
  Remove-VMHostNetworkAdapter -Nic (Get-VMHostNetworkAdapter -VMHost $esxhost | where {$_.PortGroupName -eq "vMotion"}) -Confirm:$false
  Remove-VirtualPortGroup -VirtualPortGroup (Get-VirtualPortGroup -Name "vMotion" -vmhost $esxhost) -Confirm:$false

  # Configure virtual switch for Multi-NIC vMotion
  $vportgroup1 = New-VirtualPortGroup -VirtualSwitch $vswitch -Name $VMotionPortGroupName1 -VLanId $VMotionVLan
  $vportgroup2 = New-VirtualPortGroup -VirtualSwitch $vswitch -Name $VMotionPortGroupName2 -VLanId $VMotionVLan

  $vNic1 = New-VMHostNetworkAdapter -VMHost $esxhost -VirtualSwitch $vswitch -PortGroup $vportgroup1 -VMotionEnabled:$true
  $vNic2 = New-VMHostNetworkAdapter -VMHost $esxhost -VirtualSwitch $vswitch -PortGroup $vportgroup2 -VMotionEnabled:$true

  $vportgroup1 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive $vSwitch2Nics[0] -MakeNicStandBy $vSwitch2Nics[1]
  $vportgroup2 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive $vSwitch2Nics[1] -MakeNicStandBy $vSwitch2Nics[0]