F5-LTM.psm1
<#
.SYNOPSIS A module for using the F5 LTM REST API to administer an LTM device .DESCRIPTION This module uses the F5 LTM REST API to manipulate and query pools, pool members, virtual servers and iRules It is built to work with version 11.6 .NOTES File Name : F5-LTM.psm1 Author : Joel Newton - jnewton@springcm.com Requires : PowerShell V3 Dependencies : It includes a Validation.cs class file (based on code posted by Brian Scholer) to allow for using the REST API with LTM devices using self-signed SSL certificates. #> Add-Type -Path "${PSScriptRoot}\Validation.cs" Function Get-F5session{ <# .SYNOPSIS Generate an F5 session object to be used in querying and changing the F5 LTM .DESCRIPTION This function takes the DNS name or IP address of the F5 LTM device, and a username for an account with the privileges modify the LTM via the REST API, and the user's password as a secure string. To generate a secure string from plain text, use: $F5Password = ConvertTo-SecureString -String $Password -AsPlainText -Force #> param( [Parameter(Mandatory=$true)][string]$LTMName, [Parameter(Mandatory=$true)][System.Management.Automation.PSCredential]$LTMCredentials ) $BaseURL = "https://$LTMName/mgmt/tm/ltm/" #Create custom credential object for connecting to REST API [pscustomobject]@{BaseURL = $BaseURL; Credential = $LTMCredentials} } Function Test-Functionality{ <# .SYNOPSIS Perform some standard tests to make sure things work as expected .EXAMPLE Test-Functionality -F5Session $f5 -TestVirtualServer 'virt123' -TestVirtualServerIP '10.1.1.240' -TestPool 'testpool123' -PoolMember 'Server1' #> param ( [Parameter(Mandatory=$true)]$F5Session, [Parameter(Mandatory=$true)]$TestVirtualServer, [Parameter(Mandatory=$true)]$TestVirtualServerIP, [Parameter(Mandatory=$true)]$TestPool, [Parameter(Mandatory=$true)]$PoolMember ) $TestNotesColor = 'Cyan' Write-Host "-----`r`nBeginning test`r`n-----" -ForegroundColor $TestNotesColor Write-Host "* Get the failover status of the F5 device" -ForegroundColor $TestNotesColor Get-F5Status -F5session $F5session Write-Host "`r`n* Get a list of all pools" -ForegroundColor $TestNotesColor Get-PoolList -F5session $F5Session $pools = Get-PoolList -F5session $F5Session Write-Host ("`r`n* Test whether the first pool in the list - " + $pools[0] + " - exists") -ForegroundColor $TestNotesColor Test-Pool -F5session $F5Session -PoolName $pools[0] Write-Host ("`r`n* Get the pool " + $pools[0]) -ForegroundColor $TestNotesColor Get-Pool -F5session $F5Session -PoolName $pools[0] Write-Host ("`r`n* Get members of the pool '" + $pools[0] + "'") -ForegroundColor $TestNotesColor Get-PoolMemberCollection -F5session $F5Session -PoolName $pools[0] Write-Host ("`r`n* Get the status of all members in the " + $pools[0] + " pool") -ForegroundColor $TestNotesColor Get-PoolMemberCollectionStatus -F5session $F5Session -PoolName $pools[0] Write-Host "`r`n* Create a new pool named '$TestPool'" -ForegroundColor $TestNotesColor New-Pool -F5session $F5Session -PoolName $TestPool Write-Host "`r`n* Add the computer $PoolMember to the pool '$TestPool'" -ForegroundColor $TestNotesColor Add-PoolMember -F5session $F5session -ComputerName $PoolMember -PortNumber 80 -PoolName $TestPool -Status Enabled Write-Host "`r`n* Get the new pool member" -ForegroundColor $TestNotesColor Get-PoolMember -F5session $F5session -ComputerName $PoolMember -PoolName $TestPool Write-Host "`r`n* Get the IP address for the new pool member" -ForegroundColor $TestNotesColor Get-PoolMemberIP -F5Session $F5Session -ComputerName $PoolMember -PoolName $TestPool Write-Host "`r`n* Get all pools of which this pool member is a member" -ForegroundColor $TestNotesColor Get-PoolsForMember -F5session $F5Session -ComputerName $PoolMember Write-Host "`r`n* Get the number of current connections for this pool member" -ForegroundColor $TestNotesColor Get-CurrentConnectionCount -F5session $F5Session -ComputerName $PoolMember -PoolName $TestPool Write-Host "`r`n* Disable the new pool member" -ForegroundColor $TestNotesColor Disable-PoolMember -F5session $F5session -ComputerName $PoolMember Write-Host "`r`n* Get the status of the new pool member" -ForegroundColor $TestNotesColor $PoolMemberStatus = Get-PoolMemberStatus -F5session $F5session -ComputerName $PoolMember -PoolName $TestPool $PoolMemberStatus Write-Host "`r`n* Set the pool member description to 'My new pool' and retrieve it" -ForegroundColor $TestNotesColor Write-Host "Old description:" Get-PoolMemberDescription -F5Session $F5session -ComputerName $PoolMember -PoolName $TestPool Set-PoolMemberDescription -ComputerName $PoolMember -PoolName $TestPool -Description 'My new pool' -F5Session $F5session | out-null Write-Host "New description:" Get-PoolMemberDescription -F5Session $F5session -ComputerName $PoolMember -PoolName $TestPool Write-Host "`r`n* Enable the new pool member" -ForegroundColor $TestNotesColor Enable-PoolMember -F5session $F5session -ComputerName $PoolMember Write-Host "`r`n* Remove the new pool member from the pool" -ForegroundColor $TestNotesColor Remove-PoolMember -F5session $F5session -ComputerName $PoolMember -PortNumber 80 -PoolName $TestPool Write-Host "`r`n* Get a list of all virtual servers" -ForegroundColor $TestNotesColor Get-VirtualServerList -F5Session $F5Session $virtualServers = Get-VirtualServerList -F5Session $F5Session Write-Host ("`r`n* Test whether the first virtual server in the list - " + $virtualServers[0] + " - exists") -ForegroundColor $TestNotesColor Test-VirtualServer -F5Session $F5Session -VirtualServerName $virtualServers[0] Write-Host ("`r`n* Get the virtual server '" + $virtualServers[0] + "'") -ForegroundColor $TestNotesColor Get-VirtualServer -F5Session $F5Session -VirtualServerName $virtualServers[0] Write-Host "`r`n* Create a new virtual server named '$TestVirtualServer'" -ForegroundColor $TestNotesColor New-VirtualServer -F5Session $F5Session -VirtualServerName $TestVirtualServer -Description 'description' -DestinationIP $TestVirtualServerIP -DestinationPort '80' -DefaultPool $TestPool -IPProtocol 'tcp' -ProfileNames 'http' Write-Host ("`r`n* Retrieve all iRules on the F5 LTM device.") -ForegroundColor $TestNotesColor $iRules = Get-iRuleCollection -F5session $F5Session Write-Output ("- This can be a large collection. The first entry found is:") Write-Output $iRules[0] Write-Host ("`r`n* Add the iRule '" + $iRules[0].name + "' to the new virtual server '$TestVirtualServer'") -ForegroundColor $TestNotesColor Add-iRuleToVirtualServer -F5session $F5Session -VirtualServer $TestVirtualServer -iRuleName $($iRules[0].name) Write-Host "`r`n* Get all iRules assigned to '$TestVirtualServer'" -ForegroundColor $TestNotesColor Get-VirtualServeriRuleCollection -F5session $F5Session -VirtualServer $TestVirtualServer Write-Host ("`r`n* Remove the '" + $iRules[0].name + "' iRule from the new virtual server '$TestVirtualServer'") -ForegroundColor $TestNotesColor Remove-iRuleFromVirtualServer -F5session $F5Session -VirtualServer $TestVirtualServer -iRuleName $iRules[0].name Write-Host "`r`n* Remove the new virtual server '$TestVirtualServer'" -ForegroundColor $TestNotesColor Write-Host "(This will raise a confirmation prompt unless -confirm is set to false)" -ForegroundColor $TestNotesColor Remove-VirtualServer -F5session $F5Session -VirtualServerName $TestVirtualServer Write-Host "`r`n* Remove the new pool '$TestPool'" -ForegroundColor $TestNotesColor Write-Host "(This will raise a confirmation prompt unless -confirm is set to false)" -ForegroundColor $TestNotesColor Remove-Pool -F5session $F5Session -PoolName $TestPool Write-Host "-----`r`nTest complete`r`n-----" -ForegroundColor $TestNotesColor } Function Invoke-RestMethodOverride { param ( [Parameter(Mandatory=$true)][string]$Method, [Parameter(Mandatory=$true)][string]$URI, [Parameter(Mandatory=$true)][System.Management.Automation.PSCredential]$Credential, $Body=$null, $Headers=$null, $ContentType=$null ) [SSLValidator]::OverrideValidation() Invoke-RestMethod -Method $Method -Uri $URI -Credential $Credential -Body $Body -Headers $Headers -ContentType $ContentType [SSLValidator]::RestoreValidation() } Function Get-F5Status{ <# .SYNOPSIS Test whether the specified F5 is currently in active or standby failover mode #> param ( [Parameter(Mandatory=$true)]$F5session ) $FailoverPage = $F5Session.BaseURL -replace "/ltm/", "/cm/failover-status" $FailoverJSON = Invoke-RestMethodOverride -Method Get -Uri $FailoverPage -Credential $F5Session.Credential #This is where the failover status is indicated $FailOverStatus = $FailoverJSON.entries.'https://localhost/mgmt/tm/cm/failover-status/0'.nestedStats.entries.status.description #Return the failover status value $FailOverStatus } Function Sync-DeviceToGroup{ <# .SYNOPSIS Sync the specified device to the group. This assumes the F5 session object is for the device that will be synced to the group. #> param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$GroupName ) $URI = $F5session.BaseURL -replace "/ltm", "/cm" $JSONBody = @{command='run';utilCmdArgs="config-sync to-group $GroupName"} $JSONBody = $JSONBody | ConvertTo-Json Try{ $response = Invoke-RestMethodOverride -Method POST -Uri "$URI" -Credential $F5Session.Credential -Body $JSONBody -ContentType 'application/json' Write-Output $true } Catch { Write-Error ("Failed to sync the device to the $GroupName group") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Get-VirtualServerList{ <# .SYNOPSIS Get a list of all virtual servers for the specified F5 LTM #> param ( [Parameter(Mandatory=$true)]$F5session ) #Only retrieve the pool names $VirtualServersPage = $F5session.BaseURL + 'virtual?$select=name' Try { $VirtualServersJSON = Invoke-RestMethodOverride -Method Get -Uri $VirtualServersPage -Credential $F5session.Credential $VirtualServersJSON.items.name } Catch{ Write-Error ("Failed to retrieve the list of virtual servers.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Get-VirtualServer{ <# .SYNOPSIS Retrieve the specified virtual server #> param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$VirtualServerName ) Write-Verbose "NB: Virtual server names are case-specific." #Build the URI for this virtual server $URI = $F5session.BaseURL + "virtual/$VirtualServerName" Try { Invoke-RestMethodOverride -Method Get -Uri $URI -Credential $F5session.Credential } Catch{ Write-Error ("Failed to retrieve the $VirtualServerName virtual server.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Test-VirtualServer { <# .SYNOPSIS Test whether the specified virtual server exists .NOTES Pool names are case-specific. #> param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$VirtualServerName ) Write-Verbose "NB: Virtual server names are case-specific." #Build the URI for this virtual server $URI = $F5session.BaseURL + "virtual/$VirtualServerName" Try { Invoke-RestMethodOverride -Method Get -Uri $URI -Credential $F5session.Credential | out-null $true } Catch{ $false } } Function New-VirtualServer{ <# .SYNOPSIS Create a new virtual server #> param ( [Parameter(Mandatory=$true)]$F5session, $Kind="tm:ltm:virtual:virtualstate", [Parameter(Mandatory=$true)][string]$VirtualServerName, $Description=$null, [Parameter(Mandatory=$true)]$DestinationIP, [Parameter(Mandatory=$true)]$DestinationPort, $Source='0.0.0.0/0', $DefaultPool=$null, [string[]]$ProfileNames=$null, [Parameter(Mandatory=$true,ParameterSetName = 'IpProtocol')] [ValidateSet("tcp","udp","sctp")] $ipProtocol=$null, $Mask='255.255.255.255', $ConnectionLimit='0' ) $URI = ($F5session.BaseURL + "virtual") #Check whether the specified virtual server already exists If (Test-VirtualServer -F5session $F5session -VirtualServerName $VirtualServerName){ Write-Error "The $VirtualServerName pool already exists." } Else { #Start building the JSON for the action $Destination = $DestinationIP + ":" + $DestinationPort $JSONBody = @{kind=$Kind;name=$VirtualServerName;description=$Description;partition='Common';destination=$Destination;source=$Source;pool=$DefaultPool;ipProtocol=$ipProtocol;mask=$Mask;connectionLimit=$ConnectionLimit} #Build array of profile items #JN: What happens if a non-existent profile is passed in? $ProfileItems = @() ForEach ($ProfileName in $ProfileNames){ $ProfileItems += @{kind='tm:ltm:virtual:profiles:profilesstate';name=$ProfileName} } $JSONBody.profiles = $ProfileItems $JSONBody = $JSONBody | ConvertTo-Json Write-Verbose $JSONBody Try{ Invoke-RestMethodOverride -Method POST -Uri "$URI" -Credential $F5Session.Credential -Body $JSONBody -ContentType 'application/json' } Catch { Write-Error ("Failed to retrieve the $VirtualServerName virtual server.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } } Function Remove-VirtualServer{ <# .SYNOPSIS Remove the specified virtual server. Confirmation is needed. .NOTES Virtual server names are case-specific. #> [CmdletBinding( SupportsShouldProcess=$true, ConfirmImpact="High")] param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$VirtualServerName ) Write-Verbose "NB: Virtual server names are case-specific." #Build the URI for this pool $URI = $F5session.BaseURL + "virtual/$VirtualServerName" if ($pscmdlet.ShouldProcess($VirtualServerName)){ #Check whether the specified virtual server exists If (!(Test-VirtualServer -F5session $F5session -VirtualServerName $VirtualServerName)){ Write-Error "The $VirtualServerName virtual server does not exist." } Else { Try { $response = Invoke-RestMethodOverride -Method DELETE -Uri "$URI" -Credential $F5session.Credential -ContentType 'application/json' Write-Output $true } Catch { Write-Error ("Failed to remove the $VirtualServerName virtual server.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } } } Function Get-PoolList { <# .SYNOPSIS Get a list of all pools for the specified F5 LTM #> param ( [Parameter(Mandatory=$true)]$F5session ) #Only retrieve the pool names $PoolsPage = $F5session.BaseURL + 'pool/?$select=name' Try { $PoolsJSON = Invoke-RestMethodOverride -Method Get -Uri $PoolsPage -Credential $F5session.Credential $PoolsJSON.items.name } Catch{ Write-Error ("Failed to get the list of pool names.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Get-Pool { <# .SYNOPSIS Retrieve the specified pool .NOTES Pool names are case-specific. #> param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$PoolName ) Write-Verbose "NB: Pool names are case-specific." #Build the URI for this pool $URI = $F5session.BaseURL + "pool/$PoolName" Try { Invoke-RestMethodOverride -Method Get -Uri $URI -Credential $F5session.Credential -ErrorAction SilentlyContinue } Catch{ Write-Error ("Failed to get the $PoolName pool.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Test-Pool { <# .SYNOPSIS Test whether the specified pool exists .NOTES Pool names are case-specific. #> param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$PoolName ) Write-Verbose "NB: Pool names are case-specific." #Build the URI for this pool $URI = $F5session.BaseURL + "pool/$PoolName" Try { Invoke-RestMethodOverride -Method Get -Uri $URI -Credential $F5session.Credential -ErrorAction SilentlyContinue | out-null $true } Catch { $false } } Function New-Pool { <# .SYNOPSIS Create a new pool. Optionally, add pool members to the new pool .DESCRIPTION Expects the $MemberDefinitionList param to be an array of strings. Each string should contain a computer name and a port number, comma-separated. Optionally, it can contain a description of the member. .EXAMPLE New-Pool -F5Session $F5Session -PoolName "MyPoolName" -MemberDefinitionList @("Server1,80,Web server","Server2,443,Another web server") #> param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$PoolName, [string[]]$MemberDefinitionList=$null ) $URI = ($F5session.BaseURL + "pool") #Check whether the specified pool already exists If (Test-Pool -F5session $F5session -PoolName $PoolName){ Write-Error "The $PoolName pool already exists." } Else { #Start building the JSON for the action $JSONBody = @{name=$PoolName;partition='Common';members=@()} $Members = @() ForEach ($MemberDefinition in $MemberDefinitionList){ #Build the member name from the IP address and the port $MemberObject = $MemberDefinition.Split(",") If ($MemberObject.Length -lt 2){ Throw("All member definitions should consist of a string containing at least a computer name and a port, comma-separated.") } $IPAddress = Get-CimInstance -ComputerName $MemberObject[0] -Class Win32_NetworkAdapterConfiguration | Where-Object DefaultIPGateway | Select-Object -exp IPaddress | Select-Object -first 1 Try { $PortNumber = [int]$MemberObject[1] } Catch { $ThrowMessage = $MemberObject[1] + " is not a valid value for a port number." Throw($ThrowMessage) } If (($PortNumber -lt 0) -or ($PortNumber -gt 65535)){ $ThrowMessage = $MemberObject[1] + " is not a valid value for a port number." Throw($ThrowMessage) } $Member = @{name=$($IPAddress + ":" + $PortNumber);address=$IPAddress;description=$($MemberObject[2])} $Members += $Member } $JSONBody.members = $Members $JSONBody = $JSONBody | ConvertTo-Json Try { $response = Invoke-RestMethodOverride -Method POST -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody -Headers @{"Content-Type"="application/json"} $true } Catch{ Write-Error ("Failed to create the $PoolName pool.") Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } } Function Remove-Pool{ <# .SYNOPSIS Remove the specified pool. Confirmation is needed .NOTES Pool names are case-specific. #> [CmdletBinding( SupportsShouldProcess=$true, ConfirmImpact="High")] param ( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)][string]$PoolName ) #Build the URI for this pool $URI = $F5session.BaseURL + "pool/$PoolName" if ($pscmdlet.ShouldProcess($PoolName)){ #Check whether the specified pool already exists If (!(Test-Pool -F5session $F5session -PoolName $PoolName)){ Write-Error "The $PoolName pool does not exist.`r`nNB: Pool names are case-specific." } Else { Try { $response = Invoke-RestMethodOverride -Method DELETE -Uri "$URI" -Credential $F5session.Credential -ContentType 'application/json' Write-Output $true } Catch { Write-Error "Failed to remove the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) Return($false) } } } } Function Get-PoolMemberCollection { <# .SYNOPSIS Get the members of the specified pool #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$PoolName ) $PoolMembersPage = $F5session.BaseURL + "pool/~Common~$PoolName/members/?" Try { $PoolMembersJSON = Invoke-RestMethodOverride -Method Get -Uri $PoolMembersPage -Credential $F5session.Credential $PoolMembersJSON.items } Catch { Write-Error "Failed to get the members of the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Get-PoolMemberCollectionStatus { <# .SYNOPSIS Get the status of all members of the specified pool #> param( [Parameter(Mandatory=$true)]$PoolName, [Parameter(Mandatory=$true)]$F5session ) $PoolMembers = Get-PoolMemberCollection -PoolName $PoolName -F5session $F5session | Select-Object -Property name,session,state $PoolMembers } Function Get-PoolMember { <# .SYNOPSIS Get details about the specified pool member #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PoolName ) $PoolMember = $null $IPAddress = Get-PoolMemberIP -F5Session $F5session -ComputerName $ComputerName -PoolName $PoolName $PoolMemberURI = $F5session.BaseURL + "pool/~Common~$PoolName/members/~Common~$IPAddress`?" Try { $PoolMemberJSON = Invoke-RestMethodOverride -Method Get -Uri $PoolMemberURI -Credential $F5session.Credential $PoolMemberJSON } Catch { Write-Error "Failed to get the details for the pool member $ComputerName in the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } $PoolMember } Function Get-PoolMemberDescription { <# .SYNOPSIS Get the current session and state values for the specified computer #> param( [Parameter(Mandatory=$true)]$F5Session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PoolName ) $PoolMember = Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName $PoolMember = $PoolMember | Select-Object -Property name,description $PoolMember.description } Function Set-PoolMemberDescription { <# .SYNOPSIS Set the description value for the specified pool member #> param( [Parameter(Mandatory=$true)]$F5Session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PoolName, [Parameter(Mandatory=$true)]$Description ) $IPAddress = Get-PoolMemberIP -ComputerName $ComputerName -PoolName $PoolName -F5Session $F5session $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members/$IPAddress" $JSONBody = @{description=$Description} | ConvertTo-Json Try { $response = Invoke-RestMethodOverride -Method PUT -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody -ContentType 'application/json' $true } Catch { Write-Error "Failed to set the description on $ComputerName in the $PoolName pool to $Description." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Get-PoolMemberStatus { <# .SYNOPSIS Get the current session and state values for the specified computer for the specified pool #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PoolName ) $PoolMember = Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName $PoolMember = $PoolMember | Select-Object -Property name,session,state $PoolMember } Function Get-PoolsForMember { <# .SYNOPSIS Determine which pool(s) a server is in #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName ) #All servers that are LTM pool members use the NIC with a default gateway as the IP that registers with the LTM $ComputerIP = Get-CimInstance -ComputerName $ComputerName -Class Win32_NetworkAdapterConfiguration | Where-Object DefaultIPGateway | Select-Object -exp IPaddress | Select-Object -first 1 $AllPools = Get-PoolList -F5session $F5session $PoolsFound = @() foreach($Pool in $AllPools) { $PoolMembers = Get-PoolMemberCollection -PoolName $Pool -F5session $F5session foreach($PoolMember in $PoolMembers) { if($PoolMember.address -eq $ComputerIP) { $PoolsFound += $Pool } } } $PoolsFound } Function Get-PoolMemberIP { <# .SYNOPSIS Determine the IP address and port for a server in a particular pool #> param( [Parameter(Mandatory=$true)]$F5Session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PoolName ) $IPAddress = Get-CimInstance -ComputerName $ComputerName -Class Win32_NetworkAdapterConfiguration -ErrorAction SilentlyContinue | Where-Object DefaultIPGateway | Select-Object -exp IPaddress | Select-Object -first 1 #If we don't get an IP address for the computer, then fail If (!($IPAddress)){ Write-Error "Failed to obtain IP address for $ComputerName. The error returned was:`r`n$Error[0]" Return($false) } #Check the members of the specified pool to see if there is a member that matches this computer's IP address $PoolMembers = Get-PoolMemberCollection -PoolName $PoolName -F5session $F5Session $MemberName = $false foreach($PoolMember in $PoolMembers) { if($PoolMember.address -eq $IPAddress) { $MemberName = $PoolMember.Name } } If ($MemberName){ Return($MemberName) } Else { Write-Error "This computer was not found in the specified pool." Return($false) } } Function Add-PoolMember{ <# .SYNOPSIS Add a computer to a pool as a member #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PortNumber, [Parameter(Mandatory=$true)]$PoolName, [ValidateSet("Enabled","Disabled")] [Parameter(Mandatory=$true)]$Status ) $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members" $IPAddress = Get-CimInstance -ComputerName $ComputerName -Class Win32_NetworkAdapterConfiguration -ErrorAction SilentlyContinue | Where-Object DefaultIPGateway | Select-Object -exp IPaddress | Select-Object -first 1 #If we don't get an IP address for the computer, then fail If (!($IPAddress)){ Write-Error "Failed to obtain IP address for $ComputerName. The error returned was:`r`n$Error[0]" Return($false) } $MemberName = $IPAddress + ":" + $PortNumber $JSONBody = @{name=$MemberName;address=$IPAddress;description=$ComputerName} | ConvertTo-Json Try { Invoke-RestMethodOverride -Method POST -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody -ContentType 'application/json' -ErrorAction SilentlyContinue } Catch { Write-Error "Failed to add $ComputerName to $PoolName." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } #After adding to the pool, make sure the member status is set as specified If ($Status -eq "Enabled"){ Enable-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName } ElseIf ($Status -eq "Disabled"){ Disable-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName } } Function Remove-PoolMember{ <# .SYNOPSIS Remove a computer from a pool #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PortNumber, [Parameter(Mandatory=$true)]$PoolName ) $IPAddress = Get-CimInstance -ComputerName $ComputerName -Class Win32_NetworkAdapterConfiguration -ErrorAction SilentlyContinue | Where-Object DefaultIPGateway | Select-Object -exp IPaddress | Select-Object -first 1 #If we don't get an IP address for the computer, then fail If (!($IPAddress)){ Write-Error "Failed to obtain IP address for $ComputerName. The error returned was:`r`n$Error[0]" Return($false) } $MemberName = $IPAddress + ":" + $PortNumber $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members/~Common~$MemberName" Try { $response = Invoke-RestMethodOverride -Method DELETE -Uri "$URI" -Credential $F5session.Credential -ContentType 'application/json' -ErrorAction SilentlyContinue $true } Catch { Write-Error "Failed to remove $ComputerName from $PoolName." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Disable-PoolMember{ <# .SYNOPSIS Disable a pool member in the specified pools If no pool is specified, the member will be disabled in all pools #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, $PoolName=$null, [switch]$Force ) #If the -Force param is specified pool members do not accept any new connections, even if they match an existing persistence session. #Otherwise, members will only accept only new connections that match an existing persistence session. If ($Force){ $AcceptNewConnections = "user-down" } Else { $AcceptNewConnections = "user-up" } $JSONBody = @{state=$AcceptNewConnections;session='user-disabled'} | ConvertTo-Json #If a pool name is passed in, verify the pool exists and disable the member in that pool only If ($PoolName){ If (Test-Pool -F5session $F5session -PoolName $PoolName){ $MemberFullName = (Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName).Name $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members/$MemberFullName" Try { $response = Invoke-RestMethod -Method Put -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody $true } Catch { Write-Error "Failed to disable $ComputerName in the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Else { Write-Verbose "Pool $PoolName not found" Return($false) } } #Otherwise, disable the member in all their pools Else { $Pools = Get-PoolsForMember -ComputerName $ComputerName -F5session $F5session ForEach ($PoolName in $Pools){ $MemberFullName = (Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName).Name $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members/$MemberFullName" Try { $response = Invoke-RestMethodOverride -Method Put -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody } Catch { Write-Error "Failed to disable $ComputerName in the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) Return($false) } } $true } } Function Enable-PoolMember { <# .SYNOPSIS Enable a pool member in the specified pools If no pool is specified, the member will be disabled in all pools #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, $PoolName=$null ) $JSONBody = @{state='user-up';session='user-enabled'} | ConvertTo-Json #If a pool name is passed in, verify the pool exists and enable the member in that pool only If ($PoolName){ If (Test-Pool -F5session $F5session -PoolName $PoolName){ $MemberFullName = (Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName).Name $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members/$MemberFullName" Try { $response = Invoke-RestMethodOverride -Method Put -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody $true } Catch { Write-Error "Failed to enable $ComputerName in the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Else { Write-Verbose "Pool $PoolName not found" Return($false) } } #Otherwise, enable the member in all their pools Else { $Pools = Get-PoolsForMember -ComputerName $ComputerName -F5session $F5session ForEach ($PoolName in $Pools){ $MemberFullName = (Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName).Name $URI = $F5session.BaseURL + "pool/~Common~$PoolName/members/$MemberFullName" Try { $response = Invoke-RestMethodOverride -Method Put -Uri "$URI" -Credential $F5session.Credential -Body $JSONBody } Catch { Write-Error "Failed to disable $ComputerName in the $PoolName pool." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) Return($false) } } $true } } Function Get-CurrentConnectionCount { <# .SYNOPSIS Get the count of the specified pool member's current connections #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ComputerName, [Parameter(Mandatory=$true)]$PoolName ) $IPAddress = (Get-PoolMember -F5session $F5session -ComputerName $ComputerName -PoolName $PoolName).Name $PoolMember = $F5session.BaseURL + "pool/~Common~$PoolName/members/~Common~$IPAddress/stats" $PoolMemberJSON = Invoke-RestMethodOverride -Method Get -Uri $PoolMember -Credential $F5session.Credential #Return the number of current connections for this member of this pool $PoolMemberJSON.entries.'serverside.curConns'.value } Function Get-StatusShape { <# .SYNOPSIS Determine the shape to display for a member's current state and session values #> param( [Parameter(Mandatory=$true)]$state, [Parameter(Mandatory=$true)]$session ) #Determine status shape based on state and session values If ($state -eq "up" -and $session -eq "monitor-enabled"){ $StatusShape = "green-circle" } ElseIf ($state -eq "up" -and $session -eq "user-disabled"){ $StatusShape = "black-circle" } ElseIf ($state -eq "user-down" -and $session -eq "user-disabled"){ $StatusShape = "black-diamond" } ElseIf ($state -eq "down" -and $session -eq "monitor-enabled"){ $StatusShape = "red-diamond" } ElseIf ($state -eq "unchecked" -and $session -eq "user-enabled"){ $StatusShape = "blue-square" } ElseIf ($state -eq "unchecked" -and $session -eq "user-disabled"){ $StatusShape = "black-square" } Else{ #Unknown $StatusShape = "black-square" } $StatusShape } Function Get-iRuleCollection { <# .SYNOPSIS Get all iRules for the specified F5 LTM device #> param( [Parameter(Mandatory=$true)]$F5session ) $iRuleURL = $F5session.BaseURL + "rule/" Try { $iRulesJSON = Invoke-RestMethodOverride -Method Get -Uri $iRuleURL -Credential $F5session.Credential $iRulesJSON.items } Catch { Write-Error "Failed to get the list of iRules for the LTM device." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Function Get-VirtualServeriRuleCollection { <# .SYNOPSIS Get the iRules currently applied to the specified virtual server .NOTES This function assumes everything is in the /Common partition #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$VirtualServer ) $VirtualServerURI = $F5session.BaseURL + "virtual/~Common~$VirtualServer/" Try { $VirtualserverObject = Invoke-RestMethodOverride -Method Get -Uri $VirtualServerURI -Credential $F5session.Credential } Catch { Write-Error "Failed to get the list of iRules for the $VirtualServer virtual server." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) return $false } #Filter the content for just the iRules $VirtualserverObjectContent = $VirtualserverObject | Select-Object -Property rules $iRules = $VirtualserverObjectContent.rules #If the existing iRules collection is not an array, then convert it to one before returning If ($iRules -isnot [system.array]){ $iRulesArray = @() $iRulesArray += $iRules } Else { $iRulesArray = $iRules } $iRulesArray } Function Add-iRuleToVirtualServer { <# .SYNOPSIS Add an iRule to the specified virtual server .NOTES This function assumes everything is in the /Common partition #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$VirtualServer, [Parameter(Mandatory=$true)]$iRuleName ) $iRuleToAdd = "/Common/$iRuleName" #Verify that the iRule exists on the F5 LTM $AlliRules = Get-iRuleCollection -F5session $F5session If ($AlliRules.name -notcontains $iRuleName){ Write-Warning "The $iRuleName iRule does not exist in this F5 LTM." Return($false) } #Verify that this virtual server exists If (!(Test-VirtualServer -F5session $F5session -VirtualServerName $VirtualServer)){ Write-Warning "The $VirtualServer virtual server does not exist." Return($false) } #Get the existing IRules on the virtual server [array]$iRules = Get-VirtualServeriRuleCollection -VirtualServer $VirtualServer -F5session $F5session #If there are no iRules on this virtual server, then create a new array If (!$iRules){ $iRules = @() } #Check that the specified iRule is not already in the collection If ($iRules -match $iRuleToAdd){ Write-Warning "The $VirtualServer virtual server already contains the $iRuleName iRule." Return($false) } Else { $iRules += $iRuleToAdd $VirtualserverIRules = $F5session.BaseURL + "virtual/~Common~$VirtualServer/" $JSONBody = @{rules=$iRules} | ConvertTo-Json Try { $response = Invoke-RestMethodOverride -Method PUT -Uri "$VirtualserverIRules" -Credential $F5session.Credential -Body $JSONBody -Headers @{"Content-Type"="application/json"} $true } Catch { Write-Error "Failed to add the $iRuleName iRule to the $VirtualServer virtual server." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } } Function Remove-iRuleFromVirtualServer { <# .SYNOPSIS Remove an iRule from the specified virtual server .NOTES This function assumes everything is in the /Common partition #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$VirtualServer, [Parameter(Mandatory=$true)]$iRuleName ) $iRuleToRemove = "/Common/$iRuleName" #Get the existing IRules on the virtual server [array]$iRules = Get-VirtualServeriRuleCollection -VirtualServer $VirtualServer -F5session $F5session #If there are no iRules on this virtual server, then create a new array If (!$iRules){ $iRules = @() } #Check that the specified iRule is in the collection If ($iRules -match $iRuleToRemove){ $iRules = $iRules | Where-Object { $_ -ne $iRuleToRemove } $VirtualserverIRules = $F5session.BaseURL + "virtual/~Common~$VirtualServer/" $JSONBody = @{rules=$iRules} | ConvertTo-Json Try { $response = Invoke-RestMethodOverride -Method PUT -Uri "$VirtualserverIRules" -Credential $F5session.Credential -Body $JSONBody -Headers @{"Content-Type"="application/json"} $true } Catch { Write-Error "Failed to remove the $iRuleName iRule from the $VirtualServer virtual server." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } Else { Write-Warning "The $VirtualServer virtual server does not contain the $iRuleName iRule." $false } } Function Remove-ProfileRamCache{ <# .SYNOPSIS Delete the contents of a RAM cache for the specified profile .NOTES Example profile: "profile/http/ramcache" #> param( [Parameter(Mandatory=$true)]$F5session, [Parameter(Mandatory=$true)]$ProfileName ) $ProfileURL = $F5session.BaseURL +$ProfileName Try { $response = Invoke-RestMethodOverride -Method DELETE -Uri "$ProfileURL" -Credential $F5session.Credential } Catch { Write-Error "Failed to clear the ram cache for the $ProfileName profile." Write-Error ("StatusCode:" + $_.Exception.Response.StatusCode.value__) Write-Error ("StatusDescription:" + $_.Exception.Response.StatusDescription) } } |