Posted On December 23, 2019

PowerShell: Moving Virtual Machines & Expanding Disk Volumes in Hyper-V & Microsoft Failover Clusters

kimconnect 0 comments
blog.KimConnect.com >> Codes >> PowerShell: Moving Virtual Machines & Expanding Disk Volumes in Hyper-V & Microsoft Failover Clusters

Sample VM Migation Plan (time window = 3 hours):

Pre-emptively resolve disks merging errors prior to migrating VM, then expand C:\ volume after migration
1. Gracefully shutdown VM (5 minutes)
2. Make a file-level copy backup of VM (5 to 60 minutes)
3. Export to Interim Storage and Import VM at New Storage Destination (5 to 60 minutes minutes)
4. Resize C:\ volume (5 minutes)
5. Perform Validation (20 minutes)
a. Success – no further actions
b. Failure – unregister VM > re-register VM from backup > re-validate (20 minutes)

###############################################################################################################
# Hyper-V-Move-VM.ps1
# Assumption: Hyper-V has been setup with Microsoft Failover Cluster
###############################################################################################################

# Set variables
$windowsName="CONCU.intranet.kimconnect.com"
$sourceVmName="CONCU";
$interimDestination="C:\ClusterStorage\Volume1\VHD";
$finalDestination="C:\ClusterStorage\Volume1\VHD";
$targetClusterName="HYPERV-CLUSTER01"
$resizeDiskIndex=0;
$resizeVolumeLetter="C";
$resizeTo="160GB";
$backupSourceFolder="C:\ClusterStorage\Volume2\VHD\CONCU"
$backupDestinationFolder="C:\ClusterStorage\Volume2\VHD\CONCU-BACKUP"

# Function to Create Template
# Need to add feature to check whether target cluster node has access to the $destinationFolder
function exportVM{
param(
$sourceVmName="Windows 2016 Template",
$destinationFolder="C:\ClusterStorage\Volume1\VHD"
)

# Remove all snapshots prior to performing disks expansion
try {
Get-VMSnapshot -VMName $sourceVmName | %{Remove-VMSnapshot -VMName $sourceVmName -Name $_.Name}
}
catch{
write-host "$Error`r`nUnable to remove all snapshots. Aborting Remove-VMSnapshot commands."
break;
}

# Gather source volumes
$sourceVolumes=(get-vm $sourceVmName | select -expand HardDrives).Path

# Calculate volume sizes
$totalSize=0;
$sourceVolumes|%{$totalSize+=(get-item $_).Length}
$totalSizeInGB=$totalSize/1GB

# Perform export
try{
$exportDuration=Measure-Command {Export-VM -Name $sourceVmName -Path $destinationFolder}
$exportHours=[math]::round($exportDuration.TotalHours,2);
$gbPerHour=[math]::round($totalSizeInGB/$exportHours,2);
write-host "$sourceVmName has been exported to $destinationFolder at the speed of $gbPerHour GB/Hour ($totalSizeInGB GB in $exportHours hours)";
return $true
}catch{
return $false
}
}

# Helper functions
function addVmToCluster{
param($vmName="Windows 2016 Template")
if(get-cluster -ea SilentlyContinue){Add-ClusterVirtualMachineRole -VirtualMachine $vmName}else{write-host "No clusters found."}
}

function removeVmFromCluster{
param($vmName="Windows 2016 Template")
$clusterName=(get-cluster -ea SilentlyContinue).Name
if($clusterName){
try{
Remove-ClusterGroup -VMId (Get-VM -Name $vmName).VMId -RemoveResources -Force;
write-host "$vmName has been removed from the cluster $clusterName";
}catch{
write-host $Error
}
}else{write-host "No clusters found."}
}

