The following scripts have been developed by RealVNC for use with RPort and are provided for example purposes.
Please edit the scripts to your requirements.
Copy and paste these scripts into the RPort script editor, edit as required and save to the RPort script library.
NOTE: These scripts are not supported by RealVNC Limited.
Scripts for Linux clients
NOTE: These scripts are for Debian-based Linux distributions unless otherwise stated.
Install RealVNC Server, cloud join and configure VNC Server - Debian-based and RHEL-based Linux
Please review the settings in bold to ensure they meet your requirements.
# Installs/updates VNC Server and either licenses it offline with license key
# or joins to the cloud with a cloud connectivity token
# LINUX CLIENTS ONLY
#
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
# CONFIGURE PARAMETERS BELOW TO YOUR REQUIREMENTS
# Set version of VNC Server to install, e.g. 7.1.0
# Defaults to Latest
{{$Version := "Latest"}}
# Set if we're using cloud or offline
# Accepted values: offline, cloud
{{$CloudOrOffline := "cloud"}}
# Set offline license to apply
# Not required if joining to the cloud
{{$OfflineLicense := ""}}
# Set cloud connectivity token to join VNC Server to the cloud
# Not required if using direct connections only
{{$CloudToken := "REPLACE WITH YOUR CLOUD JOIN TOKEN"}} # EDIT AS REQUIRED
# Set group to join VNC Server to - group must exist in the VNC Connect portal
# Optional
{{$CloudGroup := ""}}
######################### DO NOT EDIT BELOW THIS LINE ################################
{{$LinuxScriptPath := "/tmp/vnc.sh"}}
template:
file.managed:
- name: {{ $LinuxScriptPath }}
- contents: |
#!/bin/sh
Version="{{ $Version }}"
CloudOrOffline="{{ $CloudOrOffline }}"
OfflineLicense="{{ $OfflineLicense }}"
CloudToken="{{ $CloudToken }}"
CloudGroup="{{ $CloudGroup }}"
# Use TEMP for downloaded files
TempPath="/var/tmp"
# Detect architecture
Architecture="x64"
DetectedArchitecture="$(lscpu | grep Architecture | awk '{print $2}')"
if [ "$DetectedArchitecture" = "i386" ] || [ "$DetectedArchitecture" = "i686" ]; then
Architecture="x86"
elif [ "$DetectedArchitecture" = "aarch64" ]; then
Architecture="ARM64"
elif echo "$DetectedArchitecture" | grep -q "arm"; then
Architecture="ARM"
fi
# Set file extension based on package manager
FileExt=""
if type dpkg /dev/null 2&1; then
FileExt=".deb"
elif type rpm /dev/null 2&1; then
FileExt=".rpm"
fi
# Download VNC Server package from RealVNC website
curl -fsL --retry 3 "https://downloads.realvnc.com/download/file/vnc.files/\
VNC-Server-${Version}-Linux-${Architecture}${FileExt}" -o "${TempPath}/VNC${FileExt}"
# Install VNC Server package
if [ "$FileExt" = ".deb" ]; then
apt install -y "${TempPath}/VNC${FileExt}"
elif [ "$FileExt" = ".rpm" ]; then
yum install -y "${TempPath}/VNC${FileExt}"
fi
# Cleanup package
rm -f "${TempPath}/VNC${FileExt}"
# Determine if we are licensing by key or cloud joining
if [ "$CloudOrOffline" = "offline" ]; then
# Call vnclicense.exe to apply the key
/usr/bin/vnclicense -add "$OfflineLicense"
elif [ "$CloudOrOffline" = "cloud" ]; then
if [ "$(vncserver-x11 -service -cloudstatus | grep CloudJoined | cut -f2 -d':' | sed 's/,//')" = "false" ]; then
# If CloudGroup is set, use it to join VNC Server to that group - group must exist in the VNC Connect portal
if [ -n "$CloudGroup" ]; then
joinGroup="-joinGroup $CloudGroup"
# Call vncserver-x11 to do the cloud join
/usr/bin/vncserver-x11 -service -joinCloud "$CloudToken" "$joinGroup"
else
# Call vncserver.exe to do the cloud join
/usr/bin/vncserver-x11 -service -joinCloud "$CloudToken"
fi
fi
fi
# Add firewall rules if firewalld or ufw are detected
if type firewall-cmd /dev/null 2&1; then
firewall-cmd --zone=public --permanent --add-service=vncserver-x11-serviced
firewall-cmd --reload
elif type ufw /dev/null 2&1; then
ufw allow 5900
fi
# Disable Wayland is detected
gdmconf=""
if [ -f "/etc/gdm3/custom.conf" ]; then gdmconf="/etc/gdm3/custom.conf"; fi
if [ -f "/etc/gdm/custom.conf" ]; then gdmconf="/etc/gdm/custom.conf"; fi
if [ -n "$gdmconf" ]; then
if [ "$(grep -c "^#.*WaylandEnable=false" "$gdmconf")" -gt 0 ]; then
cp -a "$gdmconf" "$gdmconf.bak"
sed -i 's/^#.*WaylandEnable=.*/WaylandEnable=false/' "$gdmconf"
systemctl restart gdm*
fi
fi
systemctl enable vncserver-x11-serviced --now
systemctl restart vncserver-x11-serviced
- skip_verify: true
- mode: 0755
- encoding: UTF-8
cmd.run:
- names:
- sh -x {{ $LinuxScriptPath }}
- rm -f {{ $LinuxScriptPath }}
- shell: sh
# tacoscript to configure RealVNC Server
update-my-realvnc-server:
realvnc_server.config_update:
- encryption: PreferOn # EDIT AS REQUIRED
- server_mode: Service # EDIT AS REQUIRED
- query_connect: false # EDIT AS REQUIRED
- skip_reload: true # EDIT AS REQUIRED
- blank_screen: true # EDIT AS REQUIRED
- authentication: SystemAuth # EDIT AS REQUIRED
- permissions: %sudo:f # EDIT AS REQUIRED
- idle_timeout: '!UNSET!' # EDIT AS REQUIRED
Check RealVNC Server licensing
NOTE: RPort will display success (green status) for licensed VNC Servers and failure (red) where VNC Server is not installed and/or not licensed
#!/bin/bash
########################################################
# USE THIS SCRIPT TO CHECK REALVNC SERVER LICENSES ON #
# LINUX COMPUTERS. RUN THIS SCRIPT FROM RPORT #
#########################################################
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
# LINUX CLIENTS ONLY
#
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
if [ ! -x /usr/bin/vnclicense ];
then
echo "RealVNC Server not installed";
exit 1;
fi
CLOUDSTATUS=`/usr/bin/vncserver-x11 -service -cloudstatus | grep 'CloudJoined' | awk -F ":|," '{print $2}'`
if [[ "$CLOUDSTATUS" == "false" ]];
then echo "Not cloud joined.";
CLOUD=0;
else CLOUD=1;
echo "This computer is joined to a RealVNC Connect cloud team";
#echo "Cloud details:"
#/usr/bin/vncserver-x11 -service -cloudstatus 2> /dev/null
fi
if [ $CLOUD -eq 0 ]; # if we aren't cloud joined, let's check for an offline license
then
LICENSES=`/usr/bin/vnclicense -list`;
echo $LICENSES;
fi
if [[ "$LICENSES" == "No offline license found." ]];
then echo "No offline license found.";
exit 1;
else echo $LICS
fi
Unjoin RealVNC Server from Cloud and uninstall RealVNC Server
#!/bin/bash
# USE THIS SCRIPT TO *REMOVE* REALVNC SERVER FROM LINUX CLIENTS
#
# LINUX CLIENTS ONLY
#
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
# stop the process
systemctl stop vncserver-x11-serviced
# unjoin vncserver from cloud then blat the install
# remove from cloud
echo "*** Performing cloud leave ***"
/usr/bin/vncserver-x11 -service -leavecloud > /dev/null 2>&1
echo "*** Removing Package ***";
apt purge -y realvnc-vnc-server;
echo "*** Removing RealVNC Server directories ***";
rm -rf /etc/vnc;
rm -rf /root/.vnc;
systemctl daemon-reload
Configure RealVNC Server parameters
Please review the settings in bold to ensure they meet your requirements.
# USE THIS SCRIPT TO CONFIGURE REALVNC SERVER FOR LINUX
# NOTE: EDIT THE SETTINGS AS REQUIRED TO MEET YOUR REQUIREMENTS
#
# For further information on RealVNC Server parameters, see:
# https://help.realvnc.com/hc/en-us/articles/360002251297-VNC-Server-Parameter-Reference-
#
# LINUX CLIENTS ONLY
#
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
update-my-realvnc-server:
realvnc_server.config_update:
- encryption: PreferOn # EDIT AS REQUIRED
- server_mode: Service # EDIT AS REQUIRED
- query_connect: false # EDIT AS REQUIRED
- blank_screen: true # EDIT AS REQUIRED
- authentication: SystemAuth # EDIT AS REQUIRED
- permissions: %sudo:f # EDIT AS REQUIRED
- idle_timeout: '!UNSET!' # EDIT AS REQUIRED
Enable ufw firewall and add a rule for SSH
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable
Windows scripts
Install RealVNC Server, cloud join and configure VNC Server
Please review the settings in bold to ensure they meet your requirements.
# Installs/updates VNC Server and either licenses it offline with license key
# or joins to the cloud with a cloud connectivity token
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
# CONFIGURE PARAMETERS BELOW TO YOUR REQUIREMENTS
# Set version of VNC Server to install, e.g. 7.1.0
# Defaults to Latest
{{$Version := "Latest"}}
# Set if we're using cloud or offline
# Accepted values: offline, cloud
{{$CloudOrOffline := "cloud"}}
# Set offline license to apply
# Not required if joining to the cloud
{{$OfflineLicense := ""}}
# Set cloud connectivity token to join VNC Server to the cloud
# Not required if using direct connections only
{{$CloudToken := "REPLACE WITH YOUR CLOUD JOIN TOKEN"}} # EDIT AS REQUIRED
# Set group to join VNC Server to - group must exist in the VNC Connect portal
# Optional
{{$CloudGroup := ""}}
# DO NOT EDIT BELOW THIS LINE
{{$WindowsScriptPath := "C:\\Windows\\Temp\\vnc.ps1"}}
template:
file.managed:
- name: {{ $WindowsScriptPath }}
- contents: |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$Version = "{{ $Version }}"
$CloudOrOffline = "{{ $CloudOrOffline }}"
$OfflineLicense = "{{ $OfflineLicense }}"
$CloudToken = "{{ $CloudToken }}"
$CloudGroup = "{{ $CloudGroup }}"
# Use TEMP for downloaded files
$TempPath = $env:TEMP
# Detect architecture
$Architecture = "64bit"
if ((Get-WmiObject win32_operatingsystem | select osarchitecture).osarchitecture -ne "64-bit"){
$Architecture = "32bit"
}
# Download MSI archive from RealVNC website
Invoke-WebRequest -URI "https://downloads.realvnc.com/download/file/vnc.files/VNC-Server-$Version-Windows-msi.zip" -OutFile "$TempPath/VNC_MSIs.zip"
# Unzip downloaded archive - this requires Powershell 5
Expand-Archive "$TempPath/VNC_MSIs.zip" -DestinationPath "$TempPath/VNC_MSIs" -Force
# Cleanup downloaded archive now that it's been extracted
Remove-Item -Path "$TempPath\VNC_MSIs.zip"
# Select MSI matching OS architecture
$MSIFilename = Get-ChildItem "$TempPath\VNC_MSIs\*$Architecture*.msi" | Select-Object -ExpandProperty Name
# Install VNC Server MSI silently
Start-Process msiexec.exe -Wait -ArgumentList "/I $TempPath\VNC_MSIs\$MSIFilename /qn"
# Cleanup MSIs
Remove-Item -Path "$TempPath\VNC_MSIs" -Recurse
# Determine if we are licensing by key or cloud joining
if ($CloudOrOffline -eq "offline"){
# Call vnclicense.exe to apply the key
Start-Process "C:\Program Files\RealVNC\VNC Server\vnclicense.exe" -Wait -ArgumentList "-add $OfflineLicense"
}
elseif ($CloudOrOffline -eq "cloud"){
if ((& 'C:\Program Files\RealVNC\VNC Server\vncserver.exe' -service -cloudstatus | ConvertFrom-JSON | Select-Object -ExpandProperty CloudJoined) -eq $false){
# If CloudGroup is set, use it to join VNC Server to that group - group must exist in the VNC Connect portal
if ($CloudGroup -ne ""){
$joinGroup = "-joinGroup $CloudGroup"
# Call vncserver.exe to do the cloud join
Start-Process "C:\Program Files\RealVNC\VNC Server\vncserver.exe" -Wait -ArgumentList "-service -joinCloud $CloudToken $joinGroup"
}
else{
Start-Process "C:\Program Files\RealVNC\VNC Server\vncserver.exe" -Wait -ArgumentList "-service -joinCloud $CloudToken"
}
}
}
- skip_verify: true
- mode: 0755
- encoding: UTF-8
cmd.run:
- names:
- PowerShell.exe -ExecutionPolicy Bypass -File {{ $WindowsScriptPath }}
- DEL {{ $WindowsScriptPath }}
- shell: cmd.exe
# tacoscript to configure RealVNC Server
update-my-realvnc-server:
realvnc_server.config_update:
- encryption: PreferOn # EDIT AS REQUIRED
- server_mode: Service # EDIT AS REQUIRED
- query_connect: false # EDIT AS REQUIRED
- blank_screen: true # EDIT AS REQUIRED
- authentication: SystemAuth # EDIT AS REQUIRED
- permissions: %S-1-5-32-544:f # EDIT AS REQUIRED
- idle_timeout: '!UNSET!' # EDIT AS REQUIRED
Check RealVNC Server licensing
NOTE: RPort will display success (green status) for licensed VNC Servers and failure (red) where VNC Server is not installed and/or not licensed
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
function Check-Cloud($command, $argument1, $argument2) {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $command
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $argument1,$argument2
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
# Execute the command and store the output in a variable
try{
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
}
catch{
Write-Output "VNC Server not installed!"
exit 1
}
# Compare the output with the string No offline license found
if ($stdout.Contains("`"CloudJoined`":false")) {
# Throw an error with a custom message
Write-Output "Not cloud joined"
return
}
else {
# Return the output as normal
Write-Output "This computer is joined to a RealVNC Connect cloud team"
#Write-Output $stdout
$cloudjoined=$true
return
}
}
function Check-Direct($command, $argument1) {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $command
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $argument1
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
# Execute the command and store the output in a variable
try{
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
}
catch{
Write-Output "VNC Server not installed!"
exit 1
}
# Compare the output with the string No offline license found
if ($stdout.Trim() -eq "No offline license found.") {
# Throw an error with a custom message
Write-Output "No offline license found"
return
}
else {
# Return the output as normal
Write-Output $stdout
return
}
}
Check-Cloud 'C:\Program Files\RealVNC\VNC Server\vncserver.exe' '-service' '-cloudstatus'
if ($cloudjoined -eq $false)
{
Check-Direct 'C:\Program Files\RealVNC\VNC Server\vnclicense.exe' '-list'
}
else { exit }
Unjoin RealVNC Server from Cloud and uninstall RealVNC Server
# THIS SCRIPT REMOVES REALVNC SERVER FROM WINDOWS CLIENTS
# WINDOWS CLIENTS ONLY
# THIS SCRIPT IS PROVIDED BY REALVNC LIMITED AS PART OF REALONE
write-host "Performing Leave Cloud and uninstalling RealVNC Server"
& "C:\Program Files\RealVNC\VNC Server\vncserver.exe" -service -leavecloud
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "RealVNC Server"
}
$app.Uninstall()
remove-item -path "HKLM:Software\RealVNC" -Recurse
Configure RealVNC Server parameters
Please review the settings in bold to ensure they meet your requirements. Note that %S-1-5-32-544 represents the Administrators group.
Use the RealVNC permissions creator (download from https://www.realvnc.com/en/connect/download/vnc/) to build your permissions string as required.
# USE THIS SCRIPT TO CONFIGURE REALVNC SERVER FOR WINDOWS
# For further information on RealVNC Server parameters, see:
# https://help.realvnc.com/hc/en-us/articles/360002251297-VNC-Server-Parameter-Reference-
update-my-realvnc-server:
realvnc_server.config_update:
- encryption: PreferOn
- server_mode: Service
- query_connect: false
- blank_screen: true
- authentication: SystemAuth
- permissions: %S-1-5-32-544:f
- idle_timeout: '!UNSET!'
Apply Windows updates
#TLS Setting
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#Trust PowerShell Gallery - this will avoid you getting any prompts that it's untrusted
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
#Install NuGet
Install-PackageProvider -name NuGet -Confirm:$false -Force
#Install Module
Install-Module PSWindowsUpdate
#Check what updates are required for this server
Get-WindowsUpdate
#Accept and install all the updates that it's found are required
Install-WindowsUpdate -AcceptAll -AutoReboot
$needReboot = (Get-WURebootStatus -Silent).RebootRequired
if ($needReboot)
{
Write-Host "Windows Update indicated that a reboot is needed."
}
else
{
Write-Host "Windows Update indicated that no reboot is required."
}
Enable Windows Firewall for all profiles (Domain, Public, Private)
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
Write-Host "Windows Firewall Enabled for : Domain, Public, Private"
Check Windows Firewall is Enabled
$FirewallStatus = 0
$SysFirewallReg1 = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\DomainProfile" -Name EnableFirewall | Select-Object -ExpandProperty EnableFirewall
If ($SysFirewallReg1 -eq 1) {
$FirewallStatus = 1
}
$SysFirewallReg2 = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\PublicProfile" -Name EnableFirewall | Select-Object -ExpandProperty EnableFirewall
If ($SysFirewallReg2 -eq 1) {
$FirewallStatus = ($FirewallStatus + 1)
}
$SysFirewallReg3 = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile" -Name EnableFirewall | Select-Object -ExpandProperty EnableFirewall
If ($SysFirewallReg3 -eq 1) {
$FirewallStatus = ($FirewallStatus + 1)
}
If ($FirewallStatus -eq 3) {Write-Host "Compliant"}
ELSE {Write-Host "Non-Compliant"}
Miscellaneous Scripts
Check RealVNC Server licensing (for Windows and Linux clients)
This is a bash script to collect RealVNC Server license details on Windows and Linux clients. The script can be run against RPort client groups, specific clients or clients with specific RPort tags. This script is not intended to be run via RPort's script execution mechanism.
The script produces an output similar to the below.
In this example, there are 2 computers without RealVNC server installed.
----- Results -----
Total no. RPort clients: 13
No. connected RPort clients: 13
No. disconnected RPort clients: 0
No. of clients targeted: 13
No. of Windows clients targeted: 4
No. of Linux clients targeted: 9
Clients with RealVNC Server: 11
Clients without RealVNC Server: 2
Licensed RealVNC Servers: 11
Unlicensed RealVNC Servers: 0
Online licensed RealVNC Servers: 11
Offline licensed RealVNC Servers: 0
Edit the script as necessary for your environment:
#!/bin/bash
RPORT_URL="https://rportserver.com" # EDIT AS APPROPRIATE
API_USERNAME="username" # EDIT AS APPROPRIATE
API_TOKEN=`cat /home/myrportapitoken` # EDIT AS APPROPRIATE
# ONLY USE ONE OF THE BELOW
GROUP_NAMES=("All_Windows_Computers" "All_Linux_Computers") # EDIT AS APPROPRIATE
#CLIENT_NAMES=("Computer1" "Computer2" "Computer3") # EDIT AS APPROPRIATE
#TAG_NAMES=("Tag1" "Tag2") # EDIT AS APPROPRIATE
##########################################################################
##########################################################################
###### ######
###### DO NOT EDIT BELOW THIS SECTION ######
###### ######
##########################################################################
##########################################################################
function curl_with_status_code {
output_file="$1"
target_url="$2"
curl -sL -w "%{http_code}" -u "$AUTH_HEADER" -o "$output_file" --location -g "$target_url"
}
function join_by {
local IFS="$1"
shift
echo "$*"
}
# $1 - message to print
# $2 - exit code
function exit_script {
echo "$1"
rm -rf "$WORK_DIR"
exit "$2"
}
function execute_script {
os_type="$1"
shift
script="$1"
shift
client_list=("$@")
interpreter=""
CLIENT_LIST_STRING=$(printf ',"%s"' "${client_list[@]}")
TARGETS_STRING='"client_ids":['"${CLIENT_LIST_STRING:1}"'],'
MAX_CLIENTS_SCRIPT="${#client_list[@]}"
if [ "$os_type" = "Windows" ]; then
interpreter="powershell"
elif [ "$os_type" = "Linux" ]; then
interpreter="/bin/bash"
fi
response=$(curl -sL -w "%{http_code}" --location "$RPORT_URL/api/v1/scripts" \
--header 'Content-Type: application/json' \
-u "$AUTH_HEADER" \
--data "{$TARGETS_STRING"'
"is_sudo":true,
"interpreter":"'"$interpreter"'",
"timeout_sec":60,
"execute_concurrently":true,
"script":"'"$script"'"
}' -o "$WORK_DIR/scriptexecute.json")
if [ "$response" -ne 200 ]; then
echo "$response"
exit_script "Something went wrong trying to execute the script!" 1
fi
JOB_ID=$(jq -r '.data.jid' "$WORK_DIR/scriptexecute.json")
echo "Waiting 10 seconds to allow script execution to start on $MAX_CLIENTS_SCRIPT $os_type client(s)..."
sleep 10
echo "Querying RPort for script execution status for $MAX_CLIENTS_SCRIPT $os_type client(s)..."
TARGET="$RPORT_URL/api/v1/auditlog?filter[affected_id]=$JOB_ID&filter[action]=execute.done&page[limit]=100"
response=$(curl_with_status_code "$WORK_DIR/auditlog.json" "$TARGET")
CLIENT_ENDED_TOTAL=$(jq -r '.meta.count' "$WORK_DIR/auditlog.json")
echo "Script execution finished on $CLIENT_ENDED_TOTAL of $MAX_CLIENTS_SCRIPT $os_type client(s)..."
while [ "$CLIENT_ENDED_TOTAL" -lt "$MAX_CLIENTS_SCRIPT" ]; do
sleep 3
response=$(curl_with_status_code "$WORK_DIR/auditlog.json" "$TARGET")
CLIENT_ENDED_TOTAL=$(jq -r '.meta.count' "$WORK_DIR/auditlog.json")
echo "Script execution finished on $CLIENT_ENDED_TOTAL of $MAX_CLIENTS_SCRIPT $os_type client(s)..."
done
echo "Processing results of script execution status for $os_type client(s)..."
echo
jq -r '.data[].response' "$WORK_DIR/auditlog.json" > "$WORK_DIR/responses.json"
CLIENT_RESPONSES=$(wc -l < "$WORK_DIR/responses.json")
while [ "$CLIENT_RESPONSES" -lt "$CLIENT_ENDED_TOTAL" ]; do
response=$(curl_with_status_code "$WORK_DIR/auditlog.json" "$TARGET&page[offset]=$CLIENT_RESPONSES")
jq -r '.data[].response' "$WORK_DIR/auditlog.json" >> "$WORK_DIR/responses.json"
CLIENT_RESPONSES=$(wc -l < "$WORK_DIR/responses.json")
done
jq -rs '.[].result.stdout' "$WORK_DIR/responses.json" >> "$WORK_DIR/responses.txt"
}
WORK_DIR=/tmp/rport_vnc
AUTH_HEADER="${API_USERNAME}:${API_TOKEN}"
MAX_CLIENTS=0
TOTAL_CLIENTS=0
TOTAL_CLIENTS_CONNECTED=0
TOTAL_CLIENTS_DISCONNECTED=0
CLIENT_LIST=()
CLIENT_LIST_WINDOWS=()
CLIENT_LIST_LINUX=()
mkdir -p "$WORK_DIR"
response=$(curl_with_status_code "$WORK_DIR/clients.json" "$RPORT_URL/api/v1/clients")
if [ "$response" -eq 200 ]; then
TOTAL_CLIENTS=$(jq -r '.meta.count' "$WORK_DIR/clients.json")
else
exit_script "Error querying RPort for client list" 1
fi
response=$(curl_with_status_code "$WORK_DIR/clients.json" "$RPORT_URL/api/v1/clients?filter[connection_state]=connected")
if [ "$response" -eq 200 ]; then
TOTAL_CLIENTS_CONNECTED=$(jq -r '.meta.count' "$WORK_DIR/clients.json")
else
exit_script "Error querying RPort for connected client list" 1
fi
response=$(curl_with_status_code "$WORK_DIR/clients.json" "$RPORT_URL/api/v1/clients?filter[connection_state]=disconnected")
if [ "$response" -eq 200 ]; then
TOTAL_CLIENTS_DISCONNECTED=$(jq -r '.meta.count' "$WORK_DIR/clients.json")
else
exit_script "Error querying RPort for disconnected client list" 1
fi
if [ "${#GROUP_NAMES[@]}" -gt 0 ]; then
for i in "${GROUP_NAMES[@]}"; do
response=$(curl_with_status_code "$WORK_DIR/group.json" "$RPORT_URL/api/v1/client-groups/$i" )
if [ "$response" -eq 404 ]; then
echo "Client group named $i not found, removing from list"
delete=("$i")
for target in "${delete[@]}"; do
for i2 in "${!GROUP_NAMES[@]}"; do
if [[ ${GROUP_NAMES[i2]} = "$target" ]]; then
unset 'GROUP_NAMES[i2]'
fi
done
done
fi
done
TARGET="$RPORT_URL/api/v1/clients?filter[groups]="'or('"$(join_by "," "${GROUP_NAMES[@]}" | sed 's/ /%20/g')"')&filter[connection_state]=connected&fields[clients]=id,name,hostname,connection_state,os_kernel&page[limit]=500'
elif [ "${#CLIENT_NAMES[@]}" -gt 0 ]; then
for i in "${CLIENT_NAMES[@]}"; do
response=$(curl_with_status_code "$WORK_DIR/clients.json" "$RPORT_URL/api/v1/clients?filter[connection_state]=connected&filter[name]=$i")
update=("$i")
for target in "${update[@]}"; do
for i2 in "${!CLIENT_NAMES[@]}"; do
if [[ ${CLIENT_NAMES[i2]} = "$target" ]]; then
if [ "$(jq -r '.meta.count' "$WORK_DIR/clients.json")" -eq 0 ]; then
echo "Connected client named $i not found, removing from list"
unset 'CLIENT_NAMES[i2]'
fi
fi
done
done
done
TARGET="$RPORT_URL/api/v1/clients?filter[name]="'or('"$(join_by "," "${CLIENT_NAMES[@]}" | sed 's/ /%20/g')"')&filter[connection_state]=connected&fields[clients]=id,name,hostname,connection_state,os_kernel&page[limit]=500'
#CLIENT_LIST=( "${CLIENT_NAMES[@]}" )
elif [ "${#TAG_NAMES[@]}" -gt 0 ]; then
TARGET="$RPORT_URL/api/v1/clients?filter[tags]="'or('"$(join_by "," "${TAG_NAMES[@]}" | sed 's/ /%20/g')"')&filter[connection_state]=connected&fields[clients]=id,name,hostname,connection_state,os_kernel&page[limit]=500'
fi
response=$(curl_with_status_code "$WORK_DIR/clients.json" "$TARGET")
CLIENT_COUNT=0
if [ "$response" -eq 200 ]; then
CLIENT_COUNT=$(jq -r '.meta.count' "$WORK_DIR/clients.json")
jq -r '.data[]' "$WORK_DIR/clients.json" > "$WORK_DIR/client_list.json"
CLIENT_LIST_LENGTH=$(jq '.data | length' "$WORK_DIR/clients.json")
while [ "$CLIENT_LIST_LENGTH" -lt "$CLIENT_COUNT" ]; do
curl -fsL --location -g "$TARGET&page[offset]=$CLIENT_LIST_LENGTH" -u "$AUTH_HEADER" -o "$WORK_DIR/clients.json"
jq -r '.data[]' "$WORK_DIR/clients.json" >> "$WORK_DIR/client_list.json"
CLIENT_LIST_LENGTH=$(( CLIENT_LIST_LENGTH + $(jq '.data | length' "$WORK_DIR/clients.json") ))
done
fi
readarray -t CLIENT_LIST < <(jq -r '.id' "$WORK_DIR/client_list.json")
readarray -t CLIENT_LIST_WINDOWS < <(jq -r 'select(.os_kernel=="windows") | .id' "$WORK_DIR/client_list.json")
readarray -t CLIENT_LIST_LINUX < <(jq -r 'select(.os_kernel=="linux") | .id' "$WORK_DIR/client_list.json")
MAX_CLIENTS="${#CLIENT_LIST[@]}"
MAX_CLIENTS_WINDOWS="${#CLIENT_LIST_WINDOWS[@]}"
MAX_CLIENTS_LINUX="${#CLIENT_LIST_LINUX[@]}"
if [ "$MAX_CLIENTS" -eq 0 ]; then
exit_script "No eligible clients found!" 1
fi
if [ "$MAX_CLIENTS_WINDOWS" -gt 0 ]; then
execute_script "Windows" "JGxpY2Vuc2VkID0gJGZhbHNlCiRsaWNlbnNldHlwZSA9ICIiCiRpbnN0YWxsZWQgPSAkdHJ1ZQoKIyBDcmVhdGUgb2JqZWN0cyBmb3IgUHJvY2VzcyBhbmQgUHJvY2Vzc1N0YXJ0SW5mbyB0aGF0IGNhbiBiZSByZS11c2VkCiRwID0gTmV3LU9iamVjdCBTeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcwokcGluZm8gPSBOZXctT2JqZWN0IFN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzU3RhcnRJbmZvCiRwaW5mby5SZWRpcmVjdFN0YW5kYXJkRXJyb3IgPSAkdHJ1ZQokcGluZm8uUmVkaXJlY3RTdGFuZGFyZE91dHB1dCA9ICR0cnVlCiRwaW5mby5Vc2VTaGVsbEV4ZWN1dGUgPSAkZmFsc2UKJHBpbmZvLkNyZWF0ZU5vV2luZG93ID0gJHRydWUKCiMgVGVzdCBmb3IgY2xvdWQgbGljZW5zZSBmaXJzdAokcGluZm8uRmlsZU5hbWUgPSAnQzpcUHJvZ3JhbSBGaWxlc1xSZWFsVk5DXFZOQyBTZXJ2ZXJcdm5jc2VydmVyLmV4ZScKJHBpbmZvLkFyZ3VtZW50cyA9ICctc2VydmljZScsJy1jbG91ZHN0YXR1cycKJHAuU3RhcnRJbmZvID0gJHBpbmZvCgojIEV4ZWN1dGUgdGhlIGNvbW1hbmQgYW5kIHN0b3JlIHRoZSBvdXRwdXQKdHJ5ewogICAgJHAuU3RhcnQoKSB8IE91dC1OdWxsCiAgICAkcC5XYWl0Rm9yRXhpdCgpCiAgICAkc3Rkb3V0ID0gJHAuU3RhbmRhcmRPdXRwdXQuUmVhZFRvRW5kKCkKICAgICRzdGRlcnIgPSAkcC5TdGFuZGFyZEVycm9yLlJlYWRUb0VuZCgpCn0KY2F0Y2h7CiAgICAjIFRoaXMgd2lsbCBlcnJvciBpZiB2bmNzZXJ2ZXIuZXhlIGlzbid0IGZvdW5kCiAgICAkaW5zdGFsbGVkID0gJGZhbHNlCn0KCmlmICgkaW5zdGFsbGVkIC1lcSAkZmFsc2UpewogICAgV3JpdGUtT3V0cHV0ICJSZWFsVk5DIFNlcnZlciBpcyBub3QgaW5zdGFsbGVkIgp9CmVsc2V7CiAgICAjIENoZWNrIG91dHB1dCB0byBkZXRlcm1pbmUgaWYgUmVhbFZOQyBTZXJ2ZXIgaXMgam9pbmVkIHRvIHRoZSBjbG91ZAogICAgaWYgKCEgJHN0ZG91dC5Db250YWlucygiYCJDbG91ZEpvaW5lZGAiOnRydWUiKSkgewogICAgICAgICMgUmVhbFZOQyBTZXJ2ZXIgaXNuJ3QgY2xvdWQgam9pbmVkLCBzbyBjaGVjayBmb3Igb2ZmbGluZSBsaWNlbnNlCiAgICAgICAgJHBpbmZvLkZpbGVOYW1lID0gJ0M6XFByb2dyYW0gRmlsZXNcUmVhbFZOQ1xWTkMgU2VydmVyXHZuY2xpY2Vuc2UuZXhlJwogICAgICAgICRwaW5mby5Bcmd1bWVudHMgPSAnLWxpc3QnCiAgICAgICAgJHAuU3RhcnRJbmZvID0gJHBpbmZvICAgIAogICAgICAgICRwLlN0YXJ0KCkgfCBPdXQtTnVsbAogICAgICAgICRwLldhaXRGb3JFeGl0KCkKICAgICAgICAkc3Rkb3V0ID0gJHAuU3RhbmRhcmRPdXRwdXQuUmVhZFRvRW5kKCkKICAgICAgICAkc3RkZXJyID0gJHAuU3RhbmRhcmRFcnJvci5SZWFkVG9FbmQoKQogICAgCiAgICAgICAgIyBDaGVjayBvdXRwdXQgdG8gZGV0ZXJtaW5lIGlmIFJlYWxWTkMgU2VydmVyIGhhcyBhbiBvZmZsaW5lIGxpY2Vuc2UKICAgICAgICBpZiAoJHN0ZG91dC5UcmltKCkgLWVxICJObyBvZmZsaW5lIGxpY2Vuc2UgZm91bmQuIikgewogICAgICAgICAgICAjIFJlYWxWTkMgU2VydmVyIGlzbid0IG9mZmxpbmUgbGljZW5zZWQsIGJ1dCBtYXkgYmUgYSBWNyBTZXJ2ZXIgd2l0aCBhIFY2IG9mZmxpbmUgbGljZW5zZSBzbyBjaGVjayBmb3IgdGhhdAogICAgICAgICAgICAkcGluZm8uRmlsZU5hbWUgPSAnQzpcUHJvZ3JhbSBGaWxlc1xSZWFsVk5DXFZOQyBTZXJ2ZXJcdm5jbGljZW5zZS5leGUnCiAgICAgICAgICAgICRwaW5mby5Bcmd1bWVudHMgPSAnLWxlZ2FjeWxpc3QnCiAgICAgICAgICAgICRwLlN0YXJ0SW5mbyA9ICRwaW5mbyAgICAKICAgICAgICAgICAgJHAuU3RhcnQoKSB8IE91dC1OdWxsCiAgICAgICAgICAgICRwLldhaXRGb3JFeGl0KCkKICAgICAgICAgICAgJHN0ZG91dCA9ICRwLlN0YW5kYXJkT3V0cHV0LlJlYWRUb0VuZCgpCiAgICAgICAgICAgICRzdGRlcnIgPSAkcC5TdGFuZGFyZEVycm9yLlJlYWRUb0VuZCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIC1sZWdhY3lsaXN0IHdpbGwgZWl0aGVyIHJldHVybiBWNiBsaWNlbnNlIGRldGFpbHMsIG9yIHByaW50IG5vdGhpbmcgZWl0aGVyIGJlY2F1c2UgdGhlcmUgaXMgbm8gVjYgb2ZmbGluZSBsaWNlbnNlZC8tbGVnYWN5bGlzdGcgbm90IGJlaW5nIHJlY29nbmlzZWQgKFY2IFNlcnZlcikKICAgICAgICAgICAgaWYgKCRzdGRvdXQuTGVuZ3RoIC1ndCAwKXsKICAgICAgICAgICAgICAgICRsaWNlbnNlZCA9ICR0cnVlCiAgICAgICAgICAgICAgICAkbGljZW5zZXR5cGUgPSAib2ZmbGluZSIKICAgICAgICAgICAgfSAgICAgIAogICAgICAgIH0KICAgICAgICBlbHNlewogICAgICAgICAgICAkbGljZW5zZWQgPSAkdHJ1ZQogICAgICAgICAgICAkbGljZW5zZXR5cGUgPSAib2ZmbGluZSIKICAgICAgICB9CiAgICB9CiAgICBlbHNlIHsKICAgICAgICAkbGljZW5zZWQgPSAkdHJ1ZQogICAgICAgICRsaWNlbnNldHlwZSA9ICJvbmxpbmUiCiAgICB9CgogICAgaWYgKCRsaWNlbnNlZCl7CiAgICAgICAgaWYoJGxpY2Vuc2V0eXBlIC1lcSAib25saW5lIil7CiAgICAgICAgICAgICRyZXN1bHQgPSAiUmVhbFZOQyBTZXJ2ZXIgaXMgbGljZW5zZWQgJGxpY2Vuc2V0eXBlIgogICAgICAgIH0KICAgICAgICBlbHNlewogICAgICAgICAgICAkcmVzdWx0ID0gIlJlYWxWTkMgU2VydmVyIGlzIGxpY2Vuc2VkICRsaWNlbnNldHlwZSIKICAgICAgICB9CiAgICAgICAgV3JpdGUtT3V0cHV0ICRyZXN1bHQKICAgICAgICBleGl0IDAKICAgIH0KICAgIGVsc2V7CiAgICAgICAgJHJlc3VsdCA9ICJSZWFsVk5DIFNlcnZlciBpcyB1bmxpY2Vuc2VkIgogICAgICAgIFdyaXRlLU91dHB1dCAkcmVzdWx0CiAgICAgICAgZXhpdCAxCiAgICB9Cn0=" "${CLIENT_LIST_WINDOWS[@]}"
fi
if [ "$MAX_CLIENTS_LINUX" -gt 0 ]; then
execute_script"Linux""IyEvYmluL2Jhc2gKCmxpY2Vuc2VkPSJmYWxzZSIKbGljZW5zZXR5cGU9IiIKCmlmIFsgISAteCAvdXNyL2Jpbi92bmNzZXJ2ZXIteDExIF07IHRoZW4KCWVjaG8gIlJlYWxWTkMgU2VydmVyIGlzIG5vdCBpbnN0YWxsZWQiCglleGl0IDEKZmkKCmNsb3Vkam9pbmVkPSQodm5jc2VydmVyLXgxMSAtc2VydmljZSAtY2xvdWRzdGF0dXMgfCBncmVwIENsb3VkSm9pbmVkIHwgY3V0IC1mMiAtZCc6JyB8IHRyIC1kICcsJykKCiMgQ2hlY2sgb3V0cHV0IHRvIGRldGVybWluZSBpZiBSZWFsVk5DIFNlcnZlciBpcyBqb2luZWQgdG8gdGhlIGNsb3VkCmlmIFsgIiRjbG91ZGpvaW5lZCIgIT0gInRydWUiIF07IHRoZW4KCSMgUmVhbFZOQyBTZXJ2ZXIgaXNuJ3QgY2xvdWQgam9pbmVkLCBzbyBjaGVjayBmb3Igb2ZmbGluZSBsaWNlbnNlCgkKCWxpY2Vuc2VfaW5mbz0kKHZuY2xpY2Vuc2UgLWxpc3QpCgoJIyBDaGVjayBvdXRwdXQgdG8gZGV0ZXJtaW5lIGlmIFJlYWxWTkMgU2VydmVyIGhhcyBhbiBvZmZsaW5lIGxpY2Vuc2UKCWlmIFsgIiRsaWNlbnNlX2luZm8iID0gIk5vIG9mZmxpbmUgbGljZW5zZSBmb3VuZC4iIF07IHRoZW4KCQkjIFJlYWxWTkMgU2VydmVyIGlzbid0IG9mZmxpbmUgbGljZW5zZWQsIGJ1dCBtYXkgYmUgYSBWNyBTZXJ2ZXIgd2l0aCBhIFY2IG9mZmxpbmUgbGljZW5zZSBzbyBjaGVjayBmb3IgdGhhdAoJCWxpY2Vuc2VfaW5mbz0kKHZuY2xpY2Vuc2UgLWxlZ2FjeWxpc3QpCgkJCQkKCQlsaWNlbnNlX2luZm89JCh2bmNsaWNlbnNlIC1sZWdhY3lsaXN0KQoJCSMgLWxlZ2FjeWxpc3Qgd2lsbCBlaXRoZXIgcmV0dXJuIFY2IGxpY2Vuc2UgZGV0YWlscywgb3IgcHJpbnQgbm90aGluZyBlaXRoZXIgYmVjYXVzZSB0aGVyZSBpcyBubyBWNiBvZmZsaW5lIGxpY2Vuc2VkLy1sZWdhY3lsaXN0ZyBub3QgYmVpbmcgcmVjb2duaXNlZCAoVjYgU2VydmVyKQoJCWlmIFsgIiR7I2xpY2Vuc2VfaW5mb30iIC1ndCAwIF07IHRoZW4KCQkJbGljZW5zZWQ9InRydWUiCgkJCWxpY2Vuc2V0eXBlPSJvZmZsaW5lIgoJCWZpCgllbHNlCgkJbGljZW5zZWQ9InRydWUiCgkJbGljZW5zZXR5cGU9Im9mZmxpbmUiCglmaQplbHNlCglsaWNlbnNlZD0idHJ1ZSIKCWxpY2Vuc2V0eXBlPSJvbmxpbmUiCmZpCgppZiBbICIkbGljZW5zZWQiID0gInRydWUiIF07IHRoZW4KCWlmIFsgIiRsaWNlbnNldHlwZSIgPSAib25saW5lIiBdOyB0aGVuCgkJcmVzdWx0PSJSZWFsVk5DIFNlcnZlciBpcyBsaWNlbnNlZCAkbGljZW5zZXR5cGUiCgllbHNlCgkJcmVzdWx0PSJSZWFsVk5DIFNlcnZlciBpcyBsaWNlbnNlZCAkbGljZW5zZXR5cGUiCglmaQoJZWNobyAiJHJlc3VsdCIKCWV4aXQgMAplbHNlCglyZXN1bHQ9IlJlYWxWTkMgU2VydmVyIGlzIHVubGljZW5zZWQiCgllY2hvICIkcmVzdWx0IgoJZXhpdCAxCmZp""${CLIENT_LIST_LINUX[@]}"
fi
echo
echo "----- Results -----"
echo
echo "Total no. RPort clients: $TOTAL_CLIENTS"
echo "No. connected RPort clients: $TOTAL_CLIENTS_CONNECTED"
echo "No. disconnected RPort clients: $TOTAL_CLIENTS_DISCONNECTED"
echo
echo "No. of clients targeted: $MAX_CLIENTS"
echo "No. of Windows clients targeted: $MAX_CLIENTS_WINDOWS"
echo "No. of Linux clients targeted: $MAX_CLIENTS_LINUX"
echo
echo "Clients with RealVNC Server: $(( MAX_CLIENTS - $(grep -c 'RealVNC Server is not installed' $WORK_DIR/responses.txt)))"
echo "Clients without RealVNC Server: $(grep -c 'RealVNC Server is not installed' $WORK_DIR/responses.txt)"
echo "Licensed RealVNC Servers: $(grep -c 'RealVNC Server is licensed' $WORK_DIR/responses.txt)"
echo "Unlicensed RealVNC Servers: $(grep -c 'RealVNC Server is unlicensed' $WORK_DIR/responses.txt)"
echo "Online licensed RealVNC Servers: $(grep -c 'licensed online' $WORK_DIR/responses.txt)"
echo "Offline licensed RealVNC Servers: $(grep -c 'licensed offline' $WORK_DIR/responses.txt)"
exit_script "" 0
Query the RPort Audit log via API
Run the below script on a Linux computer to pull data from the RPort audit log. This could then be ingested into a SIEM such as Elastic. This script is not designed to be executed via RPort using the RPort script execution mechanism.
An RPort API token is required, which in this example has been created by user John and is saved into /home/user/rportapitoken.txt. The RPort server URL in this example is https://rportserver.com
#!/bin/bash
APITOKEN=`cat /home/john/rportapitoken.txt`
AUDITLOG=`curl -X 'GET' -H 'accept: application/json' -s -u john:$APITOKEN https://rportserver.com/api/v1/auditlog?sort=-timestamp`
echo $AUDITLOG | jq '.'
Comments
Article is closed for comments.