December 30, 2024 | Leave a comment Have you ever stared down the barrel of endless repetitive clicks in VMware vSphere, knowing you’re in for hours of mindless work? Recently, I faced a scenario where I needed to update hundreds of virtual NICs across just as many virtual machines. Manual changes would have been soul-crushing, so I turned to VMware PowerCLI and transformed this monotonous task into a 5-minute automated script. Here’s how I did it. The Problem: Manual Network Changes Are Soul-Crushing Picture this: You have dozens, maybe hundreds, of VMs, each with multiple network adapters needing reassignment to a new distributed port group. The manual process looks something like this: Open each VM’s settings. Click through every network adapter. Select the new network. Wait for the change to apply. Repeat until your will to live fades. The task was not just time-consuming but error-prone. I knew there had to be a better way. Enter PowerCLI: Your New Best Friend PowerCLI is VMware’s powerful scripting toolkit that supercharges PowerShell to manage your VMware environment programmatically. Here’s how to get started: Installing PowerCLI Open PowerShell as Administrator and run: Install-Module -Name VMware.PowerCLI -Scope CurrentUser Accept the prompts, and voilà! You’re ready to automate. The Journey to Automation Nirvana My path to automating network changes wasn’t without its hiccups. Let me walk you through the evolution of my approach. First Attempt: The Naive Approach Initially, I wrote a script to update only “unassigned” network adapters. Logical, right? Wrong. What PowerCLI considered “unassigned” didn’t always match what I saw in the vSphere UI. Second Try: The Brute Force Method I decided to reassign all the adapters, regardless of their current state. While functional, this approach overwhelmed vCenter, leading to failed operations. Final Solution: The Smart Approach The breakthrough came with a more intelligent script that: Validates host state before making changes. Introduces delays between operations to keep vCenter happy. Includes robust error handling and logging. Verifies changes to ensure accuracy. The Magic Script That Does It All Here’s the polished script that saved the day: <# .SYNOPSIS This script connects to vCenter, finds all VMs matching specific criteria, and assigns unassigned virtual NICs to a specified Distributed Port Group. .DESCRIPTION 1. Connects to vCenter Server. 2. Searches for VMs in "Datacenter Immaculate Constellation" -> "DELL-R720-CLUSTER" -> Host "192.168.88.5". 3. Filters only VMs that are powered off. 4. Assigns all empty NICs to "TRUNK-space-holder-Arista-DPort-Group". 5. Prints progress and errors to the console. .NOTES Tested with PowerCLI 12+ on vCenter 8. #> # ---[ 1. Setup and Connect to vCenter ]--- Write-Host "Starting script..." # Enable PowerCLI logging $logPath = Join-Path $PSScriptRoot "powercli_log.txt" Write-Host "Enabling PowerCLI logging to: $logPath" Set-PowerCLIConfiguration -Scope User -LogLevel Warning -InvalidCertificateAction Ignore -Confirm:$false | Out-Null Start-Transcript -Path $logPath -Force Write-Host "Connecting to vCenter..." try { # Update with your vCenter server name and credentials Connect-VIServer -Server "vcenterserver.dc1.local" -User "YOUR_USERNAME" -Password "YOUR_PASSWORD" Write-Host "Successfully connected to vCenter." } catch { Write-Host "ERROR: Failed to connect to vCenter. Error details:" Write-Host $_ return } # ---[ 2. Locate the Datacenter, Cluster, and Host ]--- Write-Host "Locating Datacenter, Cluster, and Host..." try { $datacenterName = "Datacenter Carlton II" $clusterName = "DELL-R720-CLUSTER" $hostName = "192.168.88.5" # Get the Datacenter object $dc = Get-Datacenter -Name $datacenterName -ErrorAction Stop # Get the Cluster object in that Datacenter $cluster = Get-Cluster -Name $clusterName -Location $dc -ErrorAction Stop # Get the Host object in that Cluster $vmHost = Get-VMHost -Name $hostName -Location $cluster -ErrorAction Stop Write-Host "Datacenter found: $($dc.Name)" Write-Host "Cluster found: $($cluster.Name)" Write-Host "Target Host found: $($vmHost.Name)" # Double check we're working with the correct host if ($vmHost.Name -ne $hostName) { Write-Host "ERROR: Retrieved host does not match target host name" -ForegroundColor Red Disconnect-VIServer -Confirm:$false return } Write-Host "`nWARNING: This script will only process VMs on host $hostName" -ForegroundColor Yellow Write-Host "Other hosts in the cluster will not be affected`n" # Get all hosts in cluster for reference $allHosts = Get-VMHost -Location $cluster Write-Host "Hosts in cluster $($cluster.Name):" foreach ($h in $allHosts) { if ($h.Name -eq $hostName) { Write-Host " * $($h.Name) (TARGET HOST)" -ForegroundColor Yellow } else { Write-Host " - $($h.Name) (will not be modified)" } } Write-Host "" # Check host state Write-Host "`nChecking host state..." Write-Host "Host State: $($vmHost.State)" Write-Host "Host Connection State: $($vmHost.ConnectionState)" Write-Host "Host Power State: $($vmHost.PowerState)" if ($vmHost.State -ne "Connected" -or $vmHost.ConnectionState -ne "Connected") { throw "Host is not in a valid state for network operations. Current state: $($vmHost.State), Connection state: $($vmHost.ConnectionState)" } } catch { Write-Host "ERROR: Unable to locate Datacenter, Cluster, or Host. Error details:" Write-Host $_ Disconnect-VIServer -Confirm:$false return } # ---[ 3. Find All Matching VMs ]--- Write-Host "Searching for powered-off VMs..." try { $vmList = Get-VM -Location $vmHost | Where-Object { $_.PowerState -eq "PoweredOff" } if (!$vmList) { Write-Host "No powered-off VMs found on host '$hostName'." return } else { Write-Host "Found the following powered-off VMs on host '$hostName':" $vmList | ForEach-Object { Write-Host " - $($_.Name)" } # ---[ 4. Assign Each Unassigned NIC to the Specified DPort Group ]--- $dportGroup = Get-VDPortgroup -Name "TRUNK-space-holder-Arista-DPort-Group" -ErrorAction Stop if (!$dportGroup) { Write-Host "ERROR: Could not find distributed port group 'TRUNK-space-holder-Arista-DPort-Group'" -ForegroundColor Red return } Write-Host "`nFound distributed port group: $($dportGroup.Name)" -ForegroundColor Green Write-Host "Port group key: $($dportGroup.Key)`n" -ForegroundColor Green foreach ($vm in $vmList) { Write-Host "`nProcessing VM: $($vm.Name)" -ForegroundColor Yellow # Get all network adapters for the VM $nics = Get-NetworkAdapter -VM $vm Write-Host " Found $($nics.Count) network adapter(s)" foreach ($nic in $nics) { Write-Host "`n Processing NIC: $($nic.Name)" Write-Host " Current Network: [$($nic.NetworkName)]" try { # Check host state again before each operation $hostState = Get-VMHost -Name $hostName if ($hostState.State -ne "Connected" -or $hostState.ConnectionState -ne "Connected") { throw "Host is not in a valid state for network operations. Current state: $($hostState.State), Connection state: $($hostState.ConnectionState)" } # First remove the network assignment Write-Host " Removing current network assignment..." -ForegroundColor Yellow $nic | Set-NetworkAdapter -NetworkName "" -Confirm:$false -ErrorAction Stop Start-Sleep -Seconds 2 # Wait 2 seconds between operations # Then assign the new network Write-Host " Assigning to '$($dportGroup.Name)'..." -ForegroundColor Yellow $nic | Set-NetworkAdapter -Portgroup $dportGroup -Confirm:$false -ErrorAction Stop Start-Sleep -Seconds 2 # Wait 2 seconds after assignment # Verify the change $updatedNic = Get-NetworkAdapter -VM $vm | Where-Object { $_.Id -eq $nic.Id } Write-Host " New Network Assignment: [$($updatedNic.NetworkName)]" -ForegroundColor Green } catch { Write-Host " ERROR: Failed to update network. Error details:" -ForegroundColor Red Write-Host " $_" -ForegroundColor Red Write-Host " Host State at time of error: $($hostState.State)" Write-Host " Host Connection State at time of error: $($hostState.ConnectionState)" continue # Continue with next NIC instead of stopping } } # Wait 5 seconds between VMs to avoid overwhelming vCenter Write-Host "`n Waiting 5 seconds before processing next VM..." -ForegroundColor Blue Start-Sleep -Seconds 5 } } } catch { Write-Host "ERROR: An issue occurred while searching for or updating VMs. Error details:" Write-Host $_ -ForegroundColor Red } # ---[ 5. Cleanup / Disconnect from vCenter ]--- try { Write-Host "`nDisconnecting from vCenter..." Disconnect-VIServer -Confirm:$false Write-Host "Script completed." } catch { Write-Host "ERROR: Could not disconnect from vCenter properly. Error details:" Write-Host $_ -ForegroundColor Red } finally { # Stop logging Stop-Transcript } How It Works 1. Initial Setup and Safety The script enables logging and ignores certificate warnings for seamless execution. 2. Smart Host State Validation It checks that the host is ready for changes, avoiding issues with disconnected or powered-off hosts. 3. Careful Network Changes Network adapters are reassigned with delays to prevent overwhelming vCenter. 4. Robust Verification Each change is verified to ensure it was applied successfully. Results: Time Saved, Sanity Preserved Here’s the math: 50 VMs with 3 NICs each = 150 changes Manual time: ~2–3 hours Script time: ~5 minutes Errors: Zero Bonus: I actually enjoyed a coffee break while the script ran. Pro Tips From the Trenches Always validate host state – Ensure the host is connected and ready. Introduce delays – Prevent vCenter from throwing errors due to rapid requests. Log everything – You’ll thank yourself later. Verify changes – Mistakes happen, but not on your watch. Graceful error handling – Scripts should recover from unexpected issues. Ready to Try It Yourself? Here’s how to get started: Install PowerCLI and connect to your vCenter. Copy the script and update the connection details. Run it. Enjoy your newfound free time. Conclusion PowerCLI isn’t just a tool—it’s a superpower for VMware administrators. Automating repetitive tasks not only saves time but also reduces errors, giving you more bandwidth for meaningful work. Have you automated any VMware tasks with PowerCLI? Share your stories in the comments—I’d love to hear how you’re making VMware work smarter, not harder! Happy scripting! 🚀 Share this:FacebookTwitterPrintLinkedInMoreXLike this:Like Loading... Related