function moveItemToRecycleBin{
param($item="C:\Temp\helloworld.py")
Add-Type -AssemblyName Microsoft.VisualBasic
$itemType=(get-item $item).Attributes
switch ($itemType){
"Directory" {[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteDirectory("$item",'OnlyErrorDialogs','SendToRecycleBin')}
"Archive" {[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile("$item",'OnlyErrorDialogs','SendToRecycleBin')}
}

<#
$shell = new-object -comobject "Shell.Application"
$item = $shell.Namespace(0).ParseName("$path")
$item.InvokeVerb("delete")
#>
}

# Function to gracefully shutdown remote computer
function gracefulShutdown{
param(
$windowsName,
$vmName
)
# Enable VMIntegration for Shutdown Commands
function ensureVMIntegrationForShutdown{
param($vmName)
# Ensure that the VM Integration Service for Shutdown method was enabled
$vmIntegrationShutdownEnabled=(Get-VMIntegrationService -VMName $vmName | ?{$_.Name -eq "Shutdown"}).Enabled
if (!($vmIntegrationShutdownEnabled)){Enable-VMIntegrationService -VMName $vmName -Name "Shutdown"}
}

# Ping computer, retry until wait-time expires
function pingHostUntilDown{
param($computername="localhost",$waitTime=300)
$t=0;
write-host "Pinging $ComputerName"
do {
$hostIsPingable=if(Test-Connection $ComputerName -Count 1 -Delay 1 -ErrorAction SilentlyContinue){$true}else{$false}
if($hostIsPingable){
write-host -nonewline ".";
$t+=5;
sleep 5;
}
}while ($hostIsPingable -or $t -gt $waitTime)

if($hostIsPingable){return $true}else{return $false}
}

function pingTest{
Param([string]$node)
try{
Return Test-Connection $node -Count 1 -Quiet -ea Stop;
}
catch{Return $False}
}

function enableRemoteWinRM{
Param([string]$computername)

Write-Host "checking $computername..."

if (pingTest $computername){
if (!(Test-WSMan $computername -ea SilentlyContinue)){
if(!(get-command psexec)){
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
}
choco install sysinternals -y
}
psexec.exe \\$computername -s C:\Windows\system32\winrm.cmd qc -quiet
}else{Write-Host "WinRM has been already enabled. No changes to WinRM have been made."}
}
Else{Write-Host "Unable to determine if WinRM is enabled on $computername`.`n Ping test has failed. Check if this computer is online and whether there's a firewall blocking of ICMP";}
}

# function to connect to remote machine and execute commands
function connectWinRmToShutdown{
param($remoteComputer)
do{
$session = New-PSSession -ComputerName $RemoteComputer
"Connecting to remote computer $computer..."
sleep -seconds 5
if ($session){"Connected."}
} until ($session.state -match "Opened")

invoke-command -session $session -scriptblock{
# Gracefully stop SQL if it is present
Get-service *SQL* | Where-Object {$_.status -eq "Running"} | Stop-Service -Force
#force in this context will enable the process to shutdown dependent services prior to stopping the target service

# Gracefully stop Exchange if it is present
$exchangeServices=Get-Service | Where-Object {$_.DisplayName –like "Microsoft Exchange *"};
if($exchangeServices){
net stop msexchangeadtopology /y;
net stop msexchangefba /y;
net stop msftesql-exchange /y;
net stop msexchangeis /y;
net stop msexchangesa /y;
net stop iisadmin /y;
net stop w3svc /y;
$exchangeServices | Stop-Service -Force;
}

# Finally shutdown the OS via Windows native method
Stop-Computer $env:computername -Force
}
$pingResult=pingHostUntilDown -computername $RemoteComputer -waitTime 300
if ($pingResult){write-host "$RemoteComputer is still online.";break}else{write-host "$RemoteComputer is now offline."}
}

# Attempt to connect to remote machine via WinRM
try{
ensureVMIntegrationForShutdown -vmName $vmName
if (pingTest $windowsName){
enableRemoteWinRM -computername $windowsName
connectWinRmToShutdown -remoteComputer $windowsName
if((get-vm $vmName).Status -eq "Running"){stop-vm -Name $vmName -Force -ErrorAction SilentlyContinue;} #shutdown VM in case it is still online; #shutdown VM in case it is still online
}else{
write-host "$windowsName is currently unpingable. Considering it as already shut down.";
if((get-vm $vmName).Status -eq "Running"){stop-vm -Name $vmName -Force -ErrorAction SilentlyContinue;}
}
}catch{
write-host $Error;
break;
}
}

# Function to Clone from Template
# Future feature not currently available: Import to new destination with a new VM name and GUID
# importVM -vmName $sourceVmName -sourceDirectory $interimDestination -destinationDirectory $finalDestination;
function importVm{
param(
$vmName="Windows 2016 Template",
$sourceDirectory="C:\ClusterStorage\Volume1\VHD",
$destinationDirectory="C:\ClusterStorage\Volume1\VHD"
)

# Sanity checks
# Verify whether source VM already exists in Hyper-V
$vmExists=get-vm $vmName -ErrorAction SilentlyContinue
if ($vmExists){
write-host "Cannot import $vmName because it already exists.";
break;
}
# Verify whether Interim destination and Final Destination are the same, and whether the destination node has access to Final Destination
$sameSourceAndDestination=$sourceDirectory -eq $destinationDirectory

# Gather source volumes
$sourceVolumes=(get-item "$sourceDirectory\$vmName\Virtual Hard Disks\*.vhdx").FullName

# Calculate volume sizes
$totalSize=0;
$sourceVolumes|%{$totalSize+=(get-item $_).Length}
$totalSizeInGB=$totalSize/1GB

# Use this import sequence when Source Directory and Destination Directory are the same
$vmcxFile=(get-item "$sourceDirectory\$vmName\Virtual Machines\*.vmcx").FullName
if (!($vmcxFile)){
write-host "Cannot import $vmName because a VMCX file does not exist at '$destinationFolder\$vmName\Virtual Machines\'";
break;
}else{
$importDuration=Measure-Command {
if($sameSourceAndDestination){
# Use this import sequence when Source Directory and Destination Directory are the same
Import-VM -Path "$vmcxFile";
}else{
# Use this import sequence when Source Directory and Destination Directory are different
Import-VM -Path "$vmcxFile" -Copy -GenerateNewId;
}
addVMToCluster -vmName $vmName;
}
$importHours=[math]::round($importDuration.TotalHours,2)
$gbPerHour=[math]::round($totalSizeInGB/$importHours,2)
write-host "$vmName has been imported to $destinationDirectory\$vmName at the speed of $gbPerHour GB/Hour ($totalSizeInGB GB in $importHours hours)"
if(!($sameSourceAndDestination)){write-host "`r`nRecommendation: clean up $sourceDirectory\$vmName after validation"}
}
}

# Function to unregister guest VM from Cluster and Hyper-V
function deregisterVm{
param([string]$vmName="Windows 2016 Template")
try{
$vmState=(get-vm $vmName).State
if($vmState -eq "Running"){gracefulShutdown -RemoteComputer $vmName}
$vmStopped=(get-vm $vmName).State -eq "Off"
if($vmStopped){
removeVmFromCluster -vmName $vmName;
Remove-VM -Name $vmName -Force;
write-host "$vmName has been removed from Hyper-V."
}
}catch{
write-host $Error
write-host "Unable to deregister VM $vmName."
}
}

function getVmDisks{
param($vmName)
#write-host "Gathering disks information...";
$disks=Get-VM $vmName | Select-Object VMId | Get-VHD
return $disks
}

# Expand the targeted disk
# resizeVmDisk -vmName $vmName -diskIndex $diskIndex -newSizeGb $newSize;
function resizeVmDisk{
param($vmName,$diskIndex,$newSizeGb)

write-host "Removing all snapshots prior to performing disks expansion..."
try {
Get-VMSnapshot -VMName $vmName | %{Remove-VMSnapshot -VMName $vmName -Name $_.Name}
}
catch{
write-host "unable to remove all snapshots. Aborting Remove-VMSnapshot commands."
break;
}

write-host "Gathering disks information...";
$disks=getVmDisks -vmName $vmName
$before= $($disks | select VhdType,Path,@{label='currentSizeGb';expression={$_.FileSize/1gb -as [int]}},`
@{label='minimumSizeGbAllowed';expression={$_.MinimumSize/1gb -as [int]}},`
@{label='maxSizeGb';expression={$_.Size/1gb -as [int]}}`
| ft -AutoSize | Out-String)
write-host "Before:`r`n$before"
$diskX=$disks | Select -Index $diskIndex # VhdType: Fixed, Dynamic, Differencing
$diskMinimumAllowed=$diskX.MinimumSize;
$diskCurrentSize=$diskX.FileSize;
$diskMaxSize=$diskX.Size;
$vmVolumeFile=$diskX.Path
#$vmVolume=get-vm $vmName | select -expand HardDrives | select -Index $diskIndex
#$vmVolumeFile=$vmVolume.Path

# if $newSize is not specified, set disk value to double its original size
if(!($newSizeGb)){
$newSizeBytes=$diskMaxSize*2
}else{
$newSizeBytes=$newSizeGb/1;
}

if ($newSizeGb/1 -ge $diskMinimumAllowed){
try{
Resize-VHD -Path "$vmVolumeFile" -SizeBytes ($newSizeGb/1);
$disksAfter=getVmDisks -vmName $vmName
$after= $($disksAfter | select VhdType,Path,@{label='currentSizeGb';expression={$_.FileSize/1gb -as [int]}},`
@{label='minimumSizeGbAllowed';expression={$_.MinimumSize/1gb -as [int]}},`
@{label='maxSizeGb';expression={$_.Size/1gb -as [int]}}`
| ft -AutoSize | Out-String)
write-host "After:`r`n$after"
write-host "$vmVolumeFile has been resized to $newSizeGb successfully."
}catch{
write-host "Cannot resize $vmVolumeFile.";
}
}else{
write-host "$newSizeGb GB is less than the minimum allowed of $($diskMinimumAllowed/1GB). Cannot resize this disk.";
}
}

# Connect to Windows OS of Guest-VM & Resize volume to its available maximum
function expandWindowsVmVolume{
param($windowsName,$vmName,$driveLetter="C")

if((get-vm -name $vmName).State -ne "Running"){Start-VM -Name $vmName}
$localComputerName=$env:computername
$localIps=([System.Net.Dns]::GetHostAddresses($env:computername)|?{$_.AddressFamily -eq "InterNetwork"}|%{$_.IPAddressToString;}|out-string).Trim();
$isLocal=if($windowsName -match "(localhost|127.0.0.1|$localComputerName)" -or $localIps -match $windowsName){$true}else{$false}

# Ping computer, retry until wait-time expires
function pingHostUntilUp{
param($computername="localhost",$waitTime=300)
$t=0;
write-host "Pinging $ComputerName"
do {
$hostIsPingable=if(Test-Connection $ComputerName -Count 1 -Delay 1 -ErrorAction SilentlyContinue){$true}else{$false}
if(!($hostIsPingable)){
write-host -nonewline ".";
$t+=5;
sleep 5;
}
}while (!($hostIsPingable) -and $t -le $waitTime)
return $hostIsPingable
}

function expandVolumeMax{
param($driveLetter)
Update-HostStorageCache
# Before
$before = (gwmi -Class win32_volume -Filter "DriveType!=5" -ea stop| ?{$_.DriveLetter -eq "$driveLetter`:"}|`
Select-object @{Name="Letter";Expression={$_.DriveLetter}},`
@{Name="Label";Expression={$_.Label}},`
@{Name="Capacity";Expression={"{0:N2} GiB" -f ($_.Capacity/1073741824)}},`
@{Name = "Available"; Expression = {"{0:N2} GiB" -f ($_.FreeSpace/1073741824)}},`
@{Name = "Utilization"; Expression = {"{0:N2} %" -f ((($_.Capacity-$_.FreeSpace) / $_.Capacity)*100)}}`
| ft -autosize | Out-String).Trim()
write-host "Before:`r`n$before"

$max=(Get-PartitionSupportedSize -DriveLetter $driveLetter).SizeMax;
$maxGb=[math]::round($max/1GB,4);
try{
Resize-Partition -DriveLetter $driveLetter -Size $max;
Update-HostStorageCache;
$after = (gwmi -Class win32_volume -Filter "DriveType!=5" -ea stop| ?{$_.DriveLetter -eq "$driveLetter`:"}|`
Select-object @{Name="Letter";Expression={$_.DriveLetter}},`
@{Name="Label";Expression={$_.Label}},`
@{Name="Capacity";Expression={"{0:N2} GiB" -f ($_.Capacity/1073741824)}},`
@{Name = "Available"; Expression = {"{0:N2} GiB" -f ($_.FreeSpace/1073741824)}},`
@{Name = "Utilization"; Expression = {"{0:N2} %" -f ((($_.Capacity-$_.FreeSpace) / $_.Capacity)*100)}}`
| ft -autosize | Out-String).Trim()
write-host "After:`r`n$after"
Write-Host "`r`n$driveLetter has been resized to $maxGb GB successfully.";
}catch{
write-host $Error;
Write-Host "`r`n$driveLetter has NOT been resized due to an error.";
break;
}
}

function expandVolume{
param($computerName,$isLocal)
if ($isLocal){
expandVolumeMax -driveLetter $driveLetter;
}else{
invoke-command -computername $computerName -ScriptBlock{
param($expandVolumeMax,$driveLetter)
[ScriptBlock]::Create($expandVolumeMax).Invoke($driveLetter);
}-Args ${function:expandVolumeMax},$driveLetter
}
}

if(pingHostUntilUp -computername $windowsName){
expandVolume -computerName $windowsName -isLocal $isLocal
}else{
Start-VM -Name $vmName
$hostOnline=pingHostUntilUp -computername $windowsName
if($hostOnline){
expandVolume -computerName $windowsName -isLocal $isLocal
}else{
write-host "Cannot bring $windowsName online to perform disk expansion.";
}
}
}

