vPOSH.Storage.psm1
<# .SYNOPSIS Module to manag4 various storage functions within vSphere. May require PowerCLI #> function Get-NFSVolumeHostInfo { <# .SYNOPSIS [PowerCLI] Display the location (UUID) of a datastore on the given host, or all datastores on the given host .DESCRIPTION Display the location (UUID) of a datastore on the given host, or all datastores on the given host .PARAMETER VMHost Name of the VMHost to look on .PARAMETER Datastore Name of Datastore to find #> [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string]$VMHost, [Parameter(Mandatory=$false)] [String[]]$Datastores ) $ds = get-view (get-view (Get-VMHost $VMHost).ID).ConfigManager.StorageSystem if($Datastores) { $temp = ($ds.FileSystemVolumeInfo.MountInfo | Where {$_.Volume.Type -match "NFS" -and $Datastores -ccontains $_.Volume.Name} | Select ` @{N="Name";E={($_ | Select -ExpandProperty Volume | Select Name).Name}}, ` @{N="RemoteHost";E={($_ | Select -ExpandProperty Volume | Select RemoteHost).RemoteHost}}, ` @{N="RemotePath";E={($_ | Select -ExpandProperty Volume | Select RemotePath).RemotePath}}, ` @{N="LocalPath";E={($_ | Select -ExpandProperty MountInfo | Select Path).Path -replace "/vmfs/volumes/",""}}) } else { $temp = ($ds.FileSystemVolumeInfo.MountInfo | Where {$_.Volume.Type -match "NFS"} | Select ` @{N="Name";E={($_ | Select -ExpandProperty Volume | Select Name).Name}}, ` @{N="RemoteHost";E={($_ | Select -ExpandProperty Volume | Select RemoteHost).RemoteHost}}, ` @{N="RemotePath";E={($_ | Select -ExpandProperty Volume | Select RemotePath).RemotePath}}, ` @{N="LocalPath";E={($_ | Select -ExpandProperty MountInfo | Select Path).Path -replace "/vmfs/volumes/",""}}) } return $temp } function Get-DoubleMountedNFS { <# .SYNOPSIS [PowerCLI] Get's all the NFS Datastores that are mounted to more than one cluster .DESCRIPTION Get's all the NFS Datastores that are mounted to more than one cluster and returns the name and the clusters it is mounted to. This runs on all connected vCenters unless you specify a Datacenter .PARAMETER Datacenter Name of Datacenter you want to restrict your search to #> param ( [Parameter(Mandatory=$false, HelpMessage="Get's all the NFS Datastores that are mounted to more than one cluster")] [string]$Datacenter ) $ht=@{} if($Datacenter) { $myArray= Get-Datacenter $Datacenter | get-datastore | Where {$_.Type -match "NFS" -and $_.Name -notmatch "swp" -and $_.Name -notmatch "guestOsMedia"} | Select Name, Datacenter | sort Name } else { $myArray=get-datastore | Where {$_.Type -match "NFS" -and $_.Name -notmatch "swp" -and $_.Name -notmatch "guestOsMedia"} | Select Name, Datacenter | sort Name } $myArray | %{$ht[$_.Name] += 1} $ht.Keys | Where {$ht["$_"] -gt 1} | % {write-host "Datastore $_ is mounted to more than one cluster"} $matches = $ht.Keys | Where {$ht["$_"] -gt 1} $outObj = foreach($obj in ($myArray | Where {$matches -contains $_.Name} | group -Property Name)) { $tmpObj = "" foreach($item in $obj.Group) { if($tmpObj.Length -gt 0) { $tmpObj = "$($tmpObj),$($item.Datacenter)" } else { $tmpObj = $item.Datacenter } } New-Object PSObject -Property @{ Datastore = $obj.Name Datacenters = $tmpObj } } return $outObj } function Start-SequentialSvMotion { <# .SYNOPSIS [PowerCLI]Perform sequential Storage vMotion on a list of VMs .DESCRIPTION Perform sequential Storage vMotion on a list of VMs .PARAMETER VMs List of VM's to move .PARAMETER DestinationDatastore Name of the datastore to move the VM(s) to .PARAMETER IsCluster Is the DestinationDatastore a Storage DRS Cluster .PARAMETER NumOfSeqTasks Amount of simultanious Storage vMotions to perform sequentially .PARAMETER NumSecWait Number of seconds to wait between checks, minimum of 10 seconds .EXAMPLE Start-SequentialSVMotion.ps1 -VMs "myVM1","MyVM2" -DestinationDatastore datastore .EXAMPLE Start-SequentialSvMotion -VMs (Get-Cluster MyCluster | Get-VM) -DestinationDatastore MyDatastore .EXAMPLE Start-SequentialSvMotion -VMs "myVM" -DestinationDatastore MyDatastoreCluster -IsCluster:$True .EXAMPLE Start-SequentialSvMotion -VMs "myVM" -DestinationDatastore MyDatastore -NumOfSeqTasks 5 #> param ( [Parameter(Mandatory=$True, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="List of VM's to move")] [string[]]$VMs, [Parameter(Mandatory=$True, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Name of the datastore to move the VM(s) to")] [VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl]$DestinationDatastore, [Parameter(Mandatory=$false, HelpMessage="Is the DestinationDatastore a Storage DRS Cluster")] [switch]$IsCluster=$false, [Parameter(Mandatory=$false, HelpMessage="Amount of simultanious Storage vMotions to perform sequentially")] [int]$NumOfSeqTasks=2, [Parameter(Mandatory=$false, HelpMessage="Number of seconds to wait between checks, minimum of 10 seconds")] [int]$NumSecWait=60 ) [switch]$thinProvision=$false if($NumSecWait -lt 10) { $NumSecWait = 10 } clear-host if($IsCluster) { if((get-datastorecluster $DestinationDatastore | get-datastore | select -first 1).Type -eq "NFS") { $thinProvision=$true } } else { if((get-datastore $DestinationDatastore).Type -eq "NFS") { $thinProvision=$true } } $jobs = New-Object -typeName System.Collections.Arraylist $sFormat = "Thick" if($thinProvision) { $sFormat = "Thin" } foreach ( $vm in $VMs) { $runCount = (get-task | Where {$_.Name -eq "RelocateVM_Task" -or $_.name -eq "ApplyStorageDrsRecommendation_Task"} | Where State -eq "Running").Count while($runCount -ge $NumOfSeqTasks) { write-host "$($runCount) of $($NumOfSeqTasks) Active Jobs, limit reached. Waiting..." sleep $NumSecWait $runCount = (get-task | Where {$_.Name -eq "RelocateVM_Task" -or $_.name -eq "ApplyStorageDrsRecommendation_Task"} | Where State -eq "Running").Count } if($runCount -lt $NumOfSeqTasks) { write-host "Starting relocation of $($vm)" $j=Get-vm $vm | Move-VM -Datastore $DestinationDatastore -DiskStorageFormat $sFormat -Confirm:$false -RunAsync -ErrorAction SilentlyContinue $jobs.add($j) } sleep $NumSecWait } $resultObj=foreach($job in $jobs) { $job = get-task | where Id -eq $job.Id if($job.State -ne "Running") { #$jobs.remove($job) New-Object PSObject -Property @{ VMName=$vm Result=$job.State StartTime=$job.StartTime EndTime=$job.EndTime } } } return $resultObj } function Remove-DataStoreFromDataCenter { <# .SYNOPSIS [PowerCLI]Unmounts a specified Datastore from an entire Datacenter .DESCRIPTION Unmounts a specified Datastore from an entire Datacenter .EXAMPLE Remove-DataStoreFromDataCenter -DataCenterName "dc1" -DatastoreName ds1 .PARAMETER DataCenterName The name of the Datacenter you want to work with .PARAMETER DatastoreName Name of the Datastore you want to unmount #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Name of the Datastore you want to unmount")] [string]$DatastoreName, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="The name of the Datacenter you want to work with")] [string]$DataCenterName ) foreach ($vmHost in (Get-Datacenter $DataCenterName | Get-VMHost)) { $dataStore = $vmhost | Get-Datastore $DatastoreName -ErrorAction SilentlyContinue if($dataStore) { $dataStore | Remove-Datastore -VMHost $vmhost -Confirm:$false -ErrorAction SilentlyContinue } } } function Get-VMperNFSDatastore { <# .SYSNOPSIS [PowerCLI]Retrieves a count of the number of VMs on a Datastore .DESCRIPTION Retrieves a count of the number of VMs on a Datastore in an ordered list sutable for parsing our CSV output. This runs against the currently connected vCenter(s) or just a single DataCenter (Must be connected first) and will only run against NFS volumes for VM's .EXAMPLE Get-VMperNFSDatastore -OutputFile C:\Temp\MyFile.csv .EXAMPLE Get-VMperNFSDatastore -OutputFile C:\Temp\MyFile.csv -DataCenter mydatacenter .PARAMETER DataCenter .PARAMETER OutputFile #> [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [string]$DataCenter, [Parameter(Mandatory=$false)] [string]$OutputFile ) if($DataCenter) { $oPut=Get-Datacenter $DataCenter | Get-Datastore | Where {$_.Type -eq "NFS"} | Select Name,@{N="NumVM";E={@($_ | Get-VM).Count}} | Sort NumVM,Name } else { $oPut=Get-Datastore | Where {$_.Type -eq "NFS"} | Select Datacenter,Name,@{N="NumVM";E={@($_ | Get-VM).Count}} | Sort Datacenter,NumVM,Name } if($OutputFile) { $oPut | Export-Csv -Path $OutputFile -NoTypeInformation } else { $oPut | Format-Table } } function Add-NFSDataStoreToDataCenter { <# .SYNOPSIS [PowerCLI]Mounts an NFS store on each host in a given DataCenter .DESCRIPTION Mounts an NFS store on each host in a given DataCenter .EXAMPLE Add-NFSDataStoreFromDataCenter -DataCenterName "dc1" -DataStoreName "ds1" -NFSHost 192.168.12.12 -NFSRemoteVolume "/vol/ds1" .EXAMPLE Add-NFSDataStoreFromDataCenter -DataCenterName "dc1" -DataStoreName "ds1" -NFSHost 192.168.12.12 -NFSRemoteVolume "/vol/ds1" -ReadOnly .PARAMETER Cluster The name of the Cluster you need information for .PARAMETER DatastoreName Name of the Datastore in which you want to add .PARAMETER NFSHost Name/IP of the remote NFS host .PARAMETER NFSRemoteVolume Volume export on remote host .PARAMETER ReadOnlyVolume Switch parameter to decide of the volume should be Readonly or Read/Write. Default is Read/Write #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Name of the Datastore in which you want to add")] [string]$DatastoreName, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="The name of the Cluster you need information for")] [string]$Cluster, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Name/IP of the remote NFS host")] [string]$NFSHost, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Volume export on remote host")] [string]$NFSRemoteVolume, [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Switch parameter to decide of the volume should be Readonly or Read/Write. Default is Read/Write")] [switch]$ReadOnlyVolume=$false ) foreach ($vmHost in (Get-Cluster $Cluster | Get-VMHost)) { $dataStore = $vmhost | Get-Datastore $DatastoreName -ErrorAction SilentlyContinue if(!$dataStore) { $vmHost | New-Datastore -Nfs -NfsHost $NFSHost -Path $NFSRemoteVolume.TrimStart("\") -ReadOnly:$ReadOnlyVolume -Name $DatastoreName } } } function Get-FibreWWN { <# .SYNOPSIS [PowerCLI]Gathers and formats the WWN ports for the FibreChannel HBA's of all hosts in a given datacenter .DESCRIPTION Gathers and formats the WWN ports for the FibreChannel HBA's of all hosts in a given datacenter .EXAMPLE Get-FibreWWN -DataCenterName "dc1" .PARAMETER Cluster The name of the Cluster you need information for #> [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$True, HelpMessage="Name of the Cluster that contains the host you wish to act on")] $Cluster ) $list = Get-Cluster $Cluster | Get-VMHost | Get-VMHostHBA -Type FibreChannel | Select VMHost,Device,@{N="WWN";E={"{0:X}"-f$_.PortWorldWideName}} | Sort VMhost,Device #Go through each row and put : between every 2 digits foreach ($item in $list) { $item.wwn = (&{for ($i=0;$i-lt$item.wwn.length;$i+=2) { $item.wwn.substring($i,2) }}) -join':' } return $list } function Get-NFSVMK { param ( <# .SYNOPSIS [PowerCLI]Gets the list of the VMKernel IP addresses for the NFS networks for each host .DESCRIPTION Gets the list of the VMKernel IP addresses for the NFS networks for each host .PARAMETER VMHosts Comma-delimeted list of hosts .EXAMPLE get-nfsvmk -vmhosts "myhost.somewehre.com" #> [Parameter(Mandatory=$true)] [string[]]$VMHosts ) $objResults=foreach($vmhost in $vmhosts) { $tmpObj = Get-VMHost $vmhost if($tmpObj.Version -match "5.5") { $tmpIP = $tmpObj | Get-VMHostNetworkAdapter -VMKernel | where {$_.VMotionEnabled -eq $false -and $_.FaultToleranceLoggingEnabled -eq $false -and $_.ManagementTrafficEnabled -eq $false} | select IP } else { $tmpIP = $tmpObj | Get-VMHostNetworkAdapter -VMKernel | where {$_.VMotionEnabled -eq $false -and $_.FaultToleranceLoggingEnabled -eq $false -and $_.ManagementTrafficEnabled -eq $false} | select IP } new-object PSObject -Property @{ HostName=$tmpObj.Name NFSIP=$tmpIP.IP } } return $objResults } function Get-ThinProvisionedVM { <# .SYNOPSIS [PowerCLI]Gathers all VMs that has a Thin Provisioned VMDK .DESCRIPTION Gathers all VMs that has a Thin Provisioned VMDK .EXAMPLE Get-ThinProvisionedVM #> [CmdletBinding()] param ( [object]$VMs ) if(!$VMs) { $VMs = Get-VM } $outObj = foreach ($vm in $VMs) { $view = Get-View $vm if ($view.config.hardware.Device.Backing.ThinProvisioned -eq $true) { foreach($device in ($view.Config.Hardware.Device | where {($_.GetType()).Name -eq "VirtualDisk"})) { if($device.Backing.Filename) { New-Object PSObject -Property @{ Name = $vm.Name Provisioned = [math]::round($vm.ProvisionedSpaceGB , 2) Total = [math]::round(($device | Measure-Object CapacityInKB -Sum).sum/1048576 , 2) Used = [math]::round($vm.UsedSpaceGB , 2) VMDKs = $device.Backing.Filename | Out-String VMDKSize = $device.CapacityinKB/1048576 | out-string Thin = $device.Backing.ThinProvisioned | Out-String } } } } } return $outObj } function Attach-SANDatastore { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [string]$Datacenter ) if ($datacenter) { $vmHosts = get-datacenter $datacenter | Get-VMHost } else { $vmHosts = Get-VMHost } foreach ($vmhost in $vmHosts) { #Re-attach to the host $detachedLuns = $vmhost | Get-VMHostHba -Type FibreChannel | Get-ScsiLun | Where {$_.ExtensionData.OperationalState -eq "off"} $storSys = get-view $vmhost.ExtensionData.ConfigManager.StorageSystem foreach ($detachedLun in $detachedLuns) { $storSys.AttachScsiLun($detachedLun.ExtensionData.Uuid) $storSys.RescanAllHba() } #Now mount it to the host $vmhost = Get-VMHost $vmhost.Name $lunsNeedingMounting = $vmhost | Get-Datastore | Where State -eq "Unavailable" foreach ($lunNeedingMounting in $lunsNeedingMounting) { $storSys.MountVmfsVolume($lunNeedingMounting.ExtensionData.Info.vmfs.uuid) } } } function Detach-SANDatastore { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true)] [VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore]$Datastore, [Parameter(Mandatory = $false)] [string]$Datacenter ) foreach($ds in $Datastore) { $hostviewDSDiskName = $ds.ExtensionData.Info.vmfs.extent[0].Diskname if($ds.ExtensionData.Host) { $attachedHosts = $ds.ExtensionData.host foreach($VMHost in $attachedHosts) { $dataCenterObj = get-vmhost -Id ("HostSystem-$($VMHost.key.value)") | Get-Datacenter [bool]$Proceed = $true if($Datacenter) { if($dataCenterObj.Name -ne $Datacenter) { $Proceed = $false } } if($Proceed) { $hostView = Get-View $vmHost.Key $StorageSys = Get-View $hostView.ConfigManager.StorageSystem $devices = $StorageSys.StorageDeviceInfo.ScsiLun foreach($device in $devices) { if ($device.canonicalName -eq $hostviewDSDiskName) { Write-Verbose "Unmounting LUN $($Device.canonicalName) from host $($hostview.Name)..." try { $StorageSys.UnmountVMFSVolume($ds.ExtensionData.Info.vmfs.uuid) } catch { } $LunUUID = $Device.Uuid Write-Verbose "Detaching LUN $($Device.canonicalName) from host $($hostview.Name)..." $StorageSys.DetachScsiLun($LunUUID) $StorageSys.RescanAllHba() } } } } } } } |