CommonUtil.ps1
<# Common Utility functions. #> . $PSScriptRoot/PureStorage.CBS.VVolUtil.ps1 function Get-PCBSHostGroup { <# .SYNOPSIS Get all host groups from a Flash Array .DESCRIPTION Get list of host groups from Flash Array included IP Ranges .PARAMETER FlasharrayAddress Flash Array IP address of FQDN .PARAMETER FlasharrayUsername Flash Array username .PARAMETER FlasharrayPassword Flash Array password #> Param( [Parameter(mandatory=$true)] [String]$FlasharrayAddress, [Parameter(mandatory=$true)] [String]$FlasharrayUsername, [Parameter(mandatory=$true)] [SecureString]$FlasharrayPassword ) $hgroup_result = Invoke-Pfa2CLICommand -Endpoint $FlasharrayAddress -Username $FlasharrayUsername -Password $FlasharrayPassword -CommandText "purehgroup list --csv" $result = ConvertFrom-Csv -InputObject $hgroup_result # TODO: Verify that "IP Range" is in result foreach ($r in $result) { $members = $r | Get-Member | Where {$_.Name -eq "IP Range"} if ($members.Count -le 0) { throw "Could not find 'IP Range'. PLease make sure to use a supported FlashArray" } } return $result } function Get-PCBSHostGroupByIPRange { <# .SYNOPSIS Get host groups from a Flash Array with a specific IP Range .DESCRIPTION Get host groups from a Flash Array with a specific IP Range (inclusive of start and end). Will return an empty list if no host groups are found with the specified IP Range .PARAMETER FlasharrayAddress Flash Array IP address of FQDN .PARAMETER FlasharrayUsername Flash Array username .PARAMETER FlasharrayPassword Flash Array password .PARAMETER IPRangeStart IP Range start .PARAMETER IPRangeEnd IP Range end #> Param( [Parameter(mandatory=$true)] [String]$FlasharrayAddress, [Parameter(mandatory=$true)] [String]$FlasharrayUsername, [Parameter(mandatory=$true)] [SecureString]$FlasharrayPassword, [Parameter(mandatory=$true)] [String] $IPRangeStart, [Parameter(mandatory=$true)] [String] $IPRangeEnd ) $result = @() $hgroups = Get-PCBSHostGroup -FlasharrayAddress $FlasharrayAddress -FlasharrayUsername $FlasharrayUsername -FlasharrayPassword $FlasharrayPassword foreach ($hgroup in $hgroups) { # If more than one IP Range is listed, they will be separated by "/" $ip_ranges = $hgroup."IP Range" -Split "/" | ConvertFrom-Json foreach ($ip_range in $ip_ranges) { if ($ip_range."start" -eq $IPRangeStart -and $ip_range."start" -eq $IPRangeStart) { $result += $hgroup } } } return $result } function New-PCBSHostGroup { <# .SYNOPSIS Create a new host group on Flash Array .DESCRIPTION Create a new host group on with a specified Ip Range Flash Array .PARAMETER FlasharrayAddress Flash Array IP address of FQDN .PARAMETER FlasharrayUsername Flash Array username .PARAMETER FlasharrayPassword Flash Array password .PARAMETER HostGroupName Host group name .PARAMETER HostGroupNameSpace Host group namespace .PARAMETER IPRangeStart IP Range start .PARAMETER IPRangeEnd IP Range end .EXAMPLE An example .NOTES General notes #> Param( [Parameter(mandatory=$true)] [String]$FlasharrayAddress, [Parameter(mandatory=$true)] [String]$FlasharrayUsername, [Parameter(mandatory=$true)] [SecureString]$FlasharrayPassword, [Parameter(mandatory=$true)] [String]$HostGroupName, [Parameter(mandatory=$false)] [String]$HostGroupNameSpace, [Parameter(mandatory=$true)] [String] $IPRangeStart, [Parameter(mandatory=$true)] [String] $IPRangeEnd ) $command = "purehgroup create --iprangelist $IPRangeStart-$IPRangeEnd --personality esxi $HostGroupName" $result = Invoke-Pfa2CLICommand -Endpoint $FlasharrayAddress -Username $FlasharrayUsername -Password $FlasharrayPassword -CommandText $command return $result } function Get-PurityIdentifiefFromVMWareIdentifier { Param ( [String] $name ) $updated_name = $name if (-not $name -match "^[a-zA-Z0-9\-]+$") { $updated_name = $updated_name -replace "[^\w\-]", "" $updated_name = $updated_name -replace "[_]", "" $updated_name = $updated_name -replace " ", "" } return $updated_name } function Convert-EpochToDateTime { Param ( [int64] $EpochMillseconds ) $start_date = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0 return $start_date.AddMilliseconds($EpochMillseconds) } function Update-ESXCertificates { <# .SYNOPSIS Refresh certificates for all ESXi hosts .DESCRIPTION Refresh certificates for all ESXi hosts #> $service_instance = Get-View ServiceInstance $certMgr = Get-View -Id $service_instance.Content.CertificateManager Get-VMHost | ForEach-Object -Process { Write-Host "Refreshing certificates for $($_.Name).." $certMgr.CertMgrRefreshCACertificatesAndCRLs($_.Id) } } function Remove-PCBSStaticiSCSITargets { <# .SYNOPSIS Remove statis iSCSI Targets .DESCRIPTION Remove statis iSCSI Targets .PARAMETER Esxi ESXi VMware object #> Param( [Parameter(Position=0,mandatory=$true)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost]$Esxi ) $ESXi | Get-VMHostHba -Type iScsi | Get-IScsiHbaTarget | Where {$_.Type -eq "Static"} | Remove-IScsiHbaTarget -Confirm:$false } function New-PCBSDynamicHostGroup { Param ( [String]$ClusterName, [String]$iSCSIRangeStart, [String]$iSCSIRangeEnd, [String]$FlasharrayAddress, [String]$FlasharrayUsername, [SecureString]$FlasharrayPassword ) # Create dynmaic host group if it does not exist $hgroups = Get-PCBSHostGroupByIPRange -FlasharrayAddress $FlasharrayAddress -FlasharrayUsername $FlasharrayUsername -FlasharrayPassword $FlasharrayPassword -IPRangeStart $iSCSIRangeStart -IPRangeEnd $iSCSIRangeEnd if ($hgroups.Count -eq 0) { # HostGgroup does not exist. We need to create it $HostGroupName = Get-PurityIdentifiefFromVMWareIdentifier -Name $ClusterName Write-Host "Creating host group $HostGroupName ..." $hgroup = New-PCBSHostGroup -FlasharrayAddress $FlasharrayAddress -FlasharrayUsername $FlasharrayUsername -FlasharrayPassword $FlasharrayPassword -IPRangeStart $iSCSIRangeStart -IPRangeEnd $iSCSIRangeEnd -HostGroupName $HostGroupName Write-Host "$HostGroupName was created successfully." } else { $HostGroupName = $hgroups[0].Name Write-Host "HostGroup ($HostGroupName) for iSCSI Range ($iSCSIRangeStart -> $iSCSIRangeEnd) already exists." } # Create software iSCSI adaptor for each ESXi host $fa = Connect-Pfa2Array -EndPoint $FlasharrayAddress -Username $FlasharrayUsername -Password $FlasharrayPassword -IgnoreCertificateError $ESXHosts = $Cluster | Get-VMHost foreach ($ESXHost in $ESXHosts) { Write-Host "Configuring iSCSI target for $ESXHost ..." Set-VmHostPfaiSCSI -esxi $ESXHost -flasharray $fa Write-Host "Removing static iSCSI targets for $ESXHost ..." Remove-StaticiSCSITargets -esxi $ESXHost Write-Host "Rescanning HBA for $ESXHost ..." Get-VMHostStorage -VMHost $ESXHosts -RescanAllHba | Out-Null } } function New-PfaVmfsFromSnapshot { <# .SYNOPSIS Mounts a copy of a VMFS datastore to a VMware cluster from a FlashArray snapshot. .DESCRIPTION Takes in a snapshot name, the corresponding FlashArray, and a cluster. The VMFS copy will be resignatured and mounted. .INPUTS FlashArray connection, a snapshotName, and a cluster. .OUTPUTS Returns the new datastore. #> [CmdletBinding()] Param( [Parameter(Mandatory=$true,ValueFromPipeline=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.Cluster]$cluster, [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$true)] [string]$snapName, [Parameter(Mandatory=$false)] [string]$volumeName ) $volumeSnapshot = Get-Pfa2VolumeSnapshot -Name $snapName -ErrorAction Ignore if (-not $volumeSnapshot) { throw "Could not find snapshot $snapName." } if ([string]::IsNullOrWhiteSpace($volumeName)) { $volumeName = $volumeSnapshot.Source.Name + "-"+(Get-Random -Minimum 10000 -Maximum 99999) } Write-Host "Creating a volume $volumeName..." $newVol = New-Pfa2Volume -Array $FlashArray -Name $volumeName -SourceName $snapName $hostGroup = Get-PCBSHostGroupfromVcCluster -cluster $cluster -FlashArray $FlashArray Write-Host "Connecting volume $volumeName to host group $($hostGroup.Name)..." New-Pfa2Connection -VolumeName $volumeName -HostGroupName $hostGroup.name $esxi = $cluster | Get-VMHost| where-object {($_.ConnectionState -eq 'Connected')} |Select-Object -last 1 Write-Host "Rescanning HBA..." $esxi | Get-VMHostStorage -RescanAllHba -RescanVMFS -ErrorAction stop |Out-Null $hostStorage = get-view -ID $esxi.ExtensionData.ConfigManager.StorageSystem $resigVolumes= $hostStorage.QueryUnresolvedVmfsVolume() $newNAA = "naa.624a9370" + $newVol.serial.toLower() $deleteVol = $false foreach ($resigVolume in $resigVolumes) { if ($deleteVol -eq $true) { break } foreach ($resigExtent in $resigVolume.Extent) { if ($resigExtent.Device.DiskName -eq $newNAA) { if ($resigVolume.ResolveStatus.Resolvable -eq $false) { if ($resigVolume.ResolveStatus.MultipleCopies -eq $true) { Write-Error "The volume cannot be resignatured as more than one unresignatured copy is present. Deleting and ending." Write-Error "The following volume(s) are presented and need to be removed/resignatured first:" $resigVolume.Extent.Device.DiskName |where-object {$_ -ne $newNAA} } $deleteVol = $true break } else { $volToResignature = $resigVolume break } } } } if (($null -eq $volToResignature) -and ($deleteVol -eq $false)) { Write-Error "No unresolved volume found on the created volume. Deleting and ending." $deleteVol = $true } if ($deleteVol -eq $true) { Write-Host "Removing volume $($newVol.Name)..." Remove-Pfa2Connection -Array $FlashArray -HostgroupNames $hostGroup.name -VolumeNames $newVol.name -ErrorAction SilentlyContinue Remove-Pfa2Volume -Array $FlashArray -Name $newVol.name -ErrorAction SilentlyContinue Remove-Pfa2Volume -Array $FlashArray -Name $newVol.name -Eradicate -ErrorAction SilentlyContinue throw "Failed to create datastore $volumeName from snapshot $snapName" } Write-Host "Starting resignature for $volumeName..." $esxcli=get-esxcli -VMHost $esxi -v2 -ErrorAction stop $resigOp = $esxcli.storage.vmfs.snapshot.resignature.createargs() $resigOp.volumelabel = $volToResignature.VmfsLabel $esxcli.storage.vmfs.snapshot.resignature.invoke($resigOp) |out-null Start-sleep -s 5 $esxi | Get-VMHostStorage -RescanVMFS -ErrorAction stop |Out-Null $datastores = $esxi| Get-Datastore -ErrorAction stop foreach ($ds in $datastores) { $naa = $ds.ExtensionData.Info.Vmfs.Extent.DiskName if ($naa -eq $newNAA) { $resigds = $ds | Set-Datastore -Name $newVol.name -ErrorAction stop return $resigds } } } |