function moveVM{
param(
[string]$windowsName="ISI-WSUS",
[string]$sourceVmName="Windows 2016 Template",
[string]$interimDestination="C:\ClusterStorage\Volume1\VHD",
[string]$finalDestination="C:\ClusterStorage\Volume1\VHD"
)
$timer=[System.Diagnostics.Stopwatch]::StartNew();
#gracefulShutdown -windowsName $windowsName -vmName $sourceVmName;
$exportSuccess=exportVM -sourceVmName $sourceVmName -destinationFolder $interimDestination;
if($exportSuccess){
deregisterVM -vmName $sourceVmName
importVM -vmName $sourceVmName -sourceDirectory $interimDestination -destinationDirectory $finalDestination;
$totalSeconds=$timer.Elapsed.TotalSeconds;
$hours=[math]::round($totalSeconds/3600,2);
write-host "The moveVM function has completed in $hours hours.";
write-host "Once validation succeeds, manually delete this folder $interimDestination\$sourceVmName";
$timer.stop();
}else{
write-host "The exportVM function has failed. Aborting moveVM function.";
break;
}
}

function expandVmDiskAndVolume{
param(
[string]$windowsName="Windows2016Template",
[string]$vmName="Windows 2016 Template",
[int]$diskIndex=0,
[string]$driveLetter="C",
[string]$newSize="160GB"
)
resizeVmDisk -vmName $vmName -diskIndex $diskIndex -newSizeGb $newSize;
expandWindowsVmVolume -windowsName $windowsName -vmName $vmName -driveLetter $driveLetter;
}

