From dc0213773d60620a23885d61430f409896d33804 Mon Sep 17 00:00:00 2001 From: NamedJason Date: Wed, 31 May 2017 07:27:38 -0700 Subject: [PATCH] Improved performance and user feedback I changed the structure of the functions to improve performance when working with large numbers of datastores and hosts. I also added more verbose progress bars so that the user would be more aware of what the scripts were doing at any given time. --- .../DatastoreFunctions.psm1 | 339 +++++++++++------- 1 file changed, 200 insertions(+), 139 deletions(-) diff --git a/Modules/DatastoreFunctions/DatastoreFunctions.psm1 b/Modules/DatastoreFunctions/DatastoreFunctions.psm1 index e417112..b908a40 100644 --- a/Modules/DatastoreFunctions/DatastoreFunctions.psm1 +++ b/Modules/DatastoreFunctions/DatastoreFunctions.psm1 @@ -1,50 +1,112 @@ -#Created by Alan Renouf, published at https://communities.vmware.com/docs/DOC-18008 +<# +.SYNOPSIS Datastore Functions +.DESCRIPTION A collection of functions to manipulate datastore Mount + Attach status +.EXAMPLE Get-Datastore | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize +.EXAMPLE Get-Datastore IX2ISCSI01 | Unmount-Datastore +.EXAMPLE Get-Datastore IX2ISCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize +.EXAMPLE Get-Datastore IX2iSCSI01 | Mount-Datastore +.EXAMPLE Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize +.EXAMPLE Get-Datastore IX2iSCSI01 | Detach-Datastore +.EXAMPLE Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize +.EXAMPLE Get-Datastore IX2iSCSI01 | Attach-datastore +.EXAMPLE Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize +.NOTES Written by Alan Renouf, originally published at https://blogs.vmware.com/vsphere/2012/01/automating-datastore-storage-device-detachment-in-vsphere-5.html +.NOTES May 2017: Modified by Jason Coleman (virtuallyjason.blogspot.com), to improve performance when dealing with a large number of hosts and datastores +#> +Function Get-HostViews { + [CmdletBinding()] + Param ( + $Datastore + ) + Begin{ + $allDatastores = @() + } + Process { + $allDatastores += $Datastore + } + End { + #Build the array of Datastore Objects + if (-not $Datastore) { + $allDatastores = Get-Datastore + } + $allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"} + if (-not $allDatastores){ + Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?" + } + $allHosts = @() + $DShostsKeys = $allDatastores.extensiondata.host.key.value | sort | get-unique -asstring + $DShosts = foreach ($thisKey in $DShostsKeys) {($allDatastores.extensiondata.host | ? {$_.key.value -eq $thisKey})[0]} + $i = 1 + foreach ($DSHost in $DSHosts){ + write-progress -activity "Collecting ESXi Host Views" -status "Querying $($dshost.key)..." -percentComplete ($i++/$DSHosts.count*100) + $hostObj = "" | select keyValue,hostView,storageSys + $hostObj.hostView = get-view $DSHost.key + $hostObj.keyValue = $DSHost.key.value + $hostObj.storageSys = Get-View $hostObj.hostView.ConfigManager.StorageSystem + $allHosts += $hostObj + } + write-progress -activity "Collecting ESXi Host Views" -completed + $allHosts + } +} + Function Get-DatastoreMountInfo { [CmdletBinding()] Param ( [Parameter(ValueFromPipeline=$true)] $Datastore ) + #Roll back up an unrolled array from a pipeline + Begin{ + $allDatastores = @() + } Process { + $allDatastores += $Datastore + } + End { $AllInfo = @() + #Build the array of Datastore Objects if (-not $Datastore) { - $Datastore = Get-Datastore + $allDatastores = 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 - } - } - + $allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"} + if (-not $allDatastores){ + Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?" + } + $allDatastoreNAAs = foreach ($ds in $allDatastores) {$ds.ExtensionData.Info.vmfs.extent[0].diskname} + + #Build the array of custom Host Objects + $allHosts = Get-HostViews -datastore $allDatastores + $output = @() + $i = 1 + foreach ($dsHost in $allHosts){ + write-progress -activity "Checking Datastore access" -status "Checking $($dshost.hostview.name)..." -percentComplete ($i++ / $allHosts.count * 100) + #Get all devices on the host that match the list of $allDatastoreNAAs + $devices = $dsHost.storagesys.StorageDeviceInfo.ScsiLun + foreach ($device in $devices){ + if ($allDatastoreNAAs -contains $device.canonicalName){ + #Record information about this device/host combo + $thisDatastore = $alldatastores | ? {$_.ExtensionData.Info.vmfs.extent[0].diskname -eq $device.canonicalName} + $hostviewDSAttachState = "" + if ($device.operationalState[0] -eq "ok") { + $hostviewDSAttachState = "Attached" + } elseif ($device.operationalState[0] -eq "off") { + $hostviewDSAttachState = "Detached" + } else { + $hostviewDSAttachState = $device.operationalstate[0] } + $Info = "" | Select Datastore, VMHost, Lun, Mounted, State + $Info.VMHost = $dsHost.hostview.name + $Info.Datastore = $thisDatastore.name + $Info.Lun = $device.canonicalName + $Info.mounted = ($thisDatastore.extensiondata.host | ? {$_.key.value -eq $dshost.keyvalue}).mountinfo.mounted + $Info.state = $hostviewDSAttachState + $output += $info } } } - $AllInfo + write-progress -activity "Checking Datastore access" -completed + $output } } @@ -54,81 +116,32 @@ Function Detach-Datastore { [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) { - $LunUUID = $Device.Uuid - Write-Host "Detaching LUN $($Device.CanonicalName) from host $($hostview.Name)..." - $StorageSys.DetachScsiLun($LunUUID); - } - } - } - } - } + Begin{ + $allDatastores = @() } -} - -Function Unmount-Datastore { - [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 - Write-Host "Unmounting VMFS Datastore $($DS.Name) from host $($hostview.Name)..." - $StorageSys.UnmountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid); - } - } - } + $allDatastores += $Datastore } -} - -Function Mount-Datastore { - [CmdletBinding()] - Param ( - [Parameter(ValueFromPipeline=$true)] - $Datastore - ) - Process { - if (-not $Datastore) { - Write-Host "No Datastore defined as input" - Exit + End { + $allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"} + if (-not $allDatastores){ + Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?" } - 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 - Write-Host "Mounting VMFS Datastore $($DS.Name) on host $($hostview.Name)..." - $StorageSys.MountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid); - } + $allDatastoreNAAs = foreach ($ds in $allDatastores) {$ds.ExtensionData.Info.vmfs.extent[0].diskname} + $allHosts = Get-HostViews -datastore $allDatastores + $j = 1 + foreach ($dsHost in $allHosts){ + #Get all devices on the host that match the list of $allDatastoreNAAs + write-progress -id 1 -activity "Detaching Datastores" -status "Removing device(s) from $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100) + $devices = $dsHost.storagesys.StorageDeviceInfo.ScsiLun | ? {$allDatastoreNAAs -contains $_.canonicalName} + $i = 1 + foreach ($device in $devices){ + write-progress -parentid 1 -activity "Detaching Datastores" -status "Removing device: $(($allDatastores | ? {$_.ExtensionData.Info.vmfs.extent[0].diskname -eq $device.canonicalName}).name)" -percentComplete ($i++ / $allDatastoreNAAs.count * 100) + $LunUUID = $Device.Uuid + $dsHost.storageSys.DetachScsiLun($LunUUID); } } + write-progress -activity "Detaching Datastores" -completed } } @@ -138,47 +151,95 @@ Function Attach-Datastore { [Parameter(ValueFromPipeline=$true)] $Datastore ) + Begin{ + $allDatastores = @() + } Process { - if (-not $Datastore) { - Write-Host "No Datastore defined as input" - Exit + $allDatastores += $Datastore + } + End { + $allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"} + if (-not $allDatastores){ + Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?" } - 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) { - $LunUUID = $Device.Uuid - Write-Host "Attaching LUN $($Device.CanonicalName) to host $($hostview.Name)..." - $StorageSys.AttachScsiLun($LunUUID); - } - } + $allDatastoreNAAs = foreach ($ds in $allDatastores) {$ds.ExtensionData.Info.vmfs.extent[0].diskname} + $allHosts = Get-HostViews -datastore $allDatastores + $j = 1 + foreach ($dsHost in $allHosts){ + #Get all devices on the host that match the list of $allDatastoreNAAs + write-progress -id 1 -activity "Attaching Datastores" -status "Attaching devices to $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100) + $devices = $dsHost.storagesys.StorageDeviceInfo.ScsiLun + $i = 1 + foreach ($device in $devices){ + write-progress -parentid 1 -activity "Attaching Datastores" -status "Attaching device: $($Device.Uuid)" -percentComplete ($i++ / $devices.count * 100) + if ($allDatastoreNAAs -contains $device.canonicalName){ + $LunUUID = $Device.Uuid + $dsHost.storageSys.AttachScsiLun($LunUUID); } } } + write-progress -activity "Attaching Datastores" -completed + } +} + +Function Unmount-Datastore { + [CmdletBinding()] + Param ( + [Parameter(ValueFromPipeline=$true)] + $Datastore + ) + Begin{ + $allDatastores = @() + } + Process { + $allDatastores += $Datastore + } + End { + $allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"} + if (-not $allDatastores){ + Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?" + } + $allHosts = Get-HostViews -datastore $allDatastores + $j = 1 + foreach ($dsHost in $allHosts){ + write-progress -id 1 -activity "Unmounting Datastores" -status "Unmounting devices from $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100) + $i = 1 + foreach ($ds in $allDatastores){ + write-progress -parentid 1 -activity "Unmounting Datastores" -status "Unmounting device: $($ds.name)" -percentComplete ($i++ / $allDatastores.count * 100) + $dsHost.storageSys.UnmountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid); + } + } + write-progress -activity "Unmounting Datastores" -completed + } +} + +Function Mount-Datastore { + [CmdletBinding()] + Param ( + [Parameter(ValueFromPipeline=$true)] + $Datastore + ) + Begin{ + $allDatastores = @() + } + Process { + $allDatastores += $Datastore + } + End { + $allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"} + if (-not $allDatastores){ + Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?" + } + $allHosts = Get-HostViews -datastore $allDatastores + $j = 0 + foreach ($dsHost in $allHosts){ + write-progress -activity "Mounting Datastores" -status "Mounting devices to $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100) + $i = 1 + foreach ($ds in $allDatastores){ + write-progress -activity "Mounting Datastores" -status "Mounting device: $($DS.ExtensionData.Info.vmfs.uuid)" -percentComplete ($i++ / $allDatastores.count * 100) + $dsHost.storageSys.MountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid); + } + } + write-progress -activity "Mounting Datastores" -completed } } -# -#Get-Datastore | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize -# -#Get-Datastore IX2ISCSI01 | Unmount-Datastore -# -#Get-Datastore IX2ISCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize -# -#Get-Datastore IX2iSCSI01 | Mount-Datastore -# -#Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize -# -#Get-Datastore IX2iSCSI01 | Detach-Datastore -# -#Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize -# -#Get-Datastore IX2iSCSI01 | Attach-datastore -# -#Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize -#