Microsoft.AVS.VVOLS/Microsoft.AVS.VVOLS.psm1 (506 lines of code) (raw):

<# .SYNOPSIS Creates a new vVol datastore and mounts to a VMware cluster. .PARAMETER ClusterName Cluster name .PARAMETER DatastoreName Datastore name .PARAMETER ScId Storage container ID of device used to create a new vVol datastore .EXAMPLE New-VVolDatastore -ClusterName "myCluster" -DatastoreName "myDatastore" -ScId $ScId .INPUTS vCenter cluster name, datastore name, and storage container ID .OUTPUTS None. #> function New-VvolDatastore { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param ( [Parameter( Mandatory = $true, HelpMessage = 'Cluster name in vCenter')] [ValidateNotNull()] [String] $ClusterName, [Parameter( Mandatory = $true, HelpMessage = 'Name of vVol datastore to be created in vCenter')] [ValidateNotNull()] [String] $DatastoreName, [Parameter( Mandatory = $true, HelpMessage = 'Storage container ID of device used to create a new vVol datastore')] [ValidateNotNull()] [String] $ScId ) $Cluster = Get-Cluster -Name $ClusterName -ErrorAction Ignore if (-not $Cluster) { throw "Cluster $ClusterName does not exist." } $Datastore = Get-Datastore -Name $DatastoreName -ErrorAction Ignore $VMHosts = $Cluster | Get-VMHost if ($Datastore) { $ExistingDatastoreScid = $Datastore.ExtensionData.Info.VVolds.Scid if ($ExistingDatastoreScid -ne $ScId) { throw "Unable to mount a datastore. Datastore '$DatastoreName' already exists with a different storage container ID." } $HostsWithDatastore = Get-VMHost -Datastore $DatastoreName $VMHostsToMount = $VMHosts | Where-Object { $HostsWithDatastore -notcontains $_ } if ($VMHostsToMount.Count -eq 0) { Write-Warning "Datastore '$DatastoreName' is already mounted to all hosts in cluster $ClusterName." } else { Write-Host "Datastore '$DatastoreName' is already mounted to some hosts in cluster $ClusterName. Mounting to remaining hosts..." } } else { $VMHostsToMount = $VMHosts } # We need to loop through Esxi to mount the datastore to all of hosts foreach ($Esxi in $VMHostsToMount) { # Create a new vVol datastore with the specified size and rescan storage $datastoreSystem = Get-View -Id $Esxi.ExtensionData.ConfigManager.DatastoreSystem $spec = New-Object VMware.Vim.HostDatastoreSystemVvolDatastoreSpec $spec.Name = $datastoreName $spec.ScId = $scId $Datastore = $esxi | Get-Datastore | Where-Object { $_.Type -eq "VVol" } | Where-Object { $_.ExtensionData.Info.VVolds.Scid -eq $scId } Write-Host "Mounting datastore $DatastoreName to host $($Esxi.Name)..." $datastoreSystem.CreateVvolDatastore($spec) } } <# .SYNOPSIS Removes a vVol datastore from a VMware cluster. .PARAMETER ClusterName Cluster name .PARAMETER DatastoreName Datastore name .EXAMPLE Remove-VVolDatastore -ClusterName "myCluster" -DatastoreName "myDatastore" .INPUTS vCenter cluster name, datastore name .OUTPUTS None. #> function Remove-VvolDatastore { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param ( [Parameter( Mandatory = $true, HelpMessage = 'Cluster name in vCenter')] [ValidateNotNull()] [String] $ClusterName, [Parameter( Mandatory = $true, HelpMessage = 'Name of vVol datastore to be created in vCenter')] [ValidateNotNull()] [String] $DatastoreName ) $Cluster = Get-Cluster -Name $ClusterName -ErrorAction Ignore if (-not $Cluster) { throw "Cluster $ClusterName does not exist." } $Datastore = Get-Datastore -Name $DatastoreName -ErrorAction Ignore if (-not $Datastore) { throw "Unable to remove a datastore. Datastore '$DatastoreName' does not exist." } $VM = $Datastore | Get-VM if ($VM) { throw "Unable to remove a datastore. Datastore '$DatastoreName' is already in use. Please make sure that no Virtual Machines are using this datastore." } if ("VVOL" -ne $Datastore.Type) { throw "Datastore $DatastoreName is of type $($Datastore.Type). This cmdlet can only process VVol datastores" } $VMHosts = $Cluster | Get-VMHost # We need to loop through Esxi to unmount the datastore from all of hosts foreach ($Esxi in $VMHosts) { # Unmount the datastore from the host $datastoreSystem = Get-View -Id $Esxi.ExtensionData.ConfigManager.DatastoreSystem Write-Host "Unmounting datastore $DatastoreName from host $($Esxi.Name)..." $datastoreSystem.RemoveDatastore($Datastore.ExtensionData.MoRef) } } <# .SYNOPSIS Refresh certificates for all ESXi hosts .DESCRIPTION Refresh certificates for all ESXi hosts .EXAMPLE Update-VMHostCertificate .INPUTS None. .OUTPUTS None. #> function Update-VMHostCertificate { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param () $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) | Out-Null } Write-Host "Certificates refreshed successfully for all of ESXi hosts." } <# .SYNOPSIS Create a new VASA provider in vCenter .PARAMETER ProviderName Name of VASA provider to be created in vCenter .PARAMETER FlashArrayMgmtIP URL of the VASA provider service .PARAMETER ProviderCredential Credential of the VASA provider service .EXAMPLE New-VvolVasaProvider -ProviderName "myProvider" -FlashArrayMgmtIP "1.0.0.0" -ProviderCredential $ProviderCredential #> function New-VvolVasaProvider { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param ( [Parameter( Mandatory = $true, HelpMessage = 'Name of VASA provider to be created in vCenter')] [ValidateNotNull()] [String] $ProviderName, [Parameter( Mandatory = $true, HelpMessage = 'URL of the VASA provider service')] [ValidateNotNull()] [String] $ProviderUrl, [Parameter( Mandatory = $true, HelpMessage = 'Credential of the VASA provider service')] [ValidateNotNull()] [PSCredential] $ProviderCredential ) $VasaProvider = Get-VasaProvider -Name $ProviderName -ErrorAction Ignore if ($vasaProvider) { throw "Unable to create a VASA provider. Vasa provider '$ProviderName' already exists." } New-VasaProvider -Name $ProviderName -Credential $ProviderCredential -Url $ProviderUrl -Force -ErrorAction Stop | Out-Null Write-Host "VASA provider $ProviderName created successfully." } <# .SYNOPSIS Remove a VASA provider from vCenter .PARAMETER ProviderName Name of VASA provider to be removed from vCenter .EXAMPLE Remove-VvolVasaProvider -ProviderName "myProvider" .INPUTS vCenter VASA provider name .OUTPUTS None. #> function Remove-VvolVasaProvider { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param ( [Parameter( Mandatory = $true, HelpMessage = 'Name of VASA provider to be created in vCenter')] [ValidateNotNull()] [String] $ProviderName ) $VasaProvider = Get-VasaProvider -Name $ProviderName -ErrorAction Ignore if (-not $VasaProvider) { throw "Unable to remove a VASA provider '$ProviderName'. Vasa provider '$ProviderName' does not exist." } # Find datastores connected to the vasa provider $Datastore = Get-Datastore | Where-Object { $_.ExtensionData.Info.VVolDS.VasaProviderInfo.Provider.Name -eq $VasaProvider.Name } if ($Datastore) { throw "Unable to remove a VASA provider. Vasa provider '$ProviderName' is connected to one or more datastores. Please remove the connected datastores first." } Remove-VasaProvider -Provider $VasaProvider -Confirm:$false -ErrorAction Stop | Out-Null Write-Host "VASA provider $ProviderName removed successfully." } <# .SYNOPSIS Creates a new vVol Storage Policy .PARAMETER PolicyConfigJsonString Storage policy in Json string. The command will traverse through the SPBM rules and creat a storage policy containing all of the rules. .EXAMPLE $policyConfigJsonString = @" { "SchemaVersion": "1.0.0", "Vendor": "Pure Storage", "PolicyName": "", "PolicyDescription": "", "SpbmRules": { "com.purestorage.storage.policy.FlashArrayGroup":["fa1","fa2"], "com.purestorage.storage.replication.LocalSnapshotPolicyCapable": true, "com.purestorage.storage.replication.LocalSnapshotInterval":"00:00:00" } "@" New-VvolStoragePolicy -PolicyConfigJsonString $policyConfigJsonString .INPUTS vCenter storage policy in Json string .OUTPUTS None. #> function New-VvolStoragePolicy { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param( [Parameter( Mandatory = $true, HelpMessage = 'Storage policy in Json string')] [ValidateNotNull()] [String]$PolicyConfigJsonString ) # Convert JSON to PowerShell object $PolicyConfig = ConvertFrom-Json $PolicyConfigJsonString # Extract values from the object $Vendor = $PolicyConfig.Vendor $PolicyName = $PolicyConfig.PolicyName if (-not $PolicyName) { throw "Unable to create a storage policy. Policy name is not specified." } $PolicyDescription = $PolicyConfig.PolicyDescription $SchemaVersion = $PolicyConfig.SchemaVersion if ($SchemaVersion -gt "1.0.0") { throw "Unable to create a storage policy. Schema version $SchemaVersion is not supported." } # Create SPBM rules dictionary $rules = @() $PolicyConfig.SpbmRules.PSObject.Properties | ForEach-Object { $RuleName = $_.Name $RuleValue = $_.Value if ($Vendor -eq "Pure Storage") { $ValueType = (Get-SpbmCapability -Name $RuleName).ValueType.Name if ($RuleValue -is [int64] -and $ValueType -eq "int32") { $RuleValue = [int]$RuleValue } if ($ValueType -eq "TimeSpan") { $RuleValue = [TimeSpan]::Parse($RuleValue) } } $rules += New-SpbmRule -Capability (Get-SpbmCapability -Name $RuleName) -Value $RuleValue } Write-Host "Creating policy $PolicyName for vendor $Vendor..." $Ruleset = New-SpbmRuleSet -AllOfRules $rules New-SpbmStoragePolicy -Name $PolicyName -Description $PolicyDescription -AnyOfRuleSets $Ruleset -ErrorAction Stop | Out-Null } <# .SYNOPSIS Removes a vVol Storage Policy .PARAMETER PolicyName Name of the storage policy to be removed .EXAMPLE Remove-VvolStoragePolicy -PolicyName "myPolicy" .INPUTS vCenter storage policy name .OUTPUTS None. #> function Remove-VvolStoragePolicy { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param( [Parameter( Mandatory = $true, HelpMessage = 'Storage policy name')] [ValidateNotNull()] [String]$PolicyName ) $Policy = Get-SpbmStoragePolicy -Name $PolicyName -ErrorAction Ignore if (-not $Policy) { throw "Unable to remove a storage policy. Storage policy '$PolicyName' does not exist." } Write-Host "Removing policy $PolicyName..." Remove-SpbmStoragePolicy -StoragePolicy $Policy -Confirm:$false -ErrorAction Stop | Out-Null } <# .SYNOPSIS Start a Replication Group failover or test failover .PARAMETER ReplicationGroupID Replication group ID .PARAMETER TestFailover Optional. Indicates whether to actually perform a failover(false) or to only perform a test failover(true). If not provided will only perform failover test. .PARAMETER PointInTimeReplicaName Optional. Point-in-time replica name. If not provided, the latest point-in-time replica will be used. .EXAMPLE Start-ReplicationFailover -ReplicationGroupID "myRepGroupID" -TestFailover $true .INPUTS Replication Group ID .OUTPUTS Replicated Virtual Machine names. #> function Start-ReplicationFailover { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param( [Parameter( Mandatory = $true, HelpMessage = 'Replication group ID')] [ValidateNotNull()] [String] $ReplicationGroupID, [Parameter( mandatory = $false, HelpMessage = 'Point-in-time replica name')] [String] $PointInTimeReplicaName, [Parameter( mandatory = $false, HelpMessage = 'Whether to perform a test failover or not')] [bool] $TestFailover ) $repGroup = Get-SpbmReplicationGroup -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "Target") { throw "Replication group '$ReplicationGroupID' need to be a replication group in 'Target' state." } if ($PointInTimeReplicaName) { $replica = Get-SpbmPointInTimeReplica -Name $PointInTimeReplicaName -ErrorAction Ignore if (-not $replica) { throw "Could not find point-in-time replica '$PointInTimeReplicaName'." } } ## Failing over the replication group for the VMs and setting the operations to a variable ## if ($TestFailover) { # does test failover, rep group status become InTest Write-Host "Starting test failover for replication group $ReplicationGroupID..." if ($PointInTimeReplicaName) { $replicatedVMFiles = Start-SpbmReplicationTestFailover -ReplicationGroup $repGroup -PointInTimeReplica $replica -Confirm:$false } else { $replicatedVMFiles = Start-SpbmReplicationTestFailover -ReplicationGroup $repGroup -Confirm:$false } } else { # does actual failover, rep group status become FailedOver Write-Host "Starting failover for replication group $ReplicationGroupID..." if ($PointInTimeReplicaName) { $replicatedVMFiles = Start-SpbmReplicationFailover -ReplicationGroup $repGroup -PointInTimeReplica $replica -Confirm:$false } else { $replicatedVMFiles = Start-SpbmReplicationFailover -ReplicationGroup $repGroup -Confirm:$false } } $NamedOutputs = @{} $i = 0 foreach ($VMFile in $replicatedVMFiles) { $NamedOutputs["vm_$i"] = $VMFile $i = $i + 1 } Set-Variable -Name NamedOutputs -Value $NamedOutputs -Scope Global } <# .SYNOPSIS Stop a Replication Group test failover .PARAMETER ReplicationGroupID Replication group ID .EXAMPLE Stop-ReplicationTestFailover -ReplicationGroupID "myRepGroupID" .INPUTS Replication Group ID .OUTPUTS None. #> function Stop-ReplicationTestFailover { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param( [Parameter( Mandatory = $true, HelpMessage = 'Replication group ID')] [ValidateNotNull()] [String]$ReplicationGroupID ) $repGroup = Get-SpbmReplicationGroup -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "InTest") { throw "Replication group '$ReplicationGroupID' need to be a replication group in 'InTest' state." } Write-Host "Stopping test failover for replication group $ReplicationGroupID..." Stop-SpbmReplicationTestFailover -ReplicationGroup $repGroup -Confirm:$false } <# .SYNOPSIS Start a Replication Group reverse .PARAMETER ReplicationGroupID Replication group ID .EXAMPLE Start-ReplicationReverse -ReplicationGroupID "myRepGroupID" .INPUTS Replication Group ID .OUTPUTS Reversed Replication Group Name. #> function Start-ReplicationReverse { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param( [Parameter( Mandatory = $true, HelpMessage = 'Replication group ID')] [ValidateNotNull()] [String]$ReplicationGroupID ) $repGroup = Get-SpbmReplicationGroup -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "FailedOver") { throw "Replication group '$ReplicationGroupID' need to be a replication group in 'FailedOver' state." } Write-Host "Starting reverse replication for replication group $ReplicationGroupID..." $newSourceGroup = Start-SpbmReplicationReverse -ReplicationGroup $repGroup.Name $NamedOutputs = @{} $NamedOutputs["new_source_group"] = $newSourceGroup.Name Set-Variable -Name NamedOutputs -Value $NamedOutputs -Scope Global } <# .SYNOPSIS Synchronize a replication group. Must be run on a "Target" Replication Group. .PARAMETER ReplicationGroupID Replication group ID .PARAMETER PointInTimeReplicaName Point-in-time replica name. If not provided, the latest point-in-time replica will be used. .EXAMPLE Sync-ReplicationGroup -ReplicationGroupID "myRepGroupID" -PointInTimeReplicaName "myReplica" .INPUTS Replication Group ID .OUTPUTS None. #> function Sync-ReplicationGroup { [CmdletBinding()] [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)] Param( [Parameter( Mandatory = $true, HelpMessage = 'Replication group ID')] [ValidateNotNull()] [String]$ReplicationGroupID, [Parameter( Mandatory = $true, HelpMessage = 'Point-in-time replica name')] [ValidateNotNull()] [String]$PointInTimeReplicaName ) $repGroup = Get-SpbmReplicationGroup -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "Target") { throw "Replication group '$ReplicationGroupID' need to be a replication group in 'Target' state." } Write-Host "Starting replication sync for replication group $ReplicationGroupID..." Sync-SpbmReplicationGroup -ReplicationGroup $repGroup -PointInTimeReplicaName $PointInTimeReplicaName }