function copyOnlyFiles{
param(
[Parameter(Mandatory=$true)][string]$sourceFolder,
[Parameter(Mandatory=$true)][string]$destinationFolder
)
$totalSizeBytes=0;
# Get-ChildItem "C:\Temp"|?{!$_.PSIsContainer}|%{robocopy "C:\Temp" "C:\TempCopy" $_}
# Get-ChildItem $sourceFolder|?{!$_.PSIsContainer}|%{robocopy $sourceFolder $destinationFolder $_}
# New-Item -ItemType Directory -Force -Path $destinationFolder | Out-Null
#$duration=measure-command {Get-ChildItem $sourceFolder|?{!$_.PSIsContainer}|Copy-Item -Destination $destinationFolder}
$duration=measure-command {
$filesOnly=Get-ChildItem $sourceFolder|?{!$_.PSIsContainer}
$filesOnly|%{
$totalSizeBytes+=$_.Length;
write-host $_;
robocopy $sourceFolder $destinationFolder $_;
robocopy $sourceFolder $destinationFolder $_ | %{$data = $_.Split([char]9); if("$($data[4])" -ne "") { $file = "$($data[4])"} ;Write-Progress "Percentage $($data[0])" -Activity "Robocopy" -CurrentOperation "$($file)" -ErrorAction SilentlyContinue; }
}
}
$totalsizeGb=$totalSizeBytes/1GB
$totalMinutes=[math]::round($duration.TotalMinutes,2)
$gbPerHour=[math]::round($totalsizeGb/(($duration.TotalMinutes)/60),2)
write-host "-------------------------------------------------`r`n$([math]::round($totalsizeGb,2)) GB completed in $totalMinutes minutes. Speed was $gbPerHour GB/Hour."
}

function resizeVhdxChain{
param(
[Parameter(Mandatory=$true)][String]$vmName,
[Parameter(Mandatory=$false)][int]$diskIndex=0,
[Parameter(Mandatory=$false)][String]$newSizeGb="160GB"
)

function resizeVhdx{
param(
[string]$vhdxFile,
$newSizeGb
)
# Validation
if($newsizegb.gettype().Name -eq "String"){
$sizeBytes=$newSizeGb/1
}else{
write-host "There appears to be an error with the input size of $newSizeGb"
break;
}
try{
Resize-VHD -Path "$vhdxFile" -SizeBytes $sizeBytes;
}catch{
write-host $Error
}
}

$disks=getVmDisks -vmName $vmName
$diskX=$disks | Select -Index $diskIndex
$file=$diskX.Path
$parent=(Get-VHD -Path '$file' -ea SilentlyContinue).ParentPath
if ($parent){
$vhdxFiles=while($file = (Get-VHD -Path '$file').ParentPath){$file}
}else{
$vhdxFiles=$file
}

if($vhdxFiles.Count -gt 1){
$statements=$vhdxFiles|%{
"resizeVhdx -vhdxFile '$_' -newSizeGb '$newSizeGb'`r`n";
}
#$statements+="Merge-VHD -Path '$($vhdxFiles[0])' -DestinationPath '$($vhdxFiles[$vhdxFiles.length-1])'"
write-host "Statements to confirm`r`n$statements"
pause;
$vhdxFiles|%{resizeVhdx -vhdxFile '$_' -newSizeGb '$newSizeGb'}
#Merge-VHD -Path '$($vhdxFiles[0])' -DestinationPath '$($vhdxFiles[$vhdxFiles.length-1])'
}else{
write-host "There are not parent disks to resize."
}

}

