How to get a list of Confluence Apps and their licensing information

Still need help?

The Atlassian Community is here for you.

Ask the community

Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.

Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.

*Except Fisheye and Crucible

Purpose

Apps (also known as Add-ons and Plugins) are a good way to extend Confluence functionality and they are available to administrators from the Atlassian Marketplace.

Confluence administrators may need to generate reports about licensing status of the Apps installed on their instances. For example, if you need to get the license expiry date of every installed App, this can be done from the web UI checking each App at a time. For large Confluence instances this can be time consuming.

Atlassian Universal Plugin Manager (UPM) exposes REST API methods that helps to manage the installed Apps, including their licensing information.

This document will guide you on how to create a script that uses these REST API methods to create a CSV-like report on installed Apps and their licensing information.

Solution

The solution is based on UPM's REST API methods by running a script on any computer/server with access to Confluence. It could be the Confluence server itself or your own computer.

The main steps of the code are:

  1. Get a list of all Apps using /rest/plugins/latest method.
  2. For each App, get their license information.


Below you will find the suggested script on which the output is a CSV-like report with the semi-colon ':' as the separator.

Specifics for each language:

  • Shell Script.
    • You must install jq CLI.
    • A temporary file will be saved as /tmp/restapi.out.
    • The full report is stored in file /tmp/PluginReport.csv.
  • Node.js.
  • PowerShell
    • Script was created and tested on PSVersion 6.0.2.


### Final report is saved on file /tmp/PluginReport.csv
### Change these arguments according to your instance
CONFLUENCE_SERVER_URL="http://localhost:6663"
CONFLUENCE_SERVER_CONTEXT_PATH="/c663"
ADMIN_USRNAME=admin
ADMIN_PWD=admin


CONFLUENCE_BASE_URL=$CONFLUENCE_SERVER_URL$CONFLUENCE_SERVER_CONTEXT_PATH
curl --user $ADMIN_USRNAME:$ADMIN_PWD $CONFLUENCE_BASE_URL/rest/plugins/latest/ 2>/dev/null | jq -r '.plugins[] | select(.userInstalled) | "\(.name):\(.version):\(.vendor.name):\(.usesLicensing):\(.links.self)"' > /tmp/restapi.out
echo "Plugin Name:Plugin Version:Vendor Name:Use License:License Type:Expiry Date:License Key:SEN" > /tmp/PluginReport.csv
while read PLUGINLINE; do
PLUGINKEY=$(awk 'BEGIN { FS=":" } { print $5 }' <<< "$PLUGINLINE")
LICINFO=$(curl --user $ADMIN_USRNAME:$ADMIN_PWD $CONFLUENCE_SERVER_URL$PLUGINKEY/license/ 2>/dev/null | jq '"\(.licenseType):\(.maintenanceExpiryDateString):\(.rawLicense):\(.supportEntitlementNumber)"' | sed -e 's/^"//' -e 's/"$//')
PLGINFO=$(awk 'BEGIN { FS=":"; OFS=":"; } { print $1,$2,$3,$4 }' <<< "$PLUGINLINE")
echo "$PLGINFO:$LICINFO"
done < /tmp/restapi.out >> /tmp/PluginReport.csv
/* --- Change the values of these parameters --- */
var confluenceServerUrl = 'http://localhost:6663'; // Confluence URL
var confluenceContextPath = '/c663'; // context path
//var confluenceContextPath = '/c663'; // context path
var credentials = { 'username' : 'admin', 'password' : 'admin' }; // these are the admin credentials
/* --------------------------------------------- */

var confluenceBaseUrl = confluenceServerUrl + confluenceContextPath;
const axios = require('axios');
const axios2 = require('axios');

const getConfluenceApps = async () => {
  try {
    return await axios.get(confluenceBaseUrl + '/rest/plugins/latest/', { auth: credentials })
  } catch (error) {
    console.log(error)
  }
}

 const getAppAdditionalInfo = async urlToApp => {
  try {
    return await axios2.get(confluenceServerUrl + urlToApp + '/license/', { auth: credentials })
  } catch (error) {
    console.log(error)
  }
}

const filterInstalledApps = async () => {
  const confluenceApps = await getConfluenceApps();

  // filter for user installed Apps
  let installedApps = confluenceApps.data;
  installedApps.plugins = installedApps.plugins.filter(function(eachApp){
    return eachApp.userInstalled != false;
  });
   
  // print header
  console.log('"Plugin Name":"Plugin Version":"Vendor Name":"Use License":"License Type":"Expiry Date":"License Key":"SEN"');
  // for each app
  for (itemId in installedApps.plugins) {
    let appDetailedInfo = (await getAppAdditionalInfo(installedApps.plugins[itemId].links.self)).data;
    console.log('"' + installedApps.plugins[itemId].name + '":"' + installedApps.plugins[itemId].version + '":"' + installedApps.plugins[itemId].vendor.name + '":"' + installedApps.plugins[itemId].usesLicensing + '":"' + appDetailedInfo.licenseType + '":"' + appDetailedInfo.maintenanceExpiryDateString + '":"' + appDetailedInfo.rawLicense + '":"' + appDetailedInfo.supportEntitlementNumber + '"');

  }
}

filterInstalledApps();


### --- Change the values of these parameters --- ###
$username = "local_admin"
$password = "local_admin"
$confluence_server_url = "http://localhost:2667";
$confluence_server_context_path = "/c667";
### --------------------------------------------- ###


$confluence_base_url = $confluence_server_url + $confluence_server_context_path; ### Confluence Base URL

### Basic Authentication 
function Get-BasicAuthCreds {
    param([string]$Username,[string]$Password)
    $AuthString = "{0}:{1}" -f $Username,$Password
    $AuthBytes  = [System.Text.Encoding]::Ascii.GetBytes($AuthString)
    return [Convert]::ToBase64String($AuthBytes)
}
$BasicCreds = Get-BasicAuthCreds -Username $username -Password $password;

### Collect All plugins info from rest API
$plugins_rest_url = $confluence_base_url + '/rest/plugins/latest/';
$plugins_rest_output = Invoke-RestMethod -Uri $plugins_rest_url -Method Get -ContentType 'application/json' -Headers @{"Authorization"="Basic $BasicCreds"};

### Filter for user installed Apps and select wanted attributes
$filtered_plugins = $plugins_rest_output.plugins | where userInstalled -eq "True" | select -prop name,version,@{Name="VendorName"; Expression = {$_.vendor.name}},usesLicensing,@{Name="link"; Expression = {$_.links.self}};
$filtered_plugins | ForEach-Object -Process {$_.link = $confluence_server_url + $_.link + '/license/'};

### Run license check rest api for each App
$filtered_plugins | ForEach-Object -Process {$_.link = Invoke-RestMethod -Uri $_.link -Method Get -ContentType 'application/json' -Headers @{"Authorization"="Basic $BasicCreds"}};

### Show selected attributes and convert output to CSV
$filtered_plugins | select -prop name,version,VendorName,usesLicensing,@{Name="LicenseType"; Expression = {$_.link.licenseType}},@{Name="ExpiryDateString"; Expression = {$_.link.expiryDateString}},@{Name="LicenseKey"; Expression = {$_.link.rawLicense}},@{Name="SEN"; Expression = {$_.link.supportEntitlementNumber}} | ConvertTo-Csv -Delimiter ':'

If you face below errors while executing the script, please increase the rate limit while using this script

Invoke-RestMethod : The remote server returned an error: (429) Too Many Requests.



Below is an example of a report after pasting it in a spreadsheet application.






Last modified on Mar 3, 2023

Was this helpful?

Yes
No
Provide feedback about this article
Powered by Confluence and Scroll Viewport.