Public/Set-Pool.ps1
Function Set-Pool { <# .SYNOPSIS Create or update Pool(s) .DESCRIPTION Can create new or update existing Pool(s). .PARAMETER InputObject The content of the Pool. .PARAMETER Application The iApp of the Pool. .PARAMETER Partition The partition on the F5 to put the Pool on. .PARAMETER PassThru Output the modified Pool to the pipeline. .EXAMPLE Set-Pool -Name 'northwindtraders_servers' -Description 'Northwind Traders example' -LoadBalancingMode dynamic-ratio-member Creates or updates a Pool. Note that parameters that are Mandatory for New-Pool (Name and LoadBalancingMode) must be specified for Pools that do not yet exist. .EXAMPLE Set-Pool -Name 'northwindtraders_servers' -Description 'Some useful description' Sets the description of an existing Pool. .EXAMPLE Set-Pool -Name 'northwindtraders_servers' -MemberDefinitionList {192.168.1.100,80},{192.168.1.101,80} .EXAMPLE $pool = Get-Pool -Name 'northwindtraders_servers'; $pool.minActiveMembers = if ($pool.minActiveMembers -lt 3) { 3 }; $pool | Set-Pool -PassThru; Set the minimum active pool members to 3 if currently less than 3 and returns the resulting Pool with -PassThru. #> [cmdletbinding(ConfirmImpact='Medium',SupportsShouldProcess,DefaultParameterSetName="Default")] param ( $F5Session=$Script:F5Session, [Parameter(Mandatory,ParameterSetName='InputObject',ValueFromPipeline)] [Alias('Pool')] [PSObject[]]$InputObject, #region Immutable fullPath component params [Alias('PoolName')] [Parameter(Mandatory,ValueFromPipelineByPropertyName)] $Name, [Alias('iApp')] [Parameter(ValueFromPipelineByPropertyName)] $Application='', [Parameter(ValueFromPipelineByPropertyName)] $Partition='Common', #endregion #region New-Pool equivalents [string]$Description, [ValidateSet('dynamic-ratio-member','dynamic-ratio-node','fastest-app-response','fastest-node','least-connections-member','least-connections-node','least-sessions','observed-member','observed-node','predictive-member','predictive-node','ratio-least-connections-member','ratio-least-connections-node','ratio-member','ratio-node','ratio-session','round-robin','weighted-least-connections-member','weighted-least-connections-node')] [string]$LoadBalancingMode, [string[]]$MemberDefinitionList, #endregion [switch]$PassThru ) begin { Test-F5Session -F5Session ($F5Session) Write-Verbose "NB: Pool names are case-specific." $knownproperties = @{ name='name' partition='partition' kind='kind' description='description' loadBalancingMode='loadBalancingMode' membersReference='membersReference' monitor='monitor' } } process { if ($InputObject -and ( ($Name -and $Name -cne $InputObject.name) -or ($Partition -and $Partition -cne $InputObject.partition) -or ($Application -and $Application -cne $InputObject.application) ) ) { throw 'Set-Pool does not support moving or renaming at this time. Use New-Pool and Remove-Pool.' } $NewProperties = @{} # A hash table to facilitate splatting of New-Pool params $ChgProperties = @{} # A hash table of PSBoundParameters to override InputObject properties # Build out both hashtables based on $PSBoundParameters foreach ($key in $PSBoundParameters.Keys) { switch ($key) { 'InputObject' {} # Ignore 'PassThru' {} # Ignore { @('F5Session','MemberDefinitionList') -contains $key } { $NewProperties[$key] = $PSBoundParameters[$key] } default { if ($knownproperties.ContainsKey($key)) { $NewProperties[$key] = $ChgProperties[$knownproperties[$key]] = $PSBoundParameters[$key] } } } } $ExistingPool = Get-Pool -F5Session $F5Session -Name $Name -Application $Application -Partition $Partition -ErrorAction SilentlyContinue if ($null -eq $ExistingPool) { Write-Verbose -Message 'Creating new Pool...' $null = New-Pool @NewProperties } # This performs the magic necessary for ChgProperties to override $InputObject properties $NewObject = Join-Object -Left $InputObject -Right ([pscustomobject]$ChgProperties) -Join FULL -WarningAction SilentlyContinue if ($null -ne $NewObject -and $pscmdlet.ShouldProcess($F5Session.Name, "Setting Pool $Name")) { # We only update the pool if properties other than 'Name' are passed in If ($NewObject | Get-Member -MemberType NoteProperty | Where-Object Name -ne 'Name'){ Write-Verbose -Message 'Setting Pool details...' $URI = $F5Session.BaseURL + 'pool/{0}' -f (Get-ItemPath -Name $Name -Application $Application -Partition $Partition) $JSONBody = $NewObject | ConvertTo-Json -Compress #region case-sensitive parameter names # If someone inputs their own custom PSObject with properties with unexpected case, this will correct the case of known properties. # It could arguably be removed. If not removed, it should be refactored into a shared (Private) function for use by all Set-* functions in the module. $knownRegex = '(?<=")({0})(?=":)' -f ($knownproperties.Keys -join '|') # Use of regex.Replace with a callback is more efficient than multiple, separate replacements $JsonBody = [regex]::Replace($JSONBody,$knownRegex,{param($match) $knownproperties[$match.Value] }, [Text.RegularExpressions.RegexOptions]::IgnoreCase) #endregion $null = Invoke-F5RestMethod -Method PATCH -URI "$URI" -F5Session $F5Session -Body $JSONBody -ContentType 'application/json' } # MemberDefinitionList should trump existing members IFF there is an ExistingPool, otherwise New-Pool will take care of initializing the members. if ($MemberDefinitionList -and $ExistingPool) { Write-Verbose -Message 'Setting Pool members...' # Remove all existing pool members Get-PoolMember -F5Session $F5Session -PoolName $Name -Partition $Partition | Remove-PoolMember -F5Session $F5Session -Confirm:$false # Add requested pool members ForEach ($MemberDefinition in $MemberDefinitionList){ $Node,$PortNumber = $MemberDefinition -split ',' $null = Add-PoolMember -F5Session $F5Session -PoolName $Name -Partition $Partition -Address $Node -PortNumber $PortNumber -Status Enabled } } } if ($PassThru) { Get-Pool -F5Session $F5Session -Name $Name -Application $Application -Partition $Partition } } } |