Remove a VMFS datastore using powershell

Standard

Recently I had to remove a lot of VMFS datastores from our VMWare infrastructure as we had migrated to new storage and no longer needed them.
In order to remove a datastore from your vmware infrastructure correctly you must follow the instructions given in this article. http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2004605
Basically it says you have to make sure nothing is using the datastore and then unmount and detach the datastore from each connected host. Since we work with large clusters with many ESXi hosts I didn’t enjoy the prospect of manually unmounting and detaching each datastore from each host. To avoid this I found this article http://blogs.vmware.com/vsphere/2012/01/automating-datastore-storage-device-detachment-in-vsphere-5.html which explains how to automate datastore removal. It’s a great article and includes a few functions which give you the ability to unmount and detach datastores like described above. I simply used these functions to create the script in this blog.

If the functions are already there then why use this script?

I wrote this script so that it does everything for you in one go. You don’t have to mess around with the functions or cmd-lets yourself. Also, I made a few changes to the mentioned functions which I feel improve them. Basically all you have to do is put in the name of the datastore and run the script.

What does the script do exactly?

1. The script gets the datastore info and then asks for confirmation before beginning the removal process.
2. The datastore is unmounted on each host connected to it.
3. The datastore is detached on each host connected to it.
4. At the end of the script run the datastore name and LUN canonical name is returned. This is useful as you will probably need this information when you have to delete the LUN in your storage system later on.

How do I run the script?

I. Go through the checklist “Unmounting a LUN checklist” here http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2004605 and make sure your datastore is ready for removal.
II.Copy the script to your computer and open it with and editor like powershell_ISE or powerGUI.
III. In the #Parameters section enter the name of your vCenter server and the name of the datastore you wish to remove.
IV. Hit F5 to run the script.

The script itself

I’m not going to go into details about the code as you can see all that in the links to KB articles above. I have simply copied in the script for you here. Please leave a comment if you find the script useful. Enjoy!

