VMware altyapılarında lisans yönetimi özellikle birden fazla VMware ESXi host içeren cluster yapılarında zaman zaman zahmetli bir sürece dönüşebilir.
Yeni bir lisans anahtarına geçiş lisans süresinin dolması ya da kurumsal sözleşme değişiklikleri gibi durumlarda tüm host’ların lisanslarını tek tek güncellemek hem zaman kaybı hem de hata riski oluşturur.
Bu makalemde PowerCLI kullanarak bir cluster içerisindeki tüm ESXi host’ların mevcut lisans anahtarlarını görüntüleyen ve yeni bir lisans anahtarı ile toplu olarak değiştiren bir PowerShell scriptini adım adım inceleyeceğiz.
Manuel olarak vSphere Client üzerinden lisans değiştirmek mümkün olsa da:
- Çok sayıda host varsa işlem uzun sürer
- Yanlış lisans atanma riski vardır
- Standart ve tekrar edilebilir bir yöntem oluşturmak zordur
PowerCLI sayesinde bu süreci:
- Otomatikleştirebilir
- Tekrarlanabilir hale getirebilir
- Merkezi olarak yönetebilirsiniz
Script Ne Yapıyor?
Hazırlanan script şu adımları gerçekleştirir:
- vCenter’a bağlantı kurar,
- Kullanıcıdan hedef vCenter bilgisini ister,
- Mevcut cluster’ları listeler ve seçim yaptırır,
- Seçilen cluster içindeki tüm ESXi host’ların mevcut lisans anahtarlarını gösterir,
- Yeni lisans anahtarını kullanıcıdan ister,
- Tüm host’lara yeni lisansı uygular,
- vCenter bağlantısını kapatır,
Önemli: Yeni lisans anahtarının önceden vCenter’a eklenmiş olması gerekir. Aksi halde işlem başarısız olur.
Script Kodu
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$vcenter = [Microsoft.VisualBasic.Interaction]::InputBox('Enter vCenter Name...', 'vCenter Name')
Connect-VIServer $vcenter
$cluster = Get-Cluster | Out-GridView -OutputMode Single -Title "Select Cluster"
$hosts = Get-Cluster $cluster | Get-VMHost | Sort-Object
foreach ($esxhost in $hosts){
$currentkey = Get-VMHost $esxhost | Select LicenseKey
Write-Host $esxhost License key is currently: $currentkey.LicenseKey -ForegroundColor Green
}
$newlicensekey = [Microsoft.VisualBasic.Interaction]::InputBox('New License Key', 'License Key')
foreach ($esxhost in $hosts){
Set-VMHost -VMHost $esxhost -LicenseKey $newlicensekey
Write-Host $esxhost License key set to $esxhost.LicenseKey -ForegroundColor Green
}
Disconnect-VIServer * -Confirm:$false
Dikkat Edilmesi Gerekenler
- Yeni lisans anahtarının önceden vCenter’a eklenmiş olması gerekir,
- Scripti production ortamında çalıştırmadan önce test ortamında denemeniz önerilir,
- İşlem sırasında yetkili bir hesap kullanmanız gerekir,
- Lisans değişimi sırasında host’ların erişilebilir olması gerekir,
Bu scirt’in log tutan, hata yakalamalı (try/catch), ön kontrol yapan, WhatIf / Confirm destekli, ayrıca eski lisansı kaydedip geri dönüş (rollback) için rapor üreten daha gelişmiş bir sürüm paylaşıyorum.
<#
.SYNOPSIS
Change ESXi License Keys per selected cluster (enhanced).
.DESCRIPTION
- Select vCenter and Cluster
- Shows current license keys
- Validates new key format (basic) and checks it exists in vCenter
- Applies license to all hosts
- Logs everything + exports rollback CSV (host -> old key)
.NOTES
Run in a PowerCLI-enabled PowerShell session.
#>
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param(
[string]$LogDirectory = "$env:USERPROFILE\Documents\PowerCLI-Logs",
[switch]$ExportRollbackCsv = $true
)
# ---------------------------
# Helpers
# ---------------------------
function New-LogFile {
param([string]$Dir)
if (-not (Test-Path $Dir)) { New-Item -Path $Dir -ItemType Directory -Force | Out-Null }
$stamp = Get-Date -Format "yyyyMMdd_HHmmss"
return Join-Path $Dir "Change-EsxiLicense_$stamp.log"
}
function Write-Log {
param(
[Parameter(Mandatory)] [string]$Message,
[ValidateSet("INFO","WARN","ERROR","SUCCESS")] [string]$Level = "INFO"
)
$line = "{0} [{1}] {2}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Level, $Message
Add-Content -Path $script:LogFile -Value $line
switch ($Level) {
"INFO" { Write-Host $line }
"WARN" { Write-Host $line -ForegroundColor Yellow }
"ERROR" { Write-Host $line -ForegroundColor Red }
"SUCCESS" { Write-Host $line -ForegroundColor Green }
}
}
function Test-LicenseKeyFormat {
param([Parameter(Mandatory)][string]$Key)
# VMware keys are commonly 5 blocks of 5 chars like XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
return ($Key -match '^[A-Z0-9]{5}(-[A-Z0-9]{5}){4}$')
}
# ---------------------------
# Start
# ---------------------------
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$script:LogFile = New-LogFile -Dir $LogDirectory
Write-Log "Script started. Log: $LogFile" "INFO"
$vcenter = [Microsoft.VisualBasic.Interaction]::InputBox('Enter vCenter Name or IP...', 'vCenter Name')
if ([string]::IsNullOrWhiteSpace($vcenter)) {
Write-Log "vCenter name not provided. Exiting." "ERROR"
return
}
try {
Write-Log "Connecting to vCenter: $vcenter" "INFO"
Connect-VIServer $vcenter -ErrorAction Stop | Out-Null
Write-Log "Connected to vCenter: $vcenter" "SUCCESS"
}
catch {
Write-Log "Failed to connect to vCenter '$vcenter'. Error: $($_.Exception.Message)" "ERROR"
return
}
try {
$cluster = Get-Cluster -ErrorAction Stop | Out-GridView -OutputMode Single -Title "Select Cluster"
if (-not $cluster) {
Write-Log "No cluster selected. Exiting." "ERROR"
return
}
Write-Log "Selected cluster: $($cluster.Name)" "INFO"
$hosts = Get-Cluster $cluster | Get-VMHost | Sort-Object Name
if (-not $hosts -or $hosts.Count -eq 0) {
Write-Log "No hosts found in cluster '$($cluster.Name)'. Exiting." "ERROR"
return
}
Write-Log "Host count: $($hosts.Count)" "INFO"
}
catch {
Write-Log "Failed to retrieve cluster/hosts. Error: $($_.Exception.Message)" "ERROR"
return
}
# Show current keys and build rollback mapping
$rollback = @()
foreach ($esxhost in $hosts) {
try {
$currentKey = (Get-VMHost -VMHost $esxhost -ErrorAction Stop).LicenseKey
Write-Log "Host '$($esxhost.Name)' current license: $currentKey" "INFO"
$rollback += [pscustomobject]@{
VMHost = $esxhost.Name
OldKey = $currentKey
NewKey = $null
Status = "Pending"
Message = ""
Timestamp = (Get-Date)
}
}
catch {
Write-Log "Could not read license for host '$($esxhost.Name)'. Error: $($_.Exception.Message)" "WARN"
$rollback += [pscustomobject]@{
VMHost = $esxhost.Name
OldKey = $null
NewKey = $null
Status = "ReadFailed"
Message = $_.Exception.Message
Timestamp = (Get-Date)
}
}
}
$newLicenseKey = [Microsoft.VisualBasic.Interaction]::InputBox('New License Key (e.g. XXXXX-XXXXX-XXXXX-XXXXX-XXXXX)', 'License Key')
if ([string]::IsNullOrWhiteSpace($newLicenseKey)) {
Write-Log "New license key not provided. Exiting." "ERROR"
return
}
$newLicenseKey = $newLicenseKey.Trim().ToUpper()
if (-not (Test-LicenseKeyFormat -Key $newLicenseKey)) {
Write-Log "New license key format seems invalid: '$newLicenseKey' (expected XXXXX-...)." "WARN"
Write-Log "Continuing anyway (format check is basic), but verify the key." "WARN"
}
# Verify key exists in vCenter (license inventory)
try {
$licenseMgr = Get-View -Id 'LicenseManager-LicenseManager' -ErrorAction Stop
$knownKeys = @($licenseMgr.Licenses | ForEach-Object { $_.LicenseKey })
if ($knownKeys -notcontains $newLicenseKey) {
Write-Log "The key '$newLicenseKey' is NOT found in vCenter license inventory. Add it to vCenter first." "ERROR"
return
}
Write-Log "Key found in vCenter inventory: $newLicenseKey" "SUCCESS"
}
catch {
Write-Log "Could not validate license key in vCenter. Error: $($_.Exception.Message)" "WARN"
Write-Log "Continuing without inventory validation." "WARN"
}
# Apply license
foreach ($esxhost in $hosts) {
$row = $rollback | Where-Object { $_.VMHost -eq $esxhost.Name } | Select-Object -First 1
if (-not $row) { continue }
$row.NewKey = $newLicenseKey
try {
$target = $esxhost.Name
if ($PSCmdlet.ShouldProcess($target, "Set ESXi license key to $newLicenseKey")) {
Set-VMHost -VMHost $esxhost -LicenseKey $newLicenseKey -ErrorAction Stop | Out-Null
}
$row.Status = "Success"
$row.Message = "License set"
Write-Log "Host '$($esxhost.Name)' license updated to: $newLicenseKey" "SUCCESS"
}
catch {
$row.Status = "Failed"
$row.Message = $_.Exception.Message
Write-Log "FAILED to update host '$($esxhost.Name)'. Error: $($_.Exception.Message)" "ERROR"
}
}
# Export rollback CSV
if ($ExportRollbackCsv) {
try {
$csvPath = [System.IO.Path]::ChangeExtension($LogFile, ".rollback.csv")
$rollback | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
Write-Log "Rollback CSV exported: $csvPath" "SUCCESS"
}
catch {
Write-Log "Could not export rollback CSV. Error: $($_.Exception.Message)" "WARN"
}
}
# Disconnect
try {
Disconnect-VIServer * -Confirm:$false | Out-Null
Write-Log "Disconnected from vCenter." "INFO"
}
catch {
Write-Log "Disconnect warning: $($_.Exception.Message)" "WARN"
}
Write-Log "Script finished." "INFO"
Nasıl Kullanılır?
- Deneme modu (değişiklik yapmadan);
.\Change-EsxiLicense.ps1 -WhatIf
- Gerçek uygulamak;
.\Change-EsxiLicense.ps1
- Onay sorarak ilerlesini;
.\Change-EsxiLicense.ps1 -Confirm
Rollback (Geri Dönüş) Nasıl Yapılır?
Script aynı klasöre .rollback.csv üretir. İçinde her host için OldKey yer alır. İstersen bu CSV’den otomatik rollback yapan mini bir script de yazabilirim.
![[TR] VMware PowerCLI ile VMware ESXi Lisans Anahtarlarını Toplu Olarak Değiştirmek](https://kadirkozan.com/wp-content/uploads/2026/02/VMware-logo-featured-1.jpg)