[New App Request] Fortinet FortiClient VPN

by ADMIN 43 views

Background

The Fortinet FortiClient VPN is a popular virtual private network (VPN) solution that provides secure and reliable connectivity to remote networks. However, the Fortinet team has chosen not to publish their product version numbers in an easily accessible manner, making it challenging for administrators to determine the latest version of the software.

The Problem

To address this issue, we have developed a script that retrieves the latest version of the FortiClient VPN by parsing the release notes from the Fortinet documentation site and RSS feed. The script uses regular expressions to extract the version and build numbers from the release notes content.

The Solution

Our script, named Get-FortiClientVPN.ps1, uses the following steps to determine the latest version of the FortiClient VPN:

  1. Fetch the documentation site content: The script fetches the content from the Fortinet documentation site using the Invoke-WebRequest cmdlet.
  2. Extract the latest product version: The script extracts the latest product version from the <title> tag of the documentation site content using a regular expression.
  3. Construct the RSS feed URL: The script constructs the RSS feed URL by appending the product version to the base URL.
  4. Fetch the RSS feed content: The script fetches the RSS feed content using the Invoke-WebRequest cmdlet.
  5. Extract the most recent release notes link: The script extracts the most recent release notes link from the RSS feed content using an XML parser.
  6. Fetch the release notes page content: The script fetches the release notes page content using the Invoke-WebRequest cmdlet, handling redirects.
  7. Determine the final URL after redirection: The script determines the final URL after redirection by checking the BaseResponse property of the response object.
  8. Extract version details: The script extracts the version and build numbers from the release notes content using regular expressions.
  9. Determine the highest version: The script determines the highest version by sorting the extracted versions in descending order and selecting the first one.

The Script

Here is the script in its entirety:

# Get-FortiClientVPN.ps1
<#
Background - Fortinet don't appear to publish the latest version of the FortiClient VPN on a specific webpage.
It is therefore necessary to find the latest product version in multiple steps, first from the products page on the Documentation site (defined in $docSiteUrl),
This currently returns "7.4", we then use this version to find the latest release notes for this product from Fortinets RSS feed (defined in $rssFeedUrl).
Once the Release Notes have been returned, the latest build version can be obtained from the webpage using one of two regex's, this currently returns "7.4.2.1737".
#>

$AppName = "Fortinet Forticlient VPN"
# Define the documentation site URL
$docSiteUrl = "https://docs.fortinet.com/product/forticlient"

# Step 1: Fetch the content from the documentation site
$docContent = Invoke-WebRequest -Uri $docSiteUrl -UseBasicParsing

# Step 2: Extract the latest product version from the <title> tag
if ($docContent.Content -match "<title>\s*FortiClient\s*([\d\.]+)\s*</title>") {
    $productVersion = $matches[1]
} else {
    Write-Warning "Failed to extract product version." -ForegroundColor Red
    # exit 1
}

# Construct the RSS feed URL
$rssFeedUrl = "https://docs.fortinet.com/feeds/forticlient/$productVersion.rss"

# Step 4: Fetch the RSS feed content
$rssContent = Invoke-WebRequest -Uri $rssFeedUrl -UseBasicParsing

# Extract the most recent (Windows) Release Notes link
[xml]$rssXml = $rssContent.Content
$releaseNotesUrl = ($rssXml.rss.channel.item | Where-Object { $_.title -match "${Windows}$ Release Notes" })[0].link

if (-not $releaseNotesUrl) {
    Write-Warning "Failed to find Windows Release Notes link." -ForegroundColor Red
    # exit 1
}

# Step 5: Fetch the release notes page content (handling redirects)
$response = Invoke-WebRequest -Uri $releaseNotesUrl -UseBasicParsing -MaximumRedirection 5