#############################################################################################################
##script:			Unmount_Detach-Datastore.ps1
##
##Description:		Unmounts and detaches a given datastore from all its connected hosts.
#+					Before running make sure that the datastore doesn't have any live VMs or templates on it.
#Additional info:	http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2004605
#Additional info:	http://blogs.vmware.com/vsphere/2012/01/automating-datastore-storage-device-detachment-in-vsphere-5.html
#Additional info:	https://communities.vmware.com/docs/DOC-18008
##Created by:		Noam Wajnman
##Creation Date:	August 4, 2014
##############################################################################################################
function Connect-Vcenter {
	#############################################################################################
	##Function:			Connect-Vcenter
	##
	##Description:		Loads the VMWare snap-in for powershell and connects to vcenter.
	##
	##Created by:		Noam Wajnman
	##Creation Date:	20 November, 2012
	##Updated:			31 July, 2014
	##############################################################################################
	param(
		$vcenter
	)
	#Load snap-in
	if (-not (Get-PSSnapin -Name VMware.VimAutomation.Core -erroraction "silentlycontinue" )) {
        Write-Host "Importing VMWare Snap-in VMware.VimAutomation.Core..."    
		Add-PSSnapin VMware.VimAutomation.Core
	}
    Set-PowerCLIConfiguration -DefaultVIServerMode Single -invalidCertificateAction "ignore" -confirm:$false | out-null
	#Connect to vCenter
	if ($global:DefaultVIServers.Count -lt 1) {
        Write-Host "Connecting to vcenter server $vcenter..."		
		Connect-VIServer $vCenter
	}
}
Function Get-DatastoreMountInfo {
	#function copied from https://communities.vmware.com/docs/DOC-18008
	[CmdletBinding()]
	Param (
		[Parameter(ValueFromPipeline=$true)]
		$Datastore
	)
	Process {
		$AllInfo = @()
		if (-not $Datastore) {
			$Datastore = Get-Datastore
		}
		Foreach ($ds in $Datastore) {  
			if ($ds.ExtensionData.info.Vmfs) {
				$hostviewDSDiskName = $ds.ExtensionData.Info.vmfs.extent[0].diskname
				if ($ds.ExtensionData.Host) {
					$attachedHosts = $ds.ExtensionData.Host
					Foreach ($VMHost in $attachedHosts) {
						$hostview = Get-View $VMHost.Key
						$hostviewDSState = $VMHost.MountInfo.Mounted
						$StorageSys = Get-View $HostView.ConfigManager.StorageSystem
						$devices = $StorageSys.StorageDeviceInfo.ScsiLun
						Foreach ($device in $devices) {
							$Info = '' | Select Datastore, VMHost, Lun, Mounted, State
							if ($device.canonicalName -eq $hostviewDSDiskName) {
								$hostviewDSAttachState = ''
								if ($device.operationalState[0] -eq "ok") {
									$hostviewDSAttachState = "Attached"							
								} elseif ($device.operationalState[0] -eq "off") {
									$hostviewDSAttachState = "Detached"							
								} else {
									$hostviewDSAttachState = $device.operationalstate[0]
								}
								$Info.Datastore = $ds.Name
								$Info.Lun = $hostviewDSDiskName
								$Info.VMHost = $hostview.Name
								$Info.Mounted = $HostViewDSState
								$Info.State = $hostviewDSAttachState
								$AllInfo += $Info
							}
						}
						
					}
				}
			}
		}
		$AllInfo
	}
}
Function Detach-Datastore {
	#function based on code found here https://communities.vmware.com/docs/DOC-18008
	[CmdletBinding()]
	Param (
		[Parameter(ValueFromPipeline=$true)]
		$Datastore
	)
	Process {
		if (-not $Datastore) {
			Write-Host "No Datastore defined as input"
			Exit
		}
		Foreach ($ds in $Datastore) {
			$hostviewDSDiskName = $ds.ExtensionData.Info.vmfs.extent[0].Diskname
			if ($ds.ExtensionData.Host) {
				$attachedHosts = $ds.ExtensionData.Host
				Foreach ($VMHost in $attachedHosts) {
					$hostview = Get-View $VMHost.Key
					$StorageSys = Get-View $HostView.ConfigManager.StorageSystem
					$devices = $StorageSys.StorageDeviceInfo.ScsiLun
					Foreach ($device in $devices) {
						if ($device.canonicalName -eq $hostviewDSDiskName) {
							#If the device is attached then detach it (I added this to the function to prevent error messages in vcenter when running the script)
							if ($device.operationalState[0] -eq "ok") { 
								$LunUUID = $Device.Uuid
								Write-Host "Detaching LUN $($Device.CanonicalName) from host $($hostview.Name)..."
								$StorageSys.DetachScsiLun($LunUUID);
							}
							#If the device isn't attached then skip it (I added this to the function to prevent error messages in vcenter when running the script)
							else {
								Write-Host "LUN $($Device.CanonicalName) is not attached on host $($hostview.Name)..."
							}
						}
					}
				}
			}
		}
	}
}
Function Unmount-Datastore {
	#function based on code found here https://communities.vmware.com/docs/DOC-18008
	[CmdletBinding()]
	Param (
		[Parameter(ValueFromPipeline=$true)]
		$Datastore
	)
	Process {
		if (-not $Datastore) {
			Write-Host "No Datastore defined as input"
			Exit
		}
		Foreach ($ds in $Datastore) {
			$hostviewDSDiskName = $ds.ExtensionData.Info.vmfs.extent[0].Diskname
			if ($ds.ExtensionData.Host) {
				$attachedHosts = $ds.ExtensionData.Host
				Foreach ($VMHost in $attachedHosts) {
					$hostview = Get-View $VMHost.Key
					$mounted = $VMHost.MountInfo.Mounted
					#If the device is mounted then unmount it (I added this to the function to prevent error messages in vcenter when running the script)
					if ($mounted -eq $true) {
						$StorageSys = Get-View $HostView.ConfigManager.StorageSystem
						Write-Host "Unmounting VMFS Datastore $($DS.Name) from host $($hostview.Name)..."
						$StorageSys.UnmountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid);
					}
					#If the device isn't mounted then skip it (I added this to the function to prevent error messages in vcenter when running the script)
					else {
						Write-Host "VMFS Datastore $($DS.Name) is already unmounted on host $($hostview.Name)..."
					}
				}
			}
		}
	}
}
#VARIABLES
#Parameters 
$vcenter = "Some_Vcenter_Server"
$DSName = "Some_Datastore"
#SCRIPT MAIN
clear
Connect-Vcenter $vcenter
$datastore = Get-Datastore -Name $DSName
$CanonicalName = $datastore.ExtensionData.Info.Vmfs.Extent[0].DiskName
$GoAhead = Read-Host "Are you sure that you want to unmount and detach: `n$DSName `n$CanonicalName`nfrom all its connected hosts?"
if ($GoAhead -eq "yes" -or $GoAhead -eq "y" -or $GoAhead -eq "Y") {
	Write-Host "Unmounting datastore $DSName..."	
	$datastore | Unmount-Datastore
	Write-Host "Detaching datastore $DSName from hosts..."
	$datastore | Detach-Datastore
}
$DSName
$CanonicalName
Advertisements