function mergeVhdxChain{
param(
[Parameter(Mandatory=$true)][String]$vmName,
[Parameter(Mandatory=$false)][int]$diskIndex=0
)

$disks=getVmDisks -vmName $vmName
$diskX=$disks | Select -Index $diskIndex
$file=$diskX.Path
$parent=(Get-VHD -Path '$file' -ea SilentlyContinue).ParentPath
if ($parent){
$vhdxFiles=while($file = (Get-VHD -Path $file).ParentPath){$file}
}else{
$vhdxFiles=$file
}
if($vhdxFiles.Count -gt 1){
Merge-VHD -Path "$($vhdxFiles[0])" -DestinationPath "$($vhdxFiles[$vhdxFiles.length-1])"
}else{
write-host "There are not parent disks to merge."
}
}

write-host "Commands loaded - copy and paste these lines when ready"
write-host "gracefulShutdown -windowsName `$windowsName -vmName `$sourceVmName"
write-host "copyOnlyFiles -sourceFolder `$backupSourceFolder -destinationFolder `$backupDestinationFolder"
write-host "moveVM -windowsName `$windowsName -sourceVmName `$sourceVmName -interimDestination `$interimDestination -finalDestination `$finalDestination"
write-host "getVmDisks -vmName `$sourceVmName"
write-host "resizeVhdxChain -vmName `$sourceVmName -diskIndex `$resizeDiskIndex -newSizeGb `$resizeTo"
write-host "expandVmDiskAndVolume -windowsName `$windowsName -vmName `$sourceVmName -diskIndex `$resizeDiskIndex -driveLetter `$resizeVolumeLetter -newSize `$resizeTo"

Sample Output:

<# Sample Output:
PS C:\Windows\system32> migrateVM -sourceVmName "CONCU" -destinationDirectory "C:\ClusterStorage\Volume1\VHD"
checking CONCU...
WinRM has been already enabled. No changes to WinRM have been made.
Connecting to remote computer ...
Connected.
WARNING: Waiting for service 'SOME Service (SQL)' to stop...
WARNING: Waiting for service 'SOME Service (SQL)' to stop...
Pinging CONCU
...CONCU is now offline.
CONCU has been exported to C:\ClusterStorage\Volume1\VHD\CONCU-BACKUP at the speed of 254.61 GB/Hour (38.19140625 GB in 0.15 hours)
CONCU has been removed from the cluster.
CONCU has been imported to C:\ClusterStorage\Volume1\VHD\CONCU at the speed of 3819.14 GB/Hour (38.19140625 GB in 0.01 hours)

PS C:\Windows\system32> expandVmDiskAndVolume -vmName "CONCU" -diskIndex 0 -driveLetter "C" -newSize "160GB"
Pinging CONCU
.Before:
Letter Label Capacity Available Utilization
------ ----- -------- --------- -----------
C: 109.45 GiB 12.14 GiB 73.57 %
After:
Letter Label Capacity Available Utilization
------ ----- -------- --------- -----------
C: 159.45 GiB 102.14 GiB 47.03 %

C has been resized to 159.45 GB successfully.
#>

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Post

PowerShell: 1-Liner to Change Computer Name and Join Active Directory

# The 1-liner Add-Computer -DomainName 'somedomain.com' -credential kimconnect.com\domainadmin1 -ComputerName $env:computernname -newname 'NewName' -restart # Quick…

WordPress Plugin to Customize How Posts are Displayed

A. Install the 'Display Posts' plugin B. Install the 'Code Snippets' plugin C. Add this…

Batch File to Copy Files Containing Agents’ Names

:: Set variables using system time and date popd   Set today=%Date:~4,2%_%Date:~7,2%_%Date:~10,4%   IF "%today:~0,1%"=="0"…