# Determine the final URL after redirection
if ($response.BaseResponse -and $response.BaseResponse.ResponseUri) {
    $finalReleaseNotesUrl = $response.BaseResponse.ResponseUri.AbsoluteUri
} elseif ($response.Headers["Location"]) {
    $finalReleaseNotesUrl = $response.Headers["Location"]
} else {
    $finalReleaseNotesUrl = $releaseNotesUrl  # Fallback to the original URL
}

$RNresponse = Invoke-WebRequest -Uri $finalReleaseNotesUrl -UseBasicParsing
$releaseNotesContent = $RNresponse.Content

# Extract version details
$latestVersionBuild = ""
$latestVersionExample = ""

# Extract version and build number using regex
$BuildversionMatch = $releaseNotesContent | Select-String -Pattern "FortiClient ${Windows}$.*?<span[^>]*>([\d\.]+)</span>\s*build\s*<span[^>]*>(\d+)</span>" -AllMatches
if ($BuildversionMatch.Matches.Count -gt 0) {
    $latestVersionBuild = "$($BuildversionMatch.Matches[0].Groups[1].Value).$($BuildversionMatch.Matches[0].Groups[2].Value)"
} else {
    Write-Warning "WARNING :: No Build Version Matches found in release notes content"
}

# Extract example version
$ExampleVersionMatch = $releaseNotesContent | Select-String -Pattern "Example:\s*\<span[^>]*>(\d+\.\d+\.\d+)\<\/span[^>]*>.<span[^>]*>(\d+)" -AllMatches
if ($ExampleversionMatch.Matches.Count -gt 0) {
    $latestVersionExample = "$($ExampleversionMatch.Matches[0].Groups[1].Value).$($ExampleversionMatch.Matches[0].Groups[2].Value)"
} else {
    Write-Warning "WARNING :: No Example Version Matches found in release notes content"
}

# Step 6: Determine the highest version
$LatestVersion = ($latestVersionBuild, $latestVersionExample) | Where-Object { $_ -ne "" } | Sort-Object { $_ -as [version] } -Descending | Select-Object -First 1

$Platforms = @(
    @{Architecture = 'x64'; Type = 'Exe'; Platform = 'Windows'; Uri = "https://filestore.fortinet.com/forticlient/FortiClientVPNOnlineInstaller.exe"}
)

foreach ($Platform in $Platforms) {
    $SearchCount = 3
	do {
		[version]$AppVersion = $LatestVersion
		New-NevergreenApp -Name $AppName -Version $AppVersion -Uri $Platform.Uri -Platform $Platform.Platform -Architecture $Platform.Architecture -Type $Platform.Type
        break

        $SearchCount--
    } until ($SearchCount -eq 0)

    if ($SearchCount -eq 0) {
        Write-Warning "Could not find release for $($AppName) $($Platform.Platform) $($Platform.Architecture)"
    }
}

Conclusion

In conclusion, our script Get-FortiClientVPN.ps1 provides a reliable and efficient way to determine the latest version of the FortiClient VPN by parsing the release notes from the Fortinet documentation site and RSS feed. The script uses regular expressions to extract the version and build numbers from the release notes content and determines the highest version by sorting the extracted versions in descending order.

Future Work

In the future, we plan to improve the script by adding support for other platforms, such as macOS and Linux, and by incorporating additional features, such as automatic updates and version comparison.

Example Use Cases

Here are some example use cases for the script:

  • Automating software deployment: The script can be used to automate the deployment of the FortiClient VPN software by retrieving the latest version and downloading the corresponding installer.
  • Version comparison: The script can be used to compare the version of the FortiClient VPN software installed on a system with the latest version available.
  • Release notes analysis: The script can be used to analyze the release notes of the FortiClient VPN software to identify new features, bug fixes, and security patches.

Troubleshooting

