No ICMP in Azure Challenges

I work at an MSP. We have a number of small customers with servers in Azure that we manage with BigFix. Building a BigFix relay within each customer area in Azure is not an option. We have most of our BigFix clients performing Auto relay selection to our IFRs.

Azure does not allow ICMP unless the VM has an internet IP. Thus, a large number of our BigFix clients do not allow ICMP.

I’ve put together a script that should determine which relay is the fastest for each client. I was planning to implement it as a Policy that will run every 8 hours. I have yet to test it fully.

I want to limit it to only the Azure clients that are unable to complete automatic relay selection, and it seems to me the best indicator of that are clients that don’t have a value for “Distance to BES Relay”. I have not been able to figure out the relevance for that. Does anyone have an idea?

I forgot to include this:

The Property “Distance to BES Relay” lives in a Reserved site. The analysis looks like this:

if exists selected server then if upper bound of distance of selected server = 255 then error “unknown” else upper bound of distance of selected server else error “n/a”

Probably the simplest method that I’d recommend, is to set _BESClient_RelaySelect_FailoverRelayList

From https://help.hcltechsw.com/bigfix/10.0/platform/Platform/Config/r_client_set.html

_BESClient_RelaySelect_FailoverRelayList
This setting contains a list of failover relays to choose from when no relay listed as primary, secondary or specified in the tertiary list responded to pings. This setting, first introduced in BigFix 9.0, is a semi-colon delimited list of relays to try. For automatic relay selection, see Relay Affiliation. If specified, this setting overrides _BESClient_RelaySelect_FailoverRelay. (Example: relay1.company.com;192.168.123.32;relay2.company.com)

You can use your “best relay” logic to configure the order of relays you assign in this value. You can then let the client attempt automatic (or manual) relay selection as usual, but if the automatic selection fails the client will then use the relays in this FailoverRelayList, in the order specified; the client will not attempt ICMP or determine the distance to these relays, it will go straight to TCP connect attempts for each relay.

2 Likes

I did consider using that setting, but I didn’t consider populating the list using my action that determines which relays are fastest for each client. Thank you for that! I’ll work on setting that up tomorrow, then will share the final script here. :grinning:

1 Like

That was challenging… but I think this will do it. I have yet to test it out, because I’m still working on the relevance.

I know this will get me all the Azure VMs:
((value “product_name” of it as string equals “Virtual Machine”) of structure “system_information” of smbios)

I really want to incorporate that “Distance to BES Relay” into my relevance as well, since it would be best to only apply my script on the Azure VMs that have “unknown” set for that property. I’m going to ask HCL about that.

Here is the script I put together. If anyone spots something that could be improved upon, I’m all ears.

# This script will find the fastest relay when ICMP is not available, and then will update BigFix client settings to use that relay.
# Create the folder or delete the previous relay setting text file
$folderPath = "C:\BFXdata"
$filePath = "C:\BFXdata\BFXrelay.txt"
 
if (-not (Test-Path -Path $folderPath -PathType Container)) {
          New-Item -Path $folderPath -ItemType Directory
}
 
Remove-Item $filePath -Force -ErrorAction SilentlyContinue
 
# Define the list of endpoints to test
$endpoints = @(
    "relay1.bigfix",
    "relay2.bigfix",
    "relay3.bigfix",
    "relay4.bigfix",
    "relay5.bigfix"
)
# Initialize an array to store connection details
$connections = @()

# Loop through each endpoint and test the connection to port 52311
foreach ($endpoint in $endpoints) {
    $connectionResult = $null
    $connectionTime = Measure-Command {
        $connectionResult = Test-NetConnection -ComputerName $endpoint -Port 52311 -ErrorAction SilentlyContinue
    }

    if ($connectionResult.TcpTestSucceeded) {
        $rtt = $connectionTime.TotalMilliseconds
        Write-Host "Successfully connected to $endpoint on port 52311 with approximate RTT $rtt ms"

        # Add the connection details to the array
        $connectionDetails = @{
            Endpoint = $endpoint
            RTT = $rtt
        }
        $connections += New-Object PSObject -Property $connectionDetails
    } else {
        Write-Host "Failed to connect to $endpoint on port 52311"
    }
}
# Sort the connections array by RTT in ascending order (fastest to slowest)
$sortedConnections = $connections | Sort-Object RTT

