Detach and Remove Disk from VM
Simple, annoying task
Those kind I love. Why? Cause I can automate them
Here’s the story - a VM on a Hyper-V host with a bunch of disks, that are no longer needed. Task:
- disable (set to
offline
) - remove from VM configuration
- remove from disk
The hardest part was to map disk number from within OS to disk attached in VM configuration. It seems that Location
from VM configuration maps to LUN number in Location
within the Windows OS. That’s great!
Disclaimer
THIS IS A SCRIPT, NOT A FUNCTION
Bear in mind this is an interactive script that is supposed to be run with caution! Re-check your variables before removing. This is a dirty soltuion to get the task done!
Consider yourself warned!
Let’s get to work
- initialize variables
$Credential = Get-Credential
$VMConnectionProps = @{
ComputerName = 'TestVM' #VMName
}
$HostConnectionProps =@{
ComputerName = 'HyperVHost1' #HyperV Host Name
}
if ($Credential) {
$VMConnectionProps.Credential = $Credential
$HostConnectionProps.Credential = $Credential
}
- using Out-GridView select which disks to process
$disksToDisable = Invoke-Command @VMConnectionProps -ScriptBlock {
Get-Disk | where-object {$null -ne $PSItem.Number }
} | Out-GridView -PassThru
- set disks to
offline
if ($disksToDisable) {
Invoke-Command @VMConnectionProps -ScriptBlock {
foreach ($disk in $USING:disksToDisable) {
Write-Host "Processing with disk - [$($disk.FriendlyName)] to disable."
Set-Disk -InputObject $disk -IsOffline $true
}
}
}
- get vhdx files attached to VM (from VM configuration)
$VMDisks = Invoke-Command @HostConnectionProps -ScriptBlock {
Get-VM -Name $USING:VMConnectionProps.ComputerName | Select-Object -ExpandProperty HardDrives
}
- compare and get final list of disks
$ToDelete= foreach ($diskToDisable in $disksToDisable) {
$VMDisks | Where-Object {$PSItem.ControllerLocation -eq $diskToDisable.Number}
}
- detach disks from VM
foreach ($disk in $ToDelete) {
Write-Host "Processing VM [$($VMConnectionProp.ComputerName)] on Host [$($HostConnectionProps.ComputerName)] - Removing disk [$($disk.ControllerLocation)] with Path [$($disk.Path)]"
Invoke-Command @HostConnectionProps -ScriptBlock {
$removeVMHardDiskDriveSplat = @{
ControllerType = $USING:disk.ControllerType
ControllerNumber = $USING:disk.ControllerNumber
VMName = $USING:VMConnectionProps.ComputerName
ControllerLocation = $USING:disk.controllerLocation
}
Remove-VMHardDiskDrive @removeVMHardDiskDriveSplat
}
}
- remove vhdx from Hyper-V
Invoke-Command @HostConnectionProps -ScriptBlock {
foreach ($disk in $USING:ToDelete) {
Remove-Item -Path $disk.Path
}
}
Full script
Here’s the full script
$Credential = Get-Credential
$VMConnectionProps = @{
ComputerName = 'TestVM' #VMName
}
$HostConnectionProps =@{
ComputerName = 'HyperVHost1' #HyperV Host Name
}
if ($Credential) {
$VMConnectionProps.Credential = $Credential
$HostConnectionProps.Credential = $Credential
}
#Get specifc disks from VM
$disksToDisable = Invoke-Command @VMConnectionProps -ScriptBlock {
Get-Disk | where-object {$null -ne $PSItem.Number }
} | Out-GridView -PassThru
#Set disk to offline
if ($disksToDisable) {
Invoke-Command @VMConnectionProps -ScriptBlock {
foreach ($disk in $USING:disksToDisable) {
Write-Host "Processing with disk - [$($disk.FriendlyName)] to disable."
Set-Disk -InputObject $disk -IsOffline $true
}
}
}
#Get disks attached to VM
$VMDisks = Invoke-Command @HostConnectionProps -ScriptBlock {
Get-VM -Name $USING:VMConnectionProps.ComputerName | Select-Object -ExpandProperty HardDrives
}
#get vhdx to disable and delete
$ToDelete= foreach ($diskToDisable in $disksToDisable) {
$VMDisks | Where-Object {$PSItem.ControllerLocation -eq $diskToDisable.Number}
}
#detach disk from VM
foreach ($disk in $ToDelete) {
Write-Host "Processing VM [$($VMConnectionProp.ComputerName)] on Host [$($HostConnectionProps.ComputerName)] - Removing disk [$($disk.ControllerLocation)] with Path [$($disk.Path)]"
Invoke-Command @HostConnectionProps -ScriptBlock {
$removeVMHardDiskDriveSplat = @{
ControllerType = $USING:disk.ControllerType
ControllerNumber = $USING:disk.ControllerNumber
VMName = $USING:VMConnectionProps.ComputerName
ControllerLocation = $USING:disk.controllerLocation
}
Remove-VMHardDiskDrive @removeVMHardDiskDriveSplat
}
}
#remove vhdx from Hyper-V
Invoke-Command @HostConnectionProps -ScriptBlock {
foreach ($disk in $USING:ToDelete) {
Remove-Item -Path $disk.Path
}
}
Leave a comment