Hyper-V

Convert Dynamic VHDX to Fixed VHDX

function Convert-VMDisksToFixed {
    param (
        [Parameter(Mandatory)]
        [string]$VMName,

        [Parameter(Mandatory)]
        [array]$Disks  # Her disk için @{Old="..." ; New="..."}
    )

    # VM SID bul
    try {
        $vmId = (Get-VM $VMName).Id.Guid
        $vmSid = "NT VIRTUAL MACHINE\$vmId"
    } catch {
        Write-Error "❌ VM '$VMName' bulunamadı."
        return
    }

    foreach ($disk in $Disks) {
        $oldPath = $disk.Old
        $newPath = $disk.New

        if (-not (Test-Path $oldPath)) {
            Write-Warning "⚠️ Disk bulunamadı: $oldPath"
            continue
        }

        $vhdInfo = Get-VHD -Path $oldPath

        if ($vhdInfo.VhdType -ne 'Fixed') {
            Write-Host "`n🔄 Converting to fixed: $oldPath -> $newPath"
            Convert-VHD -Path $oldPath -DestinationPath $newPath -VHDType Fixed -ErrorAction Stop
            Remove-Item -Path $oldPath -Force
        } else {
            Write-Host "`n🔁 Already fixed: Renaming $oldPath -> $newPath"
            Rename-Item -Path $oldPath -NewName (Split-Path $newPath -Leaf)
        }

        # NTFS izinlerini ayarla
        try {
            $acl = Get-Acl $newPath
            $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($vmSid, "FullControl", "Allow")
            $acl.AddAccessRule($accessRule)
            Set-Acl -Path $newPath -AclObject $acl
            Write-Host "✅ NTFS izinleri eklendi: $vmSid → $newPath"
        } catch {
            Write-Warning "❌ İzin ayarlanamadı: $newPath - $_"
        }
    }

    Write-Host "`n🎯 İşlem tamamlandı."
}

Usage

$vmName = "VM01"
$disks = @(
    @{Old="E:\HYPERV\VM01\SomeDynamicDisk1.vhdx"; New="E:\HYPERV\VM01\VM01-C-DRIVE.vhdx"},
    @{Old="E:\HYPERV\VM01\SomeFixedDisk1.vhdx"; New="E:\HYPERV\VM01\VM01-D-DRIVE.vhdx"},
    @{Old="E:\HYPERV\VM01\SomeDynamicDisk2.vhdx"; New="E:\HYPERV\VM01\VM01-E-DRIVE.vhdx"}
)

Convert-VMDisksToFixed -VMName $vmName -Disks $disks

Find&Move Orphand Virtual Hard Disk Files

function Find-AndMoveUnusedVHDs {
    param(
        [string]$SearchPath = "E:\HYPERV",
        [string]$MoveFolder = "E:\HYPERV\Orphans",
        [bool]$MoveStaledVMs = $false,
        [string]$LogFolder = "C:\Logs"
    )

    if (-not (Test-Path $SearchPath)) {
        Write-Error "Search path does not exist: $SearchPath"
        return
    }

    if (-not (Test-Path $LogFolder)) {
        New-Item -Path $LogFolder -ItemType Directory | Out-Null
    }

    $LogPath = Join-Path -Path $LogFolder -ChildPath "MovedVHDs_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
    New-Item -Path $LogPath -ItemType File -Force | Out-Null

    $usedDisks = Get-VM | Get-VMHardDiskDrive | Select-Object -ExpandProperty Path
    $vhdFiles = Get-ChildItem -Path $SearchPath -Recurse -Include *.vhd, *.vhdx -ErrorAction SilentlyContinue

    foreach ($file in $vhdFiles) {
        if ($usedDisks -notcontains $file.FullName) {
            Write-Host "Unused disk found: $($file.FullName)"

            if ($MoveStaledVMs) {
                if (-not (Test-Path $MoveFolder)) {
                    New-Item -Path $MoveFolder -ItemType Directory | Out-Null
                }

                $destinationBase = Join-Path -Path $MoveFolder -ChildPath $file.Name
                $destination = $destinationBase
                $i = 1

                while (Test-Path $destination) {
                    $destination = Join-Path -Path $MoveFolder -ChildPath ("$($file.BaseName)_$i$($file.Extension)")
                    $i++
                }

                Move-Item -Path $file.FullName -Destination $destination -Force

                $logLine = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] MOVED: '$($file.FullName)' => '$destination' | Last Modified: $($file.LastWriteTime)"
                Add-Content -Path $LogPath -Value $logLine
                Write-Host $logLine -ForegroundColor Green
            }
        }
    }

    Write-Host "İşlem tamamlandı. Log dosyası: $LogPath" -ForegroundColor Cyan
}

Usage

Find-AndMoveUnusedVHDs -SearchPath "E:\HYPERV" -MoveStaledVMs $true -MoveFolder "E:\HYPERV\Orphans" -LogFolder "C:\Logs"

Grant-VMVhdPermission

function Grant-VMVhdPermission {
    param (
        [Parameter(Mandatory)]
        [string]$VMName,

        [Parameter(Mandatory)]
        [string]$DiskPath
    )

    # Get VM SID
    try {
        $vmId = (Get-VM $VMName).Id.Guid
        $vmSid = "NT VIRTUAL MACHINE\$vmId"
    } catch {
        Write-Error "❌ Failed to find the VM '$VMName'."
        return
    }

    if (-not (Test-Path $DiskPath)) {
        Write-Error "❌ Disk path does not exist: $DiskPath"
        return
    }

    try {
        $acl = Get-Acl $DiskPath
        $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($vmSid, "FullControl", "Allow")
        $acl.AddAccessRule($accessRule)
        Set-Acl -Path $DiskPath -AclObject $acl

        Write-Host "✅ Permission successfully granted: $vmSid → $DiskPath"
    } catch {
        Write-Warning "❌ Error while setting permissions: $_"
    }
}

Usage

Grant-VMVhdPermission -VMName "VM01" -DiskPath "E:\HYPERV\VM01\VM01-C-DRIVE.vhdx"

Last updated