Having secure devices plays a major role in meeting compliance requirements. We want to support as many Mobile Device Management solutions (MDMs) like NinjaOne as possible, in addition to providing our agent.
This article goes over how to sync and bring all of your compliance-related information from NinjaOne to Drata.
Prerequisites & Data Access
Make sure you have admin access to your company's NinjaOne account.
Your NinjaOne account has access to NinjaOne public v2 API.
Your NinjaOne account has the ability to create Device Custom Fields and scripts in the Script Library.
We currently support computers. Mobile and tablet devices are not supported.
The NinjaOne agent is installed on monitored endpoints (including
ninjarmm-clion macOS/Linux and support forNinja-Property-Seton Windows).
Permissions & Data Table
Permission/Scope | Why It’s Needed | Data Accessed (Read Only) |
Device inventory | Provide the list of all enrolled devices | Device inventory |
Groups and associated device IDs | Retrieve complete compliance information for each device | Groups and associated device IDs |
Device queries | Retrieve information about volumes, antivirus, patches, software, and custom fields | Installed software verification |
Step-by-Step Setup
Step 1: Configure NinjaOne Custom Fields
NinjaOne does not collect FDE (Full Disk Encryption Status) or Screen Lock information by default. To gather information for these for the purposes of compliance, Drata asks that you enable some scripts in NinjaOne to collect this information from your devices to say to custom fields readable by Drata.
Drata expects the following device custom fields with exact API keys:
dratafdestatus: Full disk encryption status (FDE).Expected values: PASS, FAIL, UNKNOWN.
dratafdeevidence: Free-text evidence describing how the status was determined.dratascreenlockenabled: Screen lock status.Expected values: true, false, unknown (lowercase).
dratascreenlockevidence: Free-text evidence.dratascreenlocktime: Screen lock timeout in minutes (integer).
Recommended field types in NinjaOne
dratafdestatus: text or list field (string) restricted to PASS / FAIL / UNKNOWN.dratafdeevidence: multiline text.dratascreenlockenabled: text or list with true / false / unknown.dratascreenlockevidence: multiline text.dratascreenlocktime: numeric (integer) for minutes.
These names above are validated directly against NinjaOne constants, so the name must match exactly or Drata will treat the data as missing.
Step 2: Drata Scripts in NinjaOne
The following are the scripts customers can copy and paste into NinjaOne to populate the custom fields above. These can be added by performing the following steps in the NinjaOne console:
Sign in as an administrator.
Navigate to Administration → Script Library (in some versions: Configuration → Automation → Scripts).
Create a new script for each of the files below:
Select the appropriate OS type (Windows / Mac / Linux).
Language:
.sh: Shell / Bash..ps1: PowerShell.
Run as System/root (required to read system policies and write custom fields).
Paste the contents of the corresponding .ninjaone file into the script editor.
Save with a clear name, for example:
Drata - FDE (macOS) / Drata - FDE (Ubuntu)Drata - Screen Lock (macOS) / Drata - Screen Lock (Ubuntu) / Drata - Screen Lock (Windows)
Copy and paste the scripts as they are displayed below:
Drata-FDE-mac.sh → macOS, disk encryption (FileVault)
Drata-FDE-mac.sh → macOS, disk encryption (FileVault)
#!/usr/bin/env bash
set -euo pipefail
CLI="/Applications/NinjaRMMAgent/programdata/ninjarmm-cli"
FIELD_STATUS="dratafdestatus"
FIELD_EVIDENCE="dratafdeevidence"
if [[ ! -x "$CLI" ]]; then
echo "ERROR: ninjarmm-cli not found at $CLI"
exit 1
fi
status="UNKNOWN"
parts=()
ev(){ parts+=("$*"); }
# --------------------------------------------
# 1) Primary signal: fdesetup (FileVault)
# --------------------------------------------
out="$(/usr/bin/fdesetup status 2>&1 || true)"
ev "fdesetup_status=$(echo "$out" | tr '\\n' ' ')"
if echo "$out" | /usr/bin/grep -qi "FileVault is On"; then
status="PASS"
elif echo "$out" | /usr/bin/grep -qi "FileVault is Off"; then
status="FAIL"
else
# Do NOT guess — leave UNKNOWN and record why
ev "filevault_status_undetermined"
fi
# --------------------------------------------
# 2) Evidence-only fallback (no decision logic)
# --------------------------------------------
root_info="$(/usr/sbin/diskutil info / 2>/dev/null || true)"
if [[ -n "${root_info:-}" ]]; then
apfs_lines="$(echo "$root_info" | /usr/bin/awk -F: '
/File System Personality/ || /Type \\(Bundle\\)/ || /Encrypted/ {print $0}' | tr '\\n' '|' )"
[[ -n "${apfs_lines:-}" ]] && ev "diskutil_root=${apfs_lines}"
fi
# --------------------------------------------
# Final: write NinjaOne custom fields
# --------------------------------------------
evidence="$(IFS='; '; echo "${parts[*]}")"
printf '%s' "$status" | "$CLI" set --stdin "$FIELD_STATUS" >/dev/null 2>&1 || true
printf '%s' "$evidence" | "$CLI" set --stdin "$FIELD_EVIDENCE" >/dev/null 2>&1 || true
echo "$FIELD_STATUS=$status"
echo "$FIELD_EVIDENCE=$evidence"
Drata-FDE-ubuntu.sh → Ubuntu/Linux, disk encryption (LUKS/dm-crypt)
Drata-FDE-ubuntu.sh → Ubuntu/Linux, disk encryption (LUKS/dm-crypt)
#!/usr/bin/env bash
set -euo pipefail
CLI="/opt/NinjaRMMAgent/programdata/ninjarmm-cli"
FIELD_STATUS="dratafdestatus"
FIELD_EVIDENCE="dratafdeevidence"
if [[ ! -x "$CLI" ]]; then
echo "ERROR: ninjarmm-cli not found at $CLI"
exit 1
fi
status="UNKNOWN"
evidence_parts=()
ev(){ evidence_parts+=("$*"); }
if command -v systemd-detect-virt >/dev/null 2>&1; then
virt="$(systemd-detect-virt 2>/dev/null || true)"
if [[ -n "$virt" && "$virt" != "none" ]]; then
ev "virt=${virt}"
ev "vm_detected_marking_unknown"
status="UNKNOWN"
evidence="$(IFS='; '; echo "${evidence_parts[*]}")"
printf '%s' "$status" | "$CLI" set --stdin "$FIELD_STATUS" >/dev/null 2>&1
printf '%s' "$evidence" | "$CLI" set --stdin "$FIELD_EVIDENCE" >/dev/null 2>&1
echo "$FIELD_STATUS=$status"
echo "$FIELD_EVIDENCE=$evidence"
exit 0
fi
fi
root_src="$(findmnt -no SOURCE / 2>/dev/null || true)"
root_fstype="$(findmnt -no FSTYPE / 2>/dev/null || true)"
ev "findmnt:/ src=${root_src:-<empty>} fstype=${root_fstype:-<empty>}"
if ! command -v lsblk >/dev/null 2>&1; then
ev "lsblk_not_found"
status="UNKNOWN"
else
# Resolve root block device
root_dev=""
if [[ "${root_src:-}" == /dev/* ]]; then
root_dev="$root_src"
fi
if [[ -z "$root_dev" ]]; then
# Try resolve from mountpoint
root_dev="$(findmnt -no SOURCE / 2>/dev/null | head -n 1 || true)"
[[ "$root_dev" != /dev/* ]] && root_dev=""
fi
if [[ -z "$root_dev" ]]; then
ev "could_not_resolve_root_block_device"
status="UNKNOWN"
else
# Check if there is a dm-crypt layer in the chain
chain="$(lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINT -pr "$root_dev" 2>/dev/null || true)"
ev "lsblk_chain:${root_dev} => $(echo "$chain" | tr '\\n' '|')"
if echo "$chain" | awk '{print $2}' | grep -qi '^crypt$'; then
status="PASS"
ev "detected_crypt_layer"
else
# Secondary: if root is a mapper, try cryptsetup status to confirm LUKS
if [[ "$root_dev" == /dev/mapper/* ]] && command -v cryptsetup >/dev/null 2>&1; then
map="$(basename "$root_dev")"
cs="$(cryptsetup status "$map" 2>&1 || true)"
ev "cryptsetup_status:${map} => ${cs}"
if echo "$cs" | grep -qiE 'type:\\s*luks'; then
status="PASS"
ev "confirmed_luks"
else
status="FAIL"
ev "no_crypt_layer_and_not_luks"
fi
else
status="FAIL"
ev "no_crypt_layer_detected_for_root"
fi
fi
fi
fi
evidence="$(IFS='; '; echo "${evidence_parts[*]}")"
printf '%s' "$status" | "$CLI" set --stdin "$FIELD_STATUS" >/dev/null 2>&1
printf '%s' "$evidence" | "$CLI" set --stdin "$FIELD_EVIDENCE" >/dev/null 2>&1
echo "$FIELD_STATUS=$status"
echo "$FIELD_EVIDENCE=$evidence"
Drata-ScreenLock-mac.sh → macOS, screen lock
Drata-ScreenLock-mac.sh → macOS, screen lock
#!/usr/bin/env bash
set -euo pipefail
CLI="/Applications/NinjaRMMAgent/programdata/ninjarmm-cli"
FIELD_ENABLED="dratascreenlockenabled"
FIELD_EVIDENCE="dratascreenlockevidence"
FIELD_TIME="dratascreenlocktime"
if [[ ! -x "$CLI" ]]; then
echo "ERROR: ninjarmm-cli not found at $CLI"
exit 1
fi
enabled="unknown"
timeout_minutes="unknown"
parts=()
ev(){ parts+=("$*"); }
# Console user (logged-in user at GUI)
console_user="$(/usr/bin/stat -f%Su /dev/console 2>/dev/null || true)"
ev "console_user=${console_user:-<empty>}"
# If no GUI user, do not mark as false (Option A behavior)
if [[ -z "${console_user:-}" || "$console_user" == "root" || "$console_user" == "loginwindow" ]]; then
ev "no_active_console_user"
evidence="$(IFS='; '; echo "${parts[*]}")"
printf '%s' "$enabled" | "$CLI" set --stdin "$FIELD_ENABLED" >/dev/null 2>&1 || true
printf '%s' "$evidence" | "$CLI" set --stdin "$FIELD_EVIDENCE" >/dev/null 2>&1 || true
printf '%s' "$timeout_minutes" | "$CLI" set --stdin "$FIELD_TIME" >/dev/null 2>&1 || true
echo "$FIELD_ENABLED=$enabled"
echo "$FIELD_EVIDENCE=$evidence"
echo "$FIELD_TIME=$timeout_minutes"
exit 0
fi
uid="$(/usr/bin/id -u "$console_user" 2>/dev/null || true)"
ev "console_uid=${uid:-<empty>}"
# Helper: run a command in the user's GUI context (more reliable than sudo -u for preferences)
as_user() {
local u="$1"
local uid_local
uid_local="$(/usr/bin/id -u "$u")"
# launchctl asuser needs root; NinjaOne typically runs as root on macOS
/bin/launchctl asuser "$uid_local" /usr/bin/sudo -u "$u" "$@"
}
read_defaults_user() {
local domain="$1"
local key="$2"
as_user "$console_user" /usr/bin/defaults read "$domain" "$key" 2>/dev/null || true
}
read_defaults_user_currenthost() {
local domain="$1"
local key="$2"
as_user "$console_user" /usr/bin/defaults -currentHost read "$domain" "$key" 2>/dev/null || true
}
# 1) Read screensaver/lock settings from the most common sources
# - askForPassword, askForPasswordDelay often under com.apple.screensaver (user)
# - idleTime often under com.apple.screensaver (user), sometimes currentHost
ask_u="$(read_defaults_user "com.apple.screensaver" "askForPassword")"
delay_u="$(read_defaults_user "com.apple.screensaver" "askForPasswordDelay")"
idle_u="$(read_defaults_user "com.apple.screensaver" "idleTime")"
ask_ch="$(read_defaults_user_currenthost "com.apple.screensaver" "askForPassword")"
delay_ch="$(read_defaults_user_currenthost "com.apple.screensaver" "askForPasswordDelay")"
idle_ch="$(read_defaults_user_currenthost "com.apple.screensaver" "idleTime")"
ev "user_defaults com.apple.screensaver ask=${ask_u:-<empty>} delay=${delay_u:-<empty>} idle=${idle_u:-<empty>}"
ev "user_currentHost com.apple.screensaver ask=${ask_ch:-<empty>} delay=${delay_ch:-<empty>} idle=${idle_ch:-<empty>}"
# Prefer non-empty currentHost values (often the real ones), else fall back to user domain
ask="${ask_ch:-$ask_u}"
delay="${delay_ch:-$delay_u}"
idle="${idle_ch:-$idle_u}"
# 2) Also check security domain (some versions expose these)
sec_ask="$(read_defaults_user "com.apple.security.screensaver" "askForPassword")"
sec_delay="$(read_defaults_user "com.apple.security.screensaver" "askForPasswordDelay")"
if [[ -n "${sec_ask:-}" || -n "${sec_delay:-}" ]]; then
ev "user_defaults com.apple.security.screensaver ask=${sec_ask:-<empty>} delay=${sec_delay:-<empty>}"
# If primary ask is empty, fill from security domain
[[ -z "${ask:-}" ]] && ask="$sec_ask"
[[ -z "${delay:-}" ]] && delay="$sec_delay"
fi
# Normalize: ask should be 0/1; delay and idle should be seconds (ints)
if [[ "${ask:-}" =~ ^[0-9]+$ ]]; then
if [[ "$ask" -eq 1 ]]; then
enabled="true"
else
enabled="false"
fi
else
ev "askForPassword_unreadable"
fi
if [[ "$enabled" == "true" ]]; then
if [[ "${idle:-}" =~ ^[0-9]+$ ]]; then
# Some systems may not have delay set; treat missing as 0
if [[ ! "${delay:-0}" =~ ^[0-9]+$ ]]; then delay=0; fi
total_secs=$(( idle + delay ))
timeout_minutes=$(( total_secs / 60 ))
else
ev "idleTime_unreadable"
fi
fi
# 3) Evidence fallback: pmset displaysleep is NOT screen lock, but can be helpful context
display_sleep="$(/usr/bin/pmset -g | awk '/ displaysleep /{print $2; exit}' || true)"
if [[ -n "${display_sleep:-}" ]]; then
ev "pmset_displaysleep=${display_sleep}"
fi
evidence="$(IFS='; '; echo "${parts[*]}")"
printf '%s' "$enabled" | "$CLI" set --stdin "$FIELD_ENABLED" >/dev/null 2>&1 || true
printf '%s' "$evidence" | "$CLI" set --stdin "$FIELD_EVIDENCE" >/dev/null 2>&1 || true
printf '%s' "$timeout_minutes" | "$CLI" set --stdin "$FIELD_TIME" >/dev/null 2>&1 || true
echo "$FIELD_ENABLED=$enabled"
echo "$FIELD_EVIDENCE=$evidence"
echo "$FIELD_TIME=$timeout_minutes"
Drata-ScreenLock-ubuntu.sh → Ubuntu/Linux (GNOME), screen lock
Drata-ScreenLock-ubuntu.sh → Ubuntu/Linux (GNOME), screen lock
#!/usr/bin/env bash
set -euo pipefail
# ============================================
# NinjaOne Custom Fields (Linux path per NinjaOne docs)
# ============================================
CLI="/opt/NinjaRMMAgent/programdata/ninjarmm-cli"
FIELD_ENABLED="dratascreenlockenabled"
FIELD_EVIDENCE="dratascreenlockevidence"
FIELD_TIME="dratascreenlocktime"
# If you set DEBUG=1 in NinjaOne, we append extra runtime details to evidence
DEBUG="${DEBUG:-0}"
# ============================================
# Guards
# ============================================
if [[ ! -x "$CLI" ]]; then
echo "ERROR: ninjarmm-cli not found/executable at: $CLI"
exit 1
fi
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
echo "ERROR: This script must run as root (EUID=0)."
exit 1
fi
enabled="unknown"
timeout_minutes="unknown"
evidence_parts=()
gui_user="" # track whether we had a GUI session to evaluate
gnome_attempted=0 # track whether we attempted GNOME evaluation
log_ev() { evidence_parts+=("$*"); }
# gsettings returns "uint32 300" sometimes
parse_seconds() {
local val="${1:-}"
if [[ "$val" =~ ^uint32\\ ([0-9]+)$ ]]; then
echo "${BASH_REMATCH[1]}"
elif [[ "$val" =~ ^([0-9]+)$ ]]; then
echo "${BASH_REMATCH[1]}"
else
echo ""
fi
}
# ============================================
# Find active GUI session user (GNOME)
# ============================================
get_active_gui_user() {
if command -v loginctl >/dev/null 2>&1; then
while read -r sid uid user seat tty; do
[[ -z "${sid:-}" ]] && continue
[[ "${user:-}" == "root" ]] && continue
local active type class
active="$(loginctl show-session "$sid" -p Active --value 2>/dev/null || true)"
type="$(loginctl show-session "$sid" -p Type --value 2>/dev/null || true)" # x11/wayland/tty/unspecified
class="$(loginctl show-session "$sid" -p Class --value 2>/dev/null || true)" # user/greeter/...
if [[ "$active" == "yes" && ( "$type" == "x11" || "$type" == "wayland" ) && "$class" == "user" ]]; then
echo "$user"
return 0
fi
done < <(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $1,$2,$3,$4,$5}')
fi
# Fallback: who (works sometimes in X11)
who 2>/dev/null | awk '$2 ~ /^:/ {print $1; exit}'
}
# ============================================
# GNOME read with proper DBus/XDG context
# ============================================
read_gnome_lock_settings() {
local user="$1"
local uid
uid="$(id -u "$user" 2>/dev/null || true)"
[[ -z "$uid" ]] && return 1
local xdg="/run/user/$uid"
local bus="unix:path=/run/user/$uid/bus"
if [[ ! -d "$xdg" ]]; then
log_ev "gnome_user=$user but XDG_RUNTIME_DIR missing ($xdg)"
return 1
fi
if ! command -v gsettings >/dev/null 2>&1; then
log_ev "gnome_user=$user gsettings_not_found"
return 1
fi
local lock_enabled idle_delay lock_delay
lock_enabled="$(sudo -u "$user" XDG_RUNTIME_DIR="$xdg" DBUS_SESSION_BUS_ADDRESS="$bus" \\
gsettings get org.gnome.desktop.screensaver lock-enabled 2>/dev/null || true)"
idle_delay="$(sudo -u "$user" XDG_RUNTIME_DIR="$xdg" DBUS_SESSION_BUS_ADDRESS="$bus" \\
gsettings get org.gnome.desktop.session idle-delay 2>/dev/null || true)"
lock_delay="$(sudo -u "$user" XDG_RUNTIME_DIR="$xdg" DBUS_SESSION_BUS_ADDRESS="$bus" \\
gsettings get org.gnome.desktop.screensaver lock-delay 2>/dev/null || true)"
log_ev "gnome_user=$user lock-enabled=${lock_enabled:-<empty>} idle-delay=${idle_delay:-<empty>} lock-delay=${lock_delay:-<empty>}"
# If we cannot read lock_enabled, return failure -> keep unknown
if [[ -z "${lock_enabled:-}" ]]; then
log_ev "gnome_lock_enabled_unreadable"
return 1
fi
if [[ "$lock_enabled" == "true" ]]; then
local idle_secs lock_secs
idle_secs="$(parse_seconds "$idle_delay")"
lock_secs="$(parse_seconds "$lock_delay")"
# If idle-delay is 0, GNOME idle is disabled -> treat as NOT compliant (screen lock wont trigger by idle)
if [[ -z "$idle_secs" || "$idle_secs" -le 0 ]]; then
enabled="false"
timeout_minutes="unknown"
log_ev "gnome_idle_disabled_or_unreadable"
return 0
fi
enabled="true"
lock_secs="${lock_secs:-0}"
local total_secs=$(( idle_secs + lock_secs ))
timeout_minutes=$(( total_secs / 60 ))
return 0
elif [[ "$lock_enabled" == "false" ]]; then
enabled="false"
timeout_minutes="unknown"
return 0
fi
# Any other output -> unknown
log_ev "gnome_lock_enabled_unexpected_value=$lock_enabled"
return 1
}
# ============================================
# We ONLY evaluate GNOME (desktop) and if no GUI session exists we report UNKNOWN
# ============================================
gui_user="$(get_active_gui_user || true)"
if [[ -n "${gui_user:-}" ]]; then
gnome_attempted=1
read_gnome_lock_settings "$gui_user" || true
else
log_ev "no_active_gui_user_session_detected"
fi
# If GNOME was attempted but still unknown, note it explicitly
if [[ "$gnome_attempted" -eq 1 && "$enabled" == "unknown" ]]; then
log_ev "gnome_attempted_but_result_unknown"
fi
# DEBUG (optional)
if [[ "$DEBUG" == "1" ]]; then
log_ev "debug whoami=$(whoami) display=${DISPLAY:-<empty>}"
if command -v loginctl >/dev/null 2>&1; then
log_ev "debug loginctl_sessions=$(loginctl list-sessions --no-legend 2>/dev/null | tr '\\n' '|' || true)"
fi
fi
# Build evidence
evidence="$(IFS='; '; echo "${evidence_parts[*]}")"
# Write back to NinjaOne custom fields
printf '%s' "$enabled" | "$CLI" set --stdin "$FIELD_ENABLED" >/dev/null 2>&1
printf '%s' "$evidence" | "$CLI" set --stdin "$FIELD_EVIDENCE" >/dev/null 2>&1
printf '%s' "$timeout_minutes" | "$CLI" set --stdin "$FIELD_TIME" >/dev/null 2>&1
echo "$FIELD_ENABLED=$enabled"
echo "$FIELD_EVIDENCE=$evidence"
echo "$FIELD_TIME=$timeout_minutes"
Drata-ScreenLock-win.ps1 → Windows, screen lock
Drata-ScreenLock-win.ps1 → Windows, screen lock
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Set-Field([string]$Name, [string]$Value) {
try {
Ninja-Property-Set $Name $Value
Write-Host "SUCCESS: Set $Name = $Value"
} catch {
Write-Host "ERROR setting $Name : $($_.Exception.Message)"
}
}
function Get-RegValueSafe([string]$Path, [string]$Name) {
try {
$item = Get-ItemProperty -Path $Path -ErrorAction Stop
if ($null -ne $item.PSObject.Properties[$Name]) { return $item.$Name }
return $null
} catch { return $null }
}
function To-IntSafe($v) {
if ($null -eq $v) { return $null }
try {
if ($v -is [int]) { return $v }
if ($v -is [long]) { return [int]$v }
if ($v -is [uint32]) { return [int]$v }
$s = [string]$v
if ($s -match '^\\d+$') { return [int]$s }
return $null
} catch { return $null }
}
function Get-LoggedOnUserSID {
try {
$explorer = $null
try {
$explorer = Get-CimInstance Win32_Process -Filter "Name='explorer.exe'" -ErrorAction Stop | Select-Object -First 1
} catch {
$explorer = Get-WmiObject -Class Win32_Process -Filter "Name='explorer.exe'" -ErrorAction Stop | Select-Object -First 1
}
if ($explorer) {
$owner = $explorer.GetOwner()
if ($owner -and $owner.User) {
$username = "$($owner.Domain)\\$($owner.User)"
$user = New-Object System.Security.Principal.NTAccount($username)
$sid = $user.Translate([System.Security.Principal.SecurityIdentifier]).Value
return @{ Username = $owner.User; SID = $sid }
}
}
} catch { }
return $null
}
$enabled = "unknown"
$parts = New-Object System.Collections.Generic.List[string]
$source = "None"
$timeoutMinutes = "unknown"
# Track whether there was an interactive user session we could have checked
$hadLoggedOnUser = $false
try {
# 0) MDM/Intune Policy CSP (PolicyManager)
$mdmPath = "HKLM:\\SOFTWARE\\Microsoft\\PolicyManager\\current\\device\\DeviceLock"
$mdmRaw = Get-RegValueSafe $mdmPath "MaxInactivityTimeDeviceLock"
$mdm = To-IntSafe $mdmRaw
$parts.Add("MDM.DeviceLock.MaxInactivityTimeDeviceLock=$mdmRaw")
if ($null -ne $mdm -and $mdm -gt 0) {
$enabled="true"
$source="MDM(DeviceLock.MaxInactivityTimeDeviceLock)"
# MaxInactivityTimeDeviceLock is in minutes
$timeoutMinutes = $mdm
}
# 1) System policy (GPO-like)
if ($enabled -eq "unknown") {
$sysPath = "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"
$inactRaw = Get-RegValueSafe $sysPath "InactivityTimeoutSecs"
$inact = To-IntSafe $inactRaw
$parts.Add("SystemPolicy.InactivityTimeoutSecs=$inactRaw")
if ($null -ne $inact -and $inact -gt 0) {
$enabled="true"
$source="SystemPolicy(InactivityTimeoutSecs)"
$timeoutMinutes = [math]::Ceiling($inact / 60)
}
}
# 2) Screen saver policy (GPO-enforced)
if ($enabled -eq "unknown") {
$ssPath = "HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\Control Panel\\Desktop"
$ssActiveRaw = Get-RegValueSafe $ssPath "ScreenSaveActive"
$ssSecureRaw = Get-RegValueSafe $ssPath "ScreenSaverIsSecure"
$ssTimeoutRaw = Get-RegValueSafe $ssPath "ScreenSaveTimeOut"
$ssActive = To-IntSafe $ssActiveRaw
$ssSecure = To-IntSafe $ssSecureRaw
$ssTimeout = To-IntSafe $ssTimeoutRaw
$parts.Add("ScreenSaverPolicy.ScreenSaveActive=$ssActiveRaw")
$parts.Add("ScreenSaverPolicy.ScreenSaverIsSecure=$ssSecureRaw")
$parts.Add("ScreenSaverPolicy.ScreenSaveTimeOut=$ssTimeoutRaw")
if ($null -ne $ssTimeout -and $ssTimeout -gt 0 -and $ssActive -eq 1 -and $ssSecure -eq 1) {
$enabled="true"
$source="ScreenSaverPolicy(Active+Secure+Timeout)"
$timeoutMinutes = [math]::Ceiling($ssTimeout / 60)
}
}
# 3) User-level screen saver settings (logged-on user's registry)
if ($enabled -eq "unknown") {
$loggedOnUser = Get-LoggedOnUserSID
if ($loggedOnUser) {
$hadLoggedOnUser = $true
# Mount HKU if not already available
if (-not (Test-Path "HKU:\\")) {
New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS -ErrorAction SilentlyContinue | Out-Null
}
$userPath = "HKU:\\$($loggedOnUser.SID)\\Control Panel\\Desktop"
$userActiveRaw = Get-RegValueSafe $userPath "ScreenSaveActive"
$userSecureRaw = Get-RegValueSafe $userPath "ScreenSaverIsSecure"
$userTimeoutRaw = Get-RegValueSafe $userPath "ScreenSaveTimeOut"
$userActive = To-IntSafe $userActiveRaw
$userSecure = To-IntSafe $userSecureRaw
$userTimeout = To-IntSafe $userTimeoutRaw
$parts.Add("LoggedOnUser=$($loggedOnUser.Username)")
$parts.Add("UserScreenSaver.ScreenSaveActive=$userActiveRaw")
$parts.Add("UserScreenSaver.ScreenSaverIsSecure=$userSecureRaw")
$parts.Add("UserScreenSaver.ScreenSaveTimeOut=$userTimeoutRaw")
if ($null -ne $userTimeout -and $userTimeout -gt 0 -and $userActive -eq 1 -and $userSecure -eq 1) {
$enabled="true"
$source="UserScreenSaver(Active+Secure+Timeout)"
# ScreenSaveTimeOut is in seconds
$timeoutMinutes = [math]::Ceiling($userTimeout / 60)
}
} else {
$parts.Add("UserScreenSaver.NoLoggedOnUser")
}
}
# If we couldn't find any device-level policy AND no interactive user session exists,
# report UNKNOWN rather than FALSE (avoids false negatives when device is at login screen)
if ($enabled -eq "unknown") {
if ($hadLoggedOnUser -eq $false -and $source -eq "None") {
$enabled = "unknown"
$timeoutMinutes = "unknown"
$source = "NoLoggedOnUserAndNoDevicePolicy"
} else {
# If user exists but settings don't enforce lock, treat as non-compliant
$enabled = "false"
}
}
}
catch {
$enabled = "unknown"
$source = "Error"
$timeoutMinutes = "unknown"
$parts.Clear()
$parts.Add("Error: $($_.Exception.Message)")
}
$evidence = "source=$source; " + ($parts -join "; ")
Set-Field "dratascreenlockenabled" $enabled
Set-Field "dratascreenlockevidence" $evidence
Set-Field "dratascreenlocktime" $timeoutMinutes
Write-Host "dratascreenlockenabled=$enabled"
Write-Host "dratascreenlockevidence=$evidence"
Write-Host "dratascreenlocktime=$timeoutMinutes"
Specific options for Linux screen lock (Drata-ScreenLock-ubuntu.sh):
Optional environment variable DEBUG=1 to add more details into
dratascreenlockevidence.
For all scripts, it is recommended to:
Log standard output in NinjaOne for troubleshooting.
Keep evidence text in English (consistent with other Drata connectors).
Step 3: Connect NinjaOne to Drata
In Drata, go to Connections page.
Search for and select NinjaOne.
When connecting:
Choose either Standard region or Custom domain based on your NinjaOne setup.
Enter either the NinjaOne region you are using, or the full subdomain or host name.
Click Save & Test Connection.
You will be redirected to a NinjaOne OAuth page. Review that the account detail are correct and you are signed in to NinjaOne with the right account.
Step 4: Enable NinjaOne and Verify the Connection
In Drata, navigate to Settings → Internal Security page.
Under Workstation Configuration Monitoring, toggle:
Automated via NinjaOne MDM: ON
Automated via Drata Agent: OFF (optional)
Note: If both are ON, Drata Agent data takes precedence.