# Create a semicolon-separated string of endpoint names without spaces
$endpointNames = ""
foreach ($connection in $sortedConnections) {
    $endpointNames += $connection.Endpoint + ";"
}
# Remove the trailing semicolon
$endpointNames = $endpointNames.TrimEnd(";")

# Write the endpoint names in order from fastest to slowest to the specified file
$endpointNames | Out-File -FilePath $filePath

# Configure the Failover Relay List this client will use to communicate with BigFix
$RegistryKeyPath = "HKLM:\SOFTWARE\WOW6432Node\BigFix\EnterpriseClient\Settings\Client\_BESClient_RelaySelect_FailoverRelayList"
$RegistryValueName = "value"

if (!(Test-Path $RegistryKeyPath))
    {
        New-Item -Path $RegistryKeyPath -Force | Out-Null
        New-ItemProperty -Path $RegistryKeyPath -Name $RegistryValueName -Value $endpointNames -Force | Out-Null}
else
    {
    Set-ItemProperty -Path $RegistryKeyPath -Name $RegistryValueName -Value $endpointNames -Force | Out-Null}

DOH!
This will also include HyperV VMs:

The “Distance to BES Relay” is calculated by ICMP pings during relay selection - I’m not sure how useful it will be in your case, since you want to use it to configure a relay list, but you must have already selected a (pingable) relay for that to have a value

Exactly why I want to use that. I only want my fixlet to run on computers that have no value for that… because those are the ones that can’t ping a relay. There is no need to run it on Azure VMs that are able to ping the relays.

OK, if there is no way to use that existing property, then I’ll just create my own. I’ll deploy a fixlet to all the Azure VMs, determine which ones can’t complete a ping to our relays, and run this:
setting “ICMP_Blocked”=“True” on “{now}” for client

Then I’ll deploy my other script and Target the machines dynamically using that new property.

1 Like

I’m still riding the struggle bus.

My scripts are executing 100% successfully. I’m only changing the “_BESClient_RelaySelect_FailoverRelayList” on clients that cannot determine their closest relay with ICMP. However, I’ve got two issues:

  1. When my clients, which have an updated FailoverRelayList set, perform a Relay Select operation, they still default back to the main internet relay, which is the slowest possible relay they could select. It is not possible they are communicating with that via ICMP, so why aren’t they using the FailoverRelayList instead? We’re not using Relay Affiliation, TertiaryRelayList, nor do we have a FailoverRelay set.

  2. I set my fixlets to use the Powershell Action Script. However, I have no idea how to tell the client to perform a “relay select” afterwards… is there some Powershell command I can run to tell the BigFix client to perform a relay select?

@maddogcody I’m attaching the manual Relay selection process
The manual relay selection process use these settings in the following order:

Client attempts to connect to primary relay selection value (__RelayServer1) if set.
Client attempts to connect to secondary selection value (__RelayServer2) if set.
Client attempts to connect to tertiary selection if (_BESClient_RelaySelect_TertiaryRelayList) is set.
Client attempts to connect failover selection if (_BESClient_RelaySelect_FailoverRelay) is set.
Client fails to connect to relays Attempt root server selection .

https://support.hcltechsw.com/csm?id=kb_article&sysparm_article=KB0023371

If I understand correctly, the following client settings are not set on the machine:
(__RelayServer1), (__RelayServer2), (_BESClient_RelaySelect_TertiaryRelayList)
The only setting that is configured is (_BESClient_RelaySelect_FailoverRelay)

In your case , I would do the following:
Set the ActionScript type to: ActionScript
And you can use the following Knowledge Base to run the PowerShell with Actionscript - https://support.hcltechsw.com/csm?id=kb_article&sysparm_article=KB0081019

Then after the following line
action uses wow64 redirection {x64 of operating system}

I’ll write:
relay select

You can also create the PowerShell script on the fly with createfile until method - make sure to replace { with {{

You can also add the -ExecutionPolicy to Bypass if it is restricted on your computer by default

1 Like

Ah, since they’ve previously selected the Internet relay, and their IP address hasn’t changed, the client does try to use the last relay selected again (an optimization so in-progeess downloads can resume, but it does interfere with changing the relay list).
Before restarting the client or performing a new relay select, try deleting the HostSelector registry value. Related thread at BES Relay Affiliation not working

2 Likes

@JasonWalker I’ve testing this on my machine, I’m working with Manual Relay Selection with __RelayServer1 and __RelayServer2
I’ve deleted HostSelector registry value and nothing happened on the Client Log

Did you perform a new Relay Select after removing HostSelector?

No.
I can’t execute right now the “relay select” command through the BigFix Console / Web UI
On my setup, I have the__RelayServer1 and __RelayServer2 settings

I’ve changed the __RelayServer1 and __RelayServer2 settings with URLs that should not have access to.

After deleting HostSelector registry value and Restarting the BigFix Client, It starts the Relay Selection and selected the previous Relay it had communicated with.

Thank you all for your help on this. I finally have a fully functional script for all our Azure devices that are unable to use ICMP. Sorry for the delay, I’ve been busy the last two months, and finally had some time to put into modifying my script with your suggestions. I’ll post the whole thing here next week after I’ve let it run for a few days.

2 Likes

Look forward to seeing it. Thank you.

This is the first policy I run against our BigFix clients to determine if ICMP is blocked for our Windows Azure devices:

Relevance:
(((((name of it contains “Win”) of operating system) AND ((not exists relay service) AND (not exists main gather service))) AND (((value “product_name” of it as string equals “Virtual Machine”) of structure “system_information” of smbios))) AND (((not exists file “C:\BFXdata\ICMP_Fail.txt”) OR (exists file “C:\BFXdata\ICMP_Fail.txt” whose (now - modification time of it > 48 * hour))))) AND (not exists file “C:\BFXdata\ICMP_Success.txt”)

Action Script (using Powershell):

$hostname = "relay.bigfix.com"
$filepathgood = "C:\BFXdata\ICMP_Success.txt"
$filepathbad = "C:\BFXdata\ICMP_Fail.txt"
$folderPath = "C:\BFXdata"

if (-not (Test-Path -Path $folderPath -PathType Container)) {

New-Item -Path $folderPath -ItemType Directory
}

Remove-Item $filepathgood -Force -ErrorAction Ignore
Remove-Item $filepathbad -Force -ErrorAction Ignore
 
function Test-Ping {
 param (
    [string]$ComputerName
 )

$pingResult = Test-Connection -ComputerName $ComputerName -Count 1 -ErrorAction SilentlyContinue

if ($pingResult -ne $null) {
    return $true
} else {
    return $false
}
}

if (Test-Ping -ComputerName $hostname) {
"Ping to $hostname succeeded." | Out-File -FilePath $filepathgood
} else {
"Ping to $hostname failed." | Out-File -FilePath $filepathbad
}

After that policy ran on all the applicable devices, I kicked off this 2nd policy, which will perform the important part of this solution…

Relevance:
((((((name of it contains “Win”) of operating system) AND ((not exists relay service) AND (not exists main gather service))) AND (((value “product_name” of it as string equals “Virtual Machine”) of structure “system_information” of smbios))) AND (exists file “C:\BFXdata\ICMP_Fail.txt”)) AND (((not exists file “C:\BFXdata\BFXrelay.txt”) OR (exists file “C:\BFXdata\BFXrelay.txt” whose (now - modification time of it > 96 * hour))))

Action Script (BigFix Action Script):

//1. Save old ExecutionPolicy value
parameter "PolicyExisted"="{exists value "ExecutionPolicy" of key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" of (if exists x64 registry then x64 registry else registry)}"
parameter "oldExecutionPolicy"="{if (parameter "PolicyExisted" as boolean) then (value "ExecutionPolicy" of key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" of (if exists x64 registry then x64 registry else registry) as string) else ""}"
//2. set to ExecutionPolicy=Unrestricted  and Pull PowerShell exe from registry... if 64bit then pull PowerShell x64 
if {x64 of operating system}
	regset64 "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell]" "ExecutionPolicy"="Unrestricted"
	parameter "PowerShellexe"="{value "Path" of key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" of x64 registry}"
else
	//we need to determine what the current execution policy is so we can put it back when we're done.
	regset "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell]" "ExecutionPolicy"="Unrestricted"
	parameter "PowerShellexe"="{value "Path" of key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" of registry}"
endif

//3. Create PowerShell Script and save to ps1 file
delete __createfile
delete NoICMP_Relay.ps1

createfile until END_OF_FILE
# Create the folder or delete the previous relay setting text file
$folderPath = "C:\BFXdata"
$filePath = "C:\BFXdata\BFXrelay.txt"
 
if (-not (Test-Path -Path $folderPath -PathType Container)) {
      New-Item -Path $folderPath -ItemType Directory
}
Remove-Item $filePath -Force -ErrorAction SilentlyContinue

# Define the list of endpoints to test
$endpoints = @(
"relay1.bigfix",
"relay2.bigfix",
"relay3.bigfix",
"relay4.bigfix",
"relay5.bigfix"
)
# Initialize an array to store connection details
$connections = @()

# Loop through each endpoint and test the connection to port 52311
foreach ($endpoint in $endpoints) {
  $connectionResult = $null
  $connectionTime = Measure-Command {
    $connectionResult = Test-NetConnection -ComputerName $endpoint -Port 52311 -ErrorAction SilentlyContinue
}

if ($connectionResult.TcpTestSucceeded) {
    $rtt = $connectionTime.TotalMilliseconds
    Write-Host "Successfully connected to $endpoint on port 52311 with approximate RTT $rtt ms"

    # Add the connection details to the array
    $connectionDetails = @{
        Endpoint = $endpoint
        RTT = $rtt
    }
    $connections += New-Object PSObject -Property $connectionDetails
} else {
    Write-Host "Failed to connect to $endpoint on port 52311"
}
}
# Sort the connections array by RTT in ascending order (fastest to slowest)
$sortedConnections = $connections | Sort-Object RTT

# Create a semicolon-separated string of endpoint names without spaces
$endpointNames = ""
foreach ($connection in $sortedConnections) {
  $endpointNames += $connection.Endpoint + ";"
}
# Remove the trailing semicolon
$endpointNames = $endpointNames.TrimEnd(";")

# Write the endpoint names in order from fastest to slowest to the specified file
$endpointNames | Out-File -FilePath $filePath

# Configure the Failover Relay List this client will use to communicate with BigFix
$RegistryKeyPath = "HKLM:\SOFTWARE\WOW6432Node\BigFix\EnterpriseClient\Settings\Client\_BESClient_RelaySelect_FailoverRelayList"
$RegistryValueName = "value"

if (!(Test-Path $RegistryKeyPath))
{
    New-Item -Path $RegistryKeyPath -Force | Out-Null
    New-ItemProperty -Path $RegistryKeyPath -Name $RegistryValueName -Value $endpointNames -Force | Out-Null}
else
{
Set-ItemProperty -Path $RegistryKeyPath -Name $RegistryValueName -Value $endpointNames -Force | Out-Null}

# Delete the previously selected internet relay from the registry
$DelRegPath = "HKLM:\SOFTWARE\WOW6432Node\BigFix\EnterpriseClient\GlobalOptions"
$DelRegName = "HostSelector"
try {
Get-ItemProperty -Path $DelRegPath -Name $DelRegName -ErrorAction Stop
Remove-ItemProperty -Path $DelRegPath -Name $DelRegName -Force -ErrorAction Stop
}
catch {
Write-Warning "$_.Exception.Message"
}

 # Delete the BigFix Relay1 value
$DelRegPath2 = "HKLM:\SOFTWARE\WOW6432Node\BigFix\EnterpriseClient\Settings\Client\__RelayServer1"
$DelRegName2 = "value"
try {
Get-ItemProperty -Path $DelRegPath2 -Name $DelRegName2 -ErrorAction Stop
Clear-ItemProperty -Path $DelRegPath2 -Name $DelRegName2 -Force -ErrorAction Stop
}
catch {
Write-Warning "$_.Exception.Message"
}

END_OF_FILE

move __createfile NoICMP_Relay.ps1

action uses wow64 redirection false
waithidden "{​​parameter "PowerShellexe"}​​" -file "{​​pathname of client folder of current site}​​\NoICMP_Relay.ps1"

//4. Restore ExecutionPolicy back
if {​​x64 of operating system}​​
if {​​parameter "PolicyExisted" as boolean}​​
regset64 "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell]" "ExecutionPolicy"="{​​parameter "oldExecutionPolicy"}​​"
else
regdelete64 "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell]" "ExecutionPolicy"
endif
else
if {​​parameter "PolicyExisted" as boolean}​​
regset "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell]" "ExecutionPolicy"="{​​parameter "oldExecutionPolicy"}​​"
else
regdelete "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell]" "ExecutionPolicy"
endif
endif

relay select

I decided that since that first policy determines if ICMP is blocked, I’m fine with my relevance catching not just Azure VMs, but also VMs running on Microsoft Hyper-V.

I left the relevance set up on both to check for how many hours old the file is, since I’m still playing with it. I know I could switch that to days instead (>2*day).

My colleague, whom is much better with UNIX commands than me, is working on something similar for all our Linux clients running in Azure.