PowerShell ile Hyper-V Sanal Makine Yönetimi
Hyper-V ortamlarını GUI üzerinden yönetmek başlangıçta kullanışlı görünse de, onlarca sanal makineyle uğraşmaya başladığınızda fare tıklamalarının ne kadar zaman kaybettirdiğini acı bir şekilde fark ediyorsunuz. PowerShell bu noktada devreye giriyor ve tekrarlayan işlemleri otomatize etmenizi, toplu değişiklikler yapmanızı ve tüm ortamınızı kod üzerinden yönetmenizi sağlıyor. Bu yazıda Hyper-V yönetiminin PowerShell tarafını gerçek dünya senaryolarıyla ele alacağız.
Başlamadan Önce: Ortam Hazırlığı
PowerShell ile Hyper-V yönetmeye başlamadan önce gerekli modülün yüklü olduğundan emin olmanız gerekiyor. Windows Server’da bu modül genellikle Hyper-V rolüyle birlikte geliyor, ancak bazı durumlarda manuel kurulum gerekebiliyor.
# Hyper-V PowerShell modülünü kontrol et
Get-WindowsFeature -Name Hyper-V-PowerShell
# Eksikse yükle (Server Core dahil)
Install-WindowsFeature -Name Hyper-V-PowerShell
# Mevcut Hyper-V komutlarını listele
Get-Command -Module Hyper-V | Measure-Object
Uzak bir Hyper-V sunucusunu yönetecekseniz, WinRM’nin yapılandırılmış olması ve gerekli izinlerin verilmiş olması gerekiyor. Yetkisiz erişim denemelerinde karşılaşacağınız “Access Denied” hataları çoğunlukla bu adımın atlanmasından kaynaklanıyor.
# Uzak sunucuya bağlanarak VM listesini çek
$sunucu = "HYPERV-PROD-01"
Get-VM -ComputerName $sunucu
# Credential ile bağlanma
$cred = Get-Credential
Get-VM -ComputerName $sunucu -Credential $cred
Sanal Makine Listeleme ve Durum Kontrolü
Günlük operasyonlarda en sık kullandığım komutlardan biri Get-VM. Basit görünse de filtreleme özellikleriyle oldukça güçlü bir araç.
# Tüm VM'leri listele
Get-VM
# Sadece çalışan VM'leri göster
Get-VM | Where-Object {$_.State -eq "Running"}
# Belirli bir VM'nin detaylarını gör
Get-VM -Name "WebServer-01" | Format-List *
# CPU ve Memory kullanımını göster
Get-VM | Select-Object Name, State,
@{N="CPU(%)";E={$_.CPUUsage}},
@{N="RAM(MB)";E={$_.MemoryAssigned/1MB}} |
Format-Table -AutoSize
# Birden fazla host üzerindeki tüm VM'leri toplu sorgula
$hostlar = @("HYPERV-01", "HYPERV-02", "HYPERV-03")
Get-VM -ComputerName $hostlar |
Select-Object ComputerName, Name, State, CPUUsage |
Sort-Object ComputerName, Name
Ürün ortamında birden fazla Hyper-V node’unuz varsa ve hepsinin durumunu tek seferde görmek istiyorsanız, bu toplu sorgulama yaklaşımı hayat kurtarıyor. Ben bunu sabah rutinimin bir parçası olarak otomatik çalıştırıyorum.
Sanal Makine Oluşturma
Yeni bir VM oluşturmak için New-VM komutunu kullanıyoruz. Asgari parametrelerle çalışabilse de, prodüksiyon ortamında her şeyi açıkça belirtmek iyi bir alışkanlık.
# Temel VM oluşturma
New-VM -Name "AppServer-05" `
-MemoryStartupBytes 4GB `
-Generation 2 `
-Path "D:VirtualMachines" `
-NewVHDPath "D:VirtualMachinesAppServer-05AppServer-05.vhdx" `
-NewVHDSizeBytes 80GB `
-SwitchName "External-Switch"
# VM oluşturduktan sonra ek yapılandırma
$vmName = "AppServer-05"
# CPU sayısını ayarla
Set-VM -Name $vmName -ProcessorCount 4
# Dynamic Memory yapılandır
Set-VMMemory -VMName $vmName `
-DynamicMemoryEnabled $true `
-MinimumBytes 2GB `
-StartupBytes 4GB `
-MaximumBytes 16GB
# DVD sürücüsüne ISO bağla
Add-VMDvdDrive -VMName $vmName
Set-VMDvdDrive -VMName $vmName `
-Path "C:ISOsWindows_Server_2022.iso"
# VM'i başlat
Start-VM -Name $vmName
Write-Host "$vmName başarıyla oluşturuldu ve başlatıldı." -ForegroundColor Green
Bu akışı bir şablon haline getirip, farklı VM tipleri için parametre dosyaları oluşturmak oldukça pratik. Özellikle aynı konfigürasyonda onlarca VM deploy etmeniz gerektiğinde bu yaklaşım saatlerce zaman kazandırıyor.
Snapshot (Checkpoint) Yönetimi
Snapshot yönetimi Hyper-V ortamlarında kritik bir konu. Doğru kullanıldığında çok değerli, yanlış kullanıldığında disk alanını hızla tüketen bir özellik.
# Belirli bir VM için snapshot oluştur
$vmName = "WebServer-01"
$snapshotAdi = "Guncelleme_Oncesi_$(Get-Date -Format 'yyyyMMdd_HHmm')"
Checkpoint-VM -Name $vmName -SnapshotName $snapshotAdi
Write-Host "Checkpoint oluşturuldu: $snapshotAdi"
# Tüm snapshot'ları listele
Get-VMSnapshot -VMName $vmName |
Select-Object Name, CreationTime, ParentSnapshotName |
Format-Table -AutoSize
# Belirli bir snapshot'a geri dön
$hedefSnapshot = Get-VMSnapshot -VMName $vmName -Name "Guncelleme_Oncesi_20241115_0930"
Restore-VMSnapshot -VMSnapshot $hedefSnapshot -Confirm:$false
# Eski snapshot'ları temizle (30 günden eski olanlar)
$eskiSnapshots = Get-VMSnapshot -VMName $vmName |
Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-30)}
foreach ($snapshot in $eskiSnapshots) {
Write-Host "Siliniyor: $($snapshot.Name) - $($snapshot.CreationTime)"
Remove-VMSnapshot -VMSnapshot $snapshot -Confirm:$false
}
Gerçek dünya notu: Prod ortamında snapshot temizleme işlemini tam olarak anlamamış junior ekip üyeleri bazen tüm snapshot zincirini silip VM’i bozabiliyor. Script’e onay mekanizması eklemek veya sadece belirli bir yaşın üzerindeki snapshot’ları hedeflemek bu riski azaltıyor.
Disk Yönetimi
Sanal disklerin yönetimi sysadmin hayatının önemli bir parçası. Disk ekleme, boyutlandırma ve VHD/VHDX dönüşümleri gibi işlemleri PowerShell ile kolayca halledebilirsiniz.
# VM'e yeni disk ekle
$vmName = "DBServer-01"
$diskYolu = "E:VirtualMachinesDBServer-01Data_Disk.vhdx"
# Yeni VHDX oluştur
New-VHD -Path $diskYolu -SizeBytes 500GB -Dynamic
# VM'e bağla
Add-VMHardDiskDrive -VMName $vmName `
-Path $diskYolu `
-ControllerType SCSI
# Mevcut diskleri listele
Get-VMHardDiskDrive -VMName $vmName |
Select-Object Name, Path, ControllerType, ControllerNumber, ControllerLocation
# Disk boyutunu genişlet (VM kapalıyken veya çevrimiçi genişletme için)
$vhd = Get-VHD -Path $diskYolu
Write-Host "Mevcut boyut: $([math]::Round($vhd.Size/1GB, 2)) GB"
Resize-VHD -Path $diskYolu -SizeBytes 1TB
Write-Host "Yeni boyut: $([math]::Round((Get-VHD -Path $diskYolu).Size/1GB, 2)) GB"
# VHD dosyasının gerçek kullanımını kontrol et
Get-VHD -Path $diskYolu | Select-Object Path,
@{N="Boyut(GB)";E={[math]::Round($_.Size/1GB,2)}},
@{N="KullanilanAlan(GB)";E={[math]::Round($_.FileSize/1GB,2)}},
VhdFormat, VhdType
Ağ Yapılandırması
Virtual Switch ve Network Adapter yönetimi, özellikle VLAN segmentasyonu yapıyorsanız, dikkat gerektiren bir alan.
# Mevcut Virtual Switch'leri listele
Get-VMSwitch | Select-Object Name, SwitchType, NetAdapterInterfaceDescription
# Yeni External Switch oluştur
New-VMSwitch -Name "Prod-External" `
-NetAdapterName "Ethernet0" `
-AllowManagementOS $true
# Internal switch oluştur (lab ortamları için ideal)
New-VMSwitch -Name "Lab-Internal" -SwitchType Internal
# VM'e network adapter ekle
Add-VMNetworkAdapter -VMName "WebServer-01" `
-SwitchName "Prod-External" `
-Name "Management-NIC"
# VLAN yapılandırması
Set-VMNetworkAdapterVlan -VMName "WebServer-01" `
-VMNetworkAdapterName "Management-NIC" `
-Access `
-VlanId 100
# Bandwidth limiti ayarla (Mbps cinsinden, bytes/saniye olarak girilmeli)
Set-VMNetworkAdapter -VMName "WebServer-01" `
-Name "Management-NIC" `
-MaximumBandwidth 1000000000 # 1 Gbps
# Tüm VM'lerin network adapter bilgilerini toplu çek
Get-VM | ForEach-Object {
$vm = $_
Get-VMNetworkAdapter -VMName $vm.Name |
Select-Object @{N="VM";E={$vm.Name}},
Name, SwitchName, MacAddress,
@{N="IP";E={$_.IPAddresses -join ", "}}
} | Format-Table -AutoSize
Toplu VM Yönetimi – Gerçek Dünya Senaryosu
Bir güncelleme penceresi öncesinde tüm VM’lerin snapshot alınması, güncellemeler bittikten sonra snapshot’ların temizlenmesi gibi senaryolar oldukça yaygın. Bu tür operasyonlar için hazır scriptler bulundurmak sizi büyük bir kalabalıktan kurtarır.
# Güncelleme öncesi toplu snapshot scripti
param(
[Parameter(Mandatory=$true)]
[string]$ComputerName,
[string]$SnapshotPrefix = "PreUpdate",
[switch]$ExcludeOff
)
$tarih = Get-Date -Format "yyyyMMdd_HHmm"
$log = @()
try {
$vmler = Get-VM -ComputerName $ComputerName
if ($ExcludeOff) {
$vmler = $vmler | Where-Object {$_.State -eq "Running"}
Write-Host "Sadece çalışan VM'ler hedefleniyor: $($vmler.Count) adet" -ForegroundColor Yellow
}
foreach ($vm in $vmler) {
$snapshotAdi = "${SnapshotPrefix}_${tarih}"
try {
Checkpoint-VM -Name $vm.Name `
-ComputerName $ComputerName `
-SnapshotName $snapshotAdi `
-ErrorAction Stop
$log += [PSCustomObject]@{
VM = $vm.Name
Snapshot = $snapshotAdi
Durum = "Basarili"
Zaman = Get-Date
}
Write-Host "OK: $($vm.Name)" -ForegroundColor Green
}
catch {
$log += [PSCustomObject]@{
VM = $vm.Name
Snapshot = "N/A"
Durum = "HATA: $_"
Zaman = Get-Date
}
Write-Host "HATA: $($vm.Name) - $_" -ForegroundColor Red
}
}
}
finally {
# Log dosyasına yaz
$logDosyasi = "C:LogsVMSnapshot_$tarih.csv"
$log | Export-Csv -Path $logDosyasi -NoTypeInformation -Encoding UTF8
Write-Host "`nLog kaydedildi: $logDosyasi" -ForegroundColor Cyan
# Özet
$basarili = ($log | Where-Object {$_.Durum -eq "Basarili"}).Count
$hatali = ($log | Where-Object {$_.Durum -ne "Basarili"}).Count
Write-Host "`nÖzet - Basarili: $basarili | Hatali: $hatali"
}
Bu scripti çalıştırmak için:
# Basit kullanım
.TopluSnapshot.ps1 -ComputerName "HYPERV-PROD-01"
# Sadece çalışan VM'ler için
.TopluSnapshot.ps1 -ComputerName "HYPERV-PROD-01" -ExcludeOff -SnapshotPrefix "Pazar_Bakimi"
VM Live Migration
Cluster ortamında VM’leri node’lar arasında taşımak hem bakım penceresi yönetimi hem de load balancing için gerekiyor.
# Tek VM'i başka host'a taşı (Live Migration)
Move-VM -Name "WebServer-01" `
-DestinationHost "HYPERV-02" `
-IncludeStorage `
-DestinationStoragePath "D:VirtualMachines"
# Bir host üzerindeki tüm VM'leri başka bir host'a taşı
# (bakım modu için ideal)
$kaynak = "HYPERV-01"
$hedef = "HYPERV-02"
$vmler = Get-VM -ComputerName $kaynak | Where-Object {$_.State -eq "Running"}
Write-Host "$kaynak üzerinde $($vmler.Count) çalışan VM bulundu."
foreach ($vm in $vmler) {
Write-Host "Tasiniyor: $($vm.Name)..." -NoNewline
try {
Move-VM -Name $vm.Name `
-ComputerName $kaynak `
-DestinationHost $hedef `
-ErrorAction Stop
Write-Host " TAMAM" -ForegroundColor Green
}
catch {
Write-Host " HATA: $_" -ForegroundColor Red
}
}
Dikkat: IncludeStorage parametresi diskleri de taşıdığı için network üzerinde ciddi yük oluşturabilir. Sadece cluster shared storage kullanıyorsanız bu parametreye gerek yok.
Performans İzleme
Hangi VM’in kaynak tükettiğini bulmak, kapasite planlaması için kritik bilgi sağlıyor.
# Anlık performans görüntüsü
function Get-VMPerformans {
param(
[string]$ComputerName = $env:COMPUTERNAME,
[int]$OrnekSayisi = 5,
[int]$AralikSaniye = 2
)
$sonuclar = @()
for ($i = 1; $i -le $OrnekSayisi; $i++) {
Write-Progress -Activity "Performans verisi toplanıyor" `
-Status "Örnek $i / $OrnekSayisi" `
-PercentComplete (($i/$OrnekSayisi)*100)
$vmler = Get-VM -ComputerName $ComputerName |
Where-Object {$_.State -eq "Running"}
foreach ($vm in $vmler) {
$sonuclar += [PSCustomObject]@{
Zaman = Get-Date
VM = $vm.Name
CPU_Yuzde = $vm.CPUUsage
RAM_MB = [math]::Round($vm.MemoryAssigned/1MB, 0)
Durum = $vm.State
}
}
if ($i -lt $OrnekSayisi) { Start-Sleep -Seconds $AralikSaniye }
}
# Ortalama değerleri hesapla
$sonuclar | Group-Object VM | ForEach-Object {
[PSCustomObject]@{
VM = $_.Name
OrtCPU = [math]::Round(($_.Group.CPU_Yuzde | Measure-Object -Average).Average, 2)
MaxCPU = ($_.Group.CPU_Yuzde | Measure-Object -Maximum).Maximum
OrtRAM_MB = [math]::Round(($_.Group.RAM_MB | Measure-Object -Average).Average, 0)
}
} | Sort-Object OrtCPU -Descending
}
# Fonksiyonu çalıştır
Get-VMPerformans -ComputerName "HYPERV-PROD-01" -OrnekSayisi 10 -AralikSaniye 3 |
Format-Table -AutoSize
Yedekleme Entegrasyonu
Hyper-V’de export işlemi basit bir yedekleme yöntemi olarak kullanılabilir. Kritik VM’ler için düzenli export almak en kötü senaryolarda bile size bir geri dönüş noktası sağlıyor.
# VM Export script'i
param(
[string]$VMName,
[string]$ExportYolu = "\NAS-01BackupsHyper-V",
[int]$SaklamaGunu = 7
)
$tarih = Get-Date -Format "yyyyMMdd"
$hedefDizin = Join-Path $ExportYolu "$VMName$tarih"
# Dizin oluştur
if (-not (Test-Path $hedefDizin)) {
New-Item -Path $hedefDizin -ItemType Directory -Force | Out-Null
}
Write-Host "Export başlıyor: $VMName -> $hedefDizin"
$baslangic = Get-Date
try {
Export-VM -Name $VMName -Path $hedefDizin -ErrorAction Stop
$sure = (Get-Date) - $baslangic
$boyut = (Get-ChildItem $hedefDizin -Recurse |
Measure-Object -Property Length -Sum).Sum
Write-Host "Export tamamlandi!" -ForegroundColor Green
Write-Host "Sure: $([math]::Round($sure.TotalMinutes, 1)) dakika"
Write-Host "Boyut: $([math]::Round($boyut/1GB, 2)) GB"
}
catch {
Write-Host "Export HATASI: $_" -ForegroundColor Red
exit 1
}
# Eski yedekleri temizle
$eskiYedekler = Get-ChildItem (Join-Path $ExportYolu $VMName) -Directory |
Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-$SaklamaGunu)}
foreach ($eski in $eskiYedekler) {
Write-Host "Eski yedek siliniyor: $($eski.Name)"
Remove-Item $eski.FullName -Recurse -Force
}
Faydalı Parametreler ve Komutlar
Günlük kullanımda işe yarayan bazı ek komutlar:
Stop-VM -Name "VM" -Force: VM’i zorla kapatır, misafir OS’u beklemezSuspend-VM -Name "VM": VM’i RAM’i koruyarak duraklatarResume-VM -Name "VM": Duraklatılmış VM’i devam ettirirGet-VMIntegrationService -VMName "VM": Integration Services durumunu gösterirEnable-VMIntegrationService -VMName "VM" -Name "Guest Service Interface": Belirli bir servis aktif ederCompare-VM: VM’i başka bir host’a import etmeden önce uyumluluk kontrol ederMeasure-VM -VMName "VM": Resource Metering verilerini çeker (aktifse)Set-VMProcessor -VMName "VM" -CompatibilityForMigrationEnabled $true: Migration için CPU uyumluluğunu etkinleştirir
Sonuç
PowerShell ile Hyper-V yönetimi, başlangıçta birkaç basit komut öğrenmekle başlasa da zamanla tüm altyapınızı kod olarak yönetebileceğiniz bir noktaya ulaşıyor. Günlük operasyonlarda zaman kazanmak, insan hatalarını azaltmak ve tekrarlanabilir süreçler oluşturmak için bu araçları kullanmak artık opsiyonel değil, zorunlu.
En önemli tavsiyem, küçük başlamak. Önce Get-VM ile ortamınızı keşfedin, sonra basit otomasyonlar yazın. Zamanla snapshot yönetimi, migration ve yedekleme gibi kritik işlemleri de script’lerinize ekleyebilirsiniz. Tüm script’lerinizi versiyon kontrolüne (Git) alın ve production’da test etmeden önce mutlaka lab ortamında deneyin.
Herhangi bir sorunla karşılaşırsanız Get-Help -Full ile kapsamlı dokümantasyona ulaşabilirsiniz. Hyper-V modülünün Microsoft tarafından sürekli güncellenen resmi dokümantasyonu da her zaman güvenilir bir kaynak olmaya devam ediyor.
