Python Script for Reporting on Juniper Pulse Secure Connected Users
We use a pair of Juniper MAG-2600’s for the majority of VPN connections into our environment. Limited by licensing, I was asked to generate a daily report on connected users, so that senior management can have visibility of and review users that are working from home due to the Covid-19 pandemic.
As far as I could tell (please correct me if I’m wrong!) there is no way to schedule such a report automatically from the Pulse Secure admin page.
So, looking for an excuse to do some scripting, I wrote the below Python script to send an email report which simply provides a list of staff members who have connected via Pulse Secure VPN for that day.
It ain’t pretty. It’s not the most efficient. It’s not particularly secure. But it was fun to write!
It uses Selenium to log into the Pulse Secure admin page and download the User Summary Report in CSV format.
While I could have just dumped this into an email and be done with it, this was too much information for the people requesting this, they just wanted a list of names.
In our environment we don’t use any identifiable information in the samAccountName, it is a random string, for a certain amount of security through obscurity. So the rest of the script deals with converting the username field of the Pulse Secure CSV into the readable display name for the email. This unfortunately relies on a pre-dump of current domain users from PowerShell to compare the Pulse Secure samaccountnames against, so it’s not quite a completely self contained script.
Bit of a niche script, but maybe somebody out there will find something of use in it!
''' A script that pulls User Summary CSV report from Pulse Secure, parses it to list of Display Names, and emails this list to recipients. '''
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.keys import Keys
import csv
import smtplib
import glob, os
from datetime import datetime
def getUserLogFromPulseSecure():
# Function logs into Pulse Secure and downloads User Activity log for the past 24 hours
# ChomeDriver for Chrome 80 downloaded from https://chromedriver.storage.googleapis.com/index.html?path=80.0.3987.106/
# and placed in C:\Windows\System32. Confirm in PATH by running chromedriver in CMD
driver = webdriver.Chrome()
# URL for Secure Remote login page
url = 'https://x.x.x.x/dana-na/auth/url_admin/welcome.cgi'
driver.get(url)
# Click Advanced/Proceed on SSL Certificate warning screen
driver.find_element_by_id("details-button").click()
driver.find_element_by_id("proceed-link").click()
# Find username field and enter username
username = driver.find_element_by_id("username")
username.clear()
username.send_keys("admin")
# Find password field and enter password
password = driver.find_element_by_id("password")
password.clear()
password.send_keys("YourPassword")
# Find Sumbit button and click
driver.find_element_by_name("btnSubmit").click()
# If admin account is already logged in, there may be a warning. If so, click "Read only access", otherwise proceed
try:
driver.find_element_by_name("btnReadOnly").click()
except:
pass
# Fix to open a new tab, allowing a direct URL to be entered without starting a new session
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
# Direct link to downloaded the CSV log file of active sessions
driver.get("https://x.x.x.x/dana-admin/reporting/report_user_summary.cgi?download=1&format=csv&date_range=24hours&username=&realm=&sort_column=username&sort_order=2")
# Small pause to allow CSV file to complete download
sleep(3)
def getSamAccountNameFromPulseSecureLog(pathToCSV):
# Empty array to hold user samaccountname ID strings
users_by_samaccountname = []
# Count to skip first line of CSV file (headings)
count = 0
with open(pathToCSV) as csv_file:
csv_reader = csv.reader(csv_file)
for line in csv_reader:
# Skip first blank line
if count == 0:
count += 1
else:
users_by_samaccountname.append(str(line[0][8:]))
count += 1
# Return an array of samaccountname IDs
return users_by_samaccountname
def getUsersOnPulseSecureLast24Hr(users_by_samaccountname):
# Create a blank dictionary to hold samaccountname:displayname string pairs
allUserDict = {}
# Read all current samaccountnames from a pre-made list generated from Powershell
# get-aduser -filter * | select samaccountname, name | out-file c:\allusers.txt
# Replace spaces with commas in text editor, import the text file into Excel CSV using commas as delimiter
with open(r'c:\Scripts\allusers.csv') as csv_file:
csv_reader = csv.reader(csv_file)
for line in csv_reader:
allUserDict[line[0].lower()] = line[1]
# Blank list to hold string of user samaccountnames from Secure Pulse log
usersLast24Hr = []
for user in users_by_samaccountname:
if user in allUserDict:
usersLast24Hr.append(allUserDict[user])
# Return a list of user samaccountname ID strings
return usersLast24Hr
def getPathToLatestReport():
# The CSV downloaded from Pulse Secure automatically downloads to Downloads folder. This function selects the
# latest CSV file. Small chance if will pick up a non-Pulse Secure related CSV file!
list_of_files = glob.glob(r'c:\users\xxxxx\downloads\*.csv')
latest_file = max(list_of_files, key=os.path.getctime)
print(f"Using file: {latest_file}")
# Returns full path to the CSV file
return latest_file
def sendMailReport(users_last_24hr):
# Send email report to emails in 'recipients' list
dateString = "{:%B %d, %Y}".format(datetime.now())
sender = 'pulse_secure_user_report@example.com'
recipients = ['admin@example.com', 'manager@examples.com']
server = smtplib.SMTP('YOUR_SMTP_SERVER', 25)
subject = f'Pulse Secure User Report for {dateString}'
msg = f'Subject: {subject}\n\nThe following users were connected to Pulse Secure in the past 24 hours: \n\n'
for user in users_last_24hr:
msg += user + "\n"
server.sendmail(sender, recipients, msg)
getUserLogFromPulseSecure()
users_by_samaccountname = getSamAccountNameFromPulseSecureLog(getPathToLatestReport())
users_last_24hr = getUsersOnPulseSecureLast24Hr(users_by_samaccountname)
sendMailReport(users_last_24hr)