Here are some common issues that may arise when using the script:

  • Failed to extract product version: This error may occur if the script is unable to extract the product version from the documentation site content. Check the documentation site content for any changes that may be affecting the script's ability to extract the product version.
  • Failed to find Windows Release Notes link: This error may occur if the script is unable to find the Windows Release Notes link in the RSS feed content. Check the RSS feed content for any changes that may be affecting the script's ability to find the Windows Release Notes link.
  • Could not find release for [AppName] [Platform] [Architecture]: This error may occur if the script is unable to find a release for the specified application, platform, and architecture. Check the script's configuration and the availability of releases for the specified application, platform, and architecture.
    Q&A: Fortinet FortiClient VPN ==============================

Q: What is the Fortinet FortiClient VPN?

A: The Fortinet FortiClient VPN is a popular virtual private network (VPN) solution that provides secure and reliable connectivity to remote networks.

Q: Why is it difficult to determine the latest version of the FortiClient VPN?

A: The Fortinet team has chosen not to publish their product version numbers in an easily accessible manner, making it challenging for administrators to determine the latest version of the software.

Q: How does the script Get-FortiClientVPN.ps1 determine the latest version of the FortiClient VPN?

A: The script uses the following steps to determine the latest version of the FortiClient VPN:

  1. Fetch the documentation site content: The script fetches the content from the Fortinet documentation site using the Invoke-WebRequest cmdlet.
  2. Extract the latest product version: The script extracts the latest product version from the <title> tag of the documentation site content using a regular expression.
  3. Construct the RSS feed URL: The script constructs the RSS feed URL by appending the product version to the base URL.
  4. Fetch the RSS feed content: The script fetches the RSS feed content using the Invoke-WebRequest cmdlet.
  5. Extract the most recent release notes link: The script extracts the most recent release notes link from the RSS feed content using an XML parser.
  6. Fetch the release notes page content: The script fetches the release notes page content using the Invoke-WebRequest cmdlet, handling redirects.
  7. Determine the final URL after redirection: The script determines the final URL after redirection by checking the BaseResponse property of the response object.
  8. Extract version details: The script extracts the version and build numbers from the release notes content using regular expressions.
  9. Determine the highest version: The script determines the highest version by sorting the extracted versions in descending order and selecting the first one.

Q: What are the benefits of using the script Get-FortiClientVPN.ps1?

A: The script provides a reliable and efficient way to determine the latest version of the FortiClient VPN by parsing the release notes from the Fortinet documentation site and RSS feed. The script uses regular expressions to extract the version and build numbers from the release notes content and determines the highest version by sorting the extracted versions in descending order.

Q: Can the script be used for other purposes?

A: Yes, the script can be used for other purposes, such as:

  • Automating software deployment: The script can be used to automate the deployment of the FortiClient VPN software by retrieving the latest version and downloading the corresponding installer.
  • Version comparison: The script can be used to compare the version of the FortiClient VPN software installed on a system with the latest version available.
  • Release notes analysis: The script can be used to analyze the release notes of the FortiClient VPN software to identify new features, bug fixes, and security patches.

Q: What are some common issues that may arise when using the script?

A: Some common issues that may arise when using the script include:

  • Failed to extract product version: This error may occur if the script is unable to extract the product version from the documentation site content. Check the documentation site content for any changes that may be affecting the script's ability to extract the product version.
  • Failed to find Windows Release Notes link: This error may occur if the script is unable to find the Windows Release Notes link in the RSS feed content. Check the RSS feed content for any changes that may be affecting the script's ability to find the Windows Release Notes link.
  • Could not find release for [AppName] [Platform] [Architecture]: This error may occur if the script is unable to find a release for the specified application, platform, and architecture. Check the script's configuration and the availability of releases for the specified application, platform, and architecture.

Q: How can I troubleshoot issues with the script?

A: To troubleshoot issues with the script, you can:

  • Check the script's configuration: Verify that the script's configuration is correct and that the necessary parameters are set.
  • Check the availability of releases: Verify that releases are available for the specified application, platform, and architecture.
  • Check the documentation site content: Verify that the documentation site content has not changed and that the script is able to extract the product version correctly.
  • Check the RSS feed content: Verify that the RSS feed content has not changed and that the script is able to find the Windows Release Notes link correctly.