Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

429+ Articles
114+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. HOWTOs
  3. SentinelOne Health Check: Agent Status Monitoring and
SentinelOne Health Check: Agent Status Monitoring and
HOWTOAdvanced

SentinelOne Health Check: Agent Status Monitoring and

Organizations deploying SentinelOne endpoint protection require continuous monitoring of agent health to ensure comprehensive threat coverage across their...

Dylan H.

Security Operations

February 11, 2026
17 min read

SCENARIO

Organizations deploying SentinelOne endpoint protection require continuous monitoring of agent health to ensure comprehensive threat coverage across their environment. Unlike traditional antivirus solutions, SentinelOne agents must maintain active console connectivity, real-time protection engines, and current threat intelligence to function effectively.

Use this script when you need to:

  • Automate SentinelOne agent health monitoring across managed endpoints
  • Detect agents with stopped services, disabled protection, or console connectivity issues
  • Report agent status metrics to NinjaRMM for centralized dashboard visibility
  • Identify endpoints requiring manual intervention (service restarts, re-registration, updates)
  • Validate SentinelOne deployment health after mass installations or policy changes

Business Impact:

  • Security gaps: Disconnected or disabled agents leave endpoints vulnerable to threats
  • Compliance risks: Inactive protection may violate security compliance requirements (SOC 2, HIPAA, PCI-DSS)
  • Operational visibility: Automated reporting eliminates manual console checks across hundreds of endpoints

This script provides proactive alerting before security incidents occur, rather than reactive troubleshooting after breaches.


REQUIREMENTS & ASSUMPTIONS

Prerequisites:

  • SentinelOne Agent: Installed with sentinelctl.exe present in C:\Program Files\SentinelOne\Sentinel Agent *\
  • Administrator Privileges: Script requires #Requires -RunAsAdministrator for service queries
  • PowerShell 5.1 or Later: Uses modern cmdlets and error handling
  • NinjaRMM Agent (optional but recommended): For automated custom field updates

NinjaRMM Custom Fields Configuration: The script updates these custom fields in NinjaRMM. Create them as text fields before deployment:

  • s1_agent_status - Overall health status (HEALTHY, DISCONNECTED, PROTECTION_DISABLED, etc.)
  • s1_agent_version - Installed agent version (e.g., "23.4.2.15")
  • s1_last_update - Last agent update timestamp
  • s1_protection_status - Threat engine status (ACTIVE, DISABLED, UNKNOWN)
  • s1_console_connectivity - Management console connection (CONNECTED, DISCONNECTED)

System Assumptions:

  • SentinelOne service name is SentinelAgent (standard installation)
  • Log directory C:\BIN\ is writable (created automatically if missing)
  • Network connectivity allows console communication (firewall rules permit SentinelOne management traffic)
  • Agent is registered with a SentinelOne management console

Tool Verification:

  • Validate SentinelOne installation: Test-Path "${env:ProgramFiles}\SentinelOne\Sentinel Agent *\SentinelCtl.exe"
  • Verify service status: Get-Service -Name SentinelAgent
  • Confirm NinjaRMM integration: Get-Command Ninja-Property-Set -ErrorAction SilentlyContinue

PROCESS

Agent Health Check Workflow

The script performs a comprehensive eight-step health validation process:

flowchart TD
    Start([Script Execution]) --> CheckInstall[Step 1: Test-SentinelOneInstalled]
 
    CheckInstall --> InstallFound{sentinelctl.exe<br/>Found?}
    InstallFound -->|No| NotInstalled[Set Status: NOT_INSTALLED<br/>Exit Code 1]
    InstallFound -->|Yes| CheckService[Step 2: Get-SentinelService]
 
    CheckService --> ServiceRunning{Service<br/>Running?}
    ServiceRunning -->|No| ServiceStopped[Set Status: SERVICE_STOPPED<br/>Exit Code 1]
    ServiceRunning -->|Yes| GetInfo[Step 3: Get-SentinelAgentInfo]
 
    GetInfo --> InfoSuccess{Query<br/>Successful?}
    InfoSuccess -->|No| QueryFailed[Set Status: QUERY_FAILED<br/>Exit Code 1]
    InfoSuccess -->|Yes| CheckProtection[Step 4: Get-SentinelThreatProtection]
 
    CheckProtection --> CheckConnectivity[Step 5: Test-SentinelConsoleConnectivity]
    CheckConnectivity --> CheckUpdates[Step 6: Get-SentinelPendingActions]
    CheckUpdates --> Evaluate[Step 7: Determine Overall Status]
 
    Evaluate --> EvalConsole{Console<br/>Connected?}
    EvalConsole -->|No| StatusDisc[Status: DISCONNECTED<br/>Exit Code 2]
    EvalConsole -->|Yes| EvalProtection{Protection<br/>Active?}
 
    EvalProtection -->|No| StatusProt[Status: PROTECTION_DISABLED<br/>Exit Code 2]
    EvalProtection -->|Yes| EvalUpdate{Pending<br/>Updates?}
 
    EvalUpdate -->|Yes| StatusUpdate[Status: UPDATE_PENDING<br/>Exit Code 2]
    EvalUpdate -->|No| StatusHealthy[Status: HEALTHY<br/>Exit Code 0]
 
    StatusDisc --> Report[Step 8: Report to NinjaRMM]
    StatusProt --> Report
    StatusUpdate --> Report
    StatusHealthy --> Report
 
    Report --> UpdateFields[Update Custom Fields:<br/>- s1_agent_status<br/>- s1_agent_version<br/>- s1_last_update<br/>- s1_protection_status<br/>- s1_console_connectivity]
    UpdateFields --> Complete([Script Exit])
 
    NotInstalled --> Complete
    ServiceStopped --> Complete
    QueryFailed --> Complete
 
    style Start fill:#90EE90
    style StatusHealthy fill:#90EE90
    style Complete fill:#90EE90
    style NotInstalled fill:#FF6B6B
    style ServiceStopped fill:#FF6B6B
    style QueryFailed fill:#FF6B6B
    style StatusDisc fill:#FFD700
    style StatusProt fill:#FFD700
    style StatusUpdate fill:#FFA500

Step 1: Validate Script Syntax and Parameters

Download or copy the script to your management workstation and validate it compiles correctly:

pwsh -NoLogo -File .\Check-SentinelOne-Health.ps1 -WhatIf

Step 2: Test on a Single Endpoint

Before mass deployment, run the script on a test system with known-good SentinelOne agent:

 
.\Check-SentinelOne-Health.ps1

Step 3: Review Log Output

Check the generated log file for detailed execution results:

# Open today's log file
notepad "C:\BIN\LOGS-$(Get-Date -Format 'yyyy-MM-dd')-SentinelOne-Health.log"

Expected log entries for a healthy agent:

[2025-11-26 14:30:01] [INFO] ========== SentinelOne Health Check Started ==========
[2025-11-26 14:30:02] [SUCCESS] SentinelOne sentinelctl.exe found: C:\Program Files\SentinelOne\Sentinel Agent 23.4.2.15\SentinelCtl.exe
[2025-11-26 14:30:03] [SUCCESS] Service 'SentinelAgent' status: Running
[2025-11-26 14:30:05] [INFO] Agent Version: 23.4.2.15
[2025-11-26 14:30:05] [INFO] Console Connectivity: Yes
[2025-11-26 14:30:06] [SUCCESS] Threat Protection Engine: Active
[2025-11-26 14:30:07] [SUCCESS] No pending updates detected
[2025-11-26 14:30:08] [SUCCESS] Overall Agent Status: HEALTHY

Step 4: Verify NinjaRMM Custom Field Updates

If NinjaRMM integration is configured, confirm the custom fields populated correctly:

  1. Log into NinjaRMM dashboard
  2. Navigate to the test endpoint device details
  3. Check the custom fields section for s1_* fields
  4. Verify values match the log output

Step 5: Interpret Health Status Codes

SentinelOne Agent Architecture

Understanding the agent's component dependencies helps diagnose health check failures:

graph TB
    subgraph Endpoint["Windows Endpoint"]
        subgraph Agent["SentinelOne Agent Installation"]
            SentinelCtl[sentinelctl.exe<br/>CLI Management Tool]
            Service[SentinelAgent Service<br/>Windows Service]
            Engine[Threat Protection Engine<br/>Behavioral AI]
            Config[Agent Configuration<br/>Console URL, Policies]
        end
 
        subgraph OS["Operating System"]
            WinService[Windows Service Manager]
            Network[Network Stack]
            FileSystem[File System Monitoring]
        end
    end
 
    subgraph External["External Dependencies"]
        Console[SentinelOne Management Console<br/>Cloud/On-Premises]
        ThreatIntel[Threat Intelligence Feed<br/>Real-Time Updates]
    end
 
    Service --> WinService
    Service --> Engine
    Service --> FileSystem
    Engine --> FileSystem
    Engine --> ThreatIntel
    Service --> Network
    Network --> Console
    Config --> Console
    SentinelCtl --> Service
 
    Script[Health Check Script] -.Query.-> SentinelCtl
    Script -.Check Status.-> Service
    Script -.Validate.-> Engine
    Script -.Test Connectivity.-> Console
 
    style Service fill:#FF9999,stroke:#333,stroke-width:3px
    style Engine fill:#99CCFF,stroke:#333,stroke-width:2px
    style Console fill:#90EE90,stroke:#333,stroke-width:2px
    style Script fill:#FFD700,stroke:#333,stroke-width:3px

Component Health Checks:

ComponentHealth Check MethodFailure Impact
sentinelctl.exeFile existence checkScript cannot query agent status (NOT_INSTALLED)
SentinelAgent ServiceGet-Service status checkAgent inactive, no threat protection (SERVICE_STOPPED)
Threat Enginesentinelctl engine statusService running but not blocking threats (PROTECTION_DISABLED)
Console Connectivitysentinelctl status parsingNo policy updates, unmanaged agent (DISCONNECTED)
Pending Updatessentinelctl check-updateAgent functional but outdated (UPDATE_PENDING)

The script reports these overall agent status codes:

Status CodeMeaningRecommended Action
HEALTHYAll checks passedNo action required
DISCONNECTEDConsole connectivity lostCheck network/firewall, verify console URL
PROTECTION_DISABLEDThreat engine inactiveReview policies, re-enable protection in console
UPDATE_PENDINGAgent update availableSchedule maintenance window for update
SERVICE_STOPPEDSentinelAgent service not runningRestart service: Restart-Service SentinelAgent
SERVICE_NOT_FOUNDService missingReinstall SentinelOne agent
NOT_INSTALLEDAgent not detectedDeploy SentinelOne agent
QUERY_FAILEDsentinelctl.exe errorCheck agent installation integrity
HEALTH_CHECK_FAILEDScript exceptionReview log file for error details

Step 6: Deploy via NinjaRMM Automation

For mass deployment to managed endpoints:

  1. Upload script to NinjaRMM Scripts repository
  2. Create scheduled automation task (recommended: daily execution)
  3. Set execution context to System/Administrator
  4. Configure alerting for non-HEALTHY status codes
  5. Monitor dashboard for custom field population

Step 7: Troubleshoot Unhealthy Agents

When agents report non-HEALTHY status, follow these remediation steps:

For DISCONNECTED status:

# Verify network connectivity to management console
Test-NetConnection -ComputerName <your-sentinelone-console>.sentinelone.net -Port 443
 
# Check proxy settings if applicable
& "C:\Program Files\SentinelOne\Sentinel Agent *\SentinelCtl.exe" config show
 
# Force agent re-registration
& "C:\Program Files\SentinelOne\Sentinel Agent *\SentinelCtl.exe" management reconnect

For PROTECTION_DISABLED status:

# Check protection engine state
& "C:\Program Files\SentinelOne\Sentinel Agent *\SentinelCtl.exe" engine status
 
# Enable protection (if disabled locally)
& "C:\Program Files\SentinelOne\Sentinel Agent *\SentinelCtl.exe" engine start
 
# Verify policy in SentinelOne console (may be disabled by policy)

For SERVICE_STOPPED status:

# Check service startup type
Get-Service SentinelAgent | Select-Object Name, Status, StartType
 
# Set to automatic and start
Set-Service SentinelAgent -StartupType Automatic
Start-Service SentinelAgent
 
# Verify service started successfully
Get-Service SentinelAgent

Step 8: Schedule Automated Execution

For standalone systems not using NinjaRMM, create a scheduled task:

# Create daily scheduled task (runs at 2 AM)
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-ExecutionPolicy Bypass -NoProfile -File "C:\Scripts\Check-SentinelOne-Health.ps1"'
$trigger = New-ScheduledTaskTrigger -Daily -At 2AM
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
 
Register-ScheduledTask -TaskName "SentinelOne Health Monitor" -Action $action -Trigger $trigger -Principal $principal -Settings $settings

Step 9: Monitor and Alert

Establish monitoring thresholds for proactive alerting:

  • Critical Alert: Status is NOT_INSTALLED, SERVICE_NOT_FOUND, or DISCONNECTED for >24 hours
  • Warning Alert: Status is PROTECTION_DISABLED, UPDATE_PENDING, or SERVICE_STOPPED
  • Info Alert: First-time agent detection (status changes from NOT_INSTALLED to HEALTHY)

Configure NinjaRMM conditions or parse log files for automated ticketing integration.


SCRIPT DETAIL

Core Functions and Logic Flow

1. Installation Detection (Test-SentinelOneInstalled)

The script uses wildcard path expansion to locate sentinelctl.exe regardless of agent version:

$sentinelCtlPath = "${env:ProgramFiles}\SentinelOne\Sentinel Agent *\SentinelCtl.exe"
$sentinelCtl = Get-Item $sentinelCtlPath -ErrorAction SilentlyContinue | Select-Object -First 1

This handles version-specific installation directories like Sentinel Agent 23.4.2.15 without hardcoding version numbers. If multiple versions exist (rare), it selects the first match.

2. Service Status Validation (Get-SentinelService)

Checks the Windows service using standard Get-Service cmdlet:

$service = Get-Service -Name $serviceName -ErrorAction Stop
if ($status -ne 'Running') {
    Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue "SERVICE_STOPPED"
    return $false
}

The service name SentinelAgent is standard across all SentinelOne installations. Non-running states (Stopped, Paused, StartPending) all trigger the SERVICE_STOPPED status.

3. Agent Information Query (Get-SentinelAgentInfo)

Executes sentinelctl.exe status and parses text output using regex:

$agentInfo = & $SentinelCtlPath status 2>&1
 
foreach ($line in $agentInfo) {
    if ($line -match "Agent version:\s*(.+)") {
        $agentData.Version = $matches[1].Trim()
    } elseif ($line -match "Last updated:\s*(.+)") {
        $agentData.LastUpdate = $matches[1].Trim()
    }
    # ... additional parsing
}

The 2>&1 redirection captures both stdout and stderr. Exit code validation ($LASTEXITCODE -ne 0) detects command failures even when partial output is returned.

4. Threat Protection Engine Check (Get-SentinelThreatProtection)

Queries the behavioral AI engine separately from service status:

$protectionInfo = & $SentinelCtlPath engine status 2>&1
 
if ($line -match "Engine state:\s*(.+)") {
    $engineStatus = $matches[1].Trim()
}

This detects scenarios where the service is running but protection is disabled by policy or manual intervention. Regex matching uses (?i)active|enabled|on to handle various console output formats.

5. Console Connectivity Validation (Test-SentinelConsoleConnectivity)

Parses the "Connected to management" field from agent status:

$isConnected = $ConnectionStatus -match "(?i)yes|true|connected|online"

Connectivity issues indicate:

  • Network/firewall blocking SentinelOne management ports (443, 8443)
  • Agent token expired (re-registration required)
  • Management console URL misconfigured
  • Proxy settings preventing HTTPS connections

6. Pending Update Detection (Get-SentinelPendingActions)

Executes sentinelctl.exe check-update to identify available agent updates:

$updateInfo = & $SentinelCtlPath check-update 2>&1
 
foreach ($line in $updateInfo) {
    if ($line -match "(?i)update available|new version") {
        $hasPendingUpdate = $true
    }
}

This check does NOT automatically install updates. It only reports availability for scheduled maintenance windows.

7. Overall Status Determination

The script prioritizes health issues hierarchically:

$overallStatus = "HEALTHY"
if ($consoleStatus -eq "DISCONNECTED") {
    $overallStatus = "DISCONNECTED"  # Critical - no management
} elseif ($protectionStatus -notmatch "(?i)active|enabled|on") {
    $overallStatus = "PROTECTION_DISABLED"  # High - no threat blocking
} elseif ($hasPendingUpdates) {
    $overallStatus = "UPDATE_PENDING"  # Low - functional but outdated
}

Disconnection overrides all other issues because an unmanaged agent cannot receive policy updates or threat intelligence.

8. NinjaRMM Integration (Set-NinjaProperty)

The script gracefully handles missing NinjaRMM integration:

if (Get-Command Ninja-Property-Set -ErrorAction SilentlyContinue) {
    Ninja-Property-Set $PropertyName $PropertyValue
} else {
    Write-Log "NinjaRMM integration not available" -Level 'WARNING'
}

When NinjaRMM cmdlet is unavailable (standalone execution), the script continues and logs locally without failing. This allows the same script to function in both NinjaRMM and non-NinjaRMM environments.

9. Exit Code Strategy

The script uses three exit codes for automation integration:

  • Exit 0: HEALTHY status - all checks passed
  • Exit 1: Critical failures (agent not installed, service missing, query errors)
  • Exit 2: Warning states (disconnected, protection disabled, updates pending)

NinjaRMM and scheduled task monitoring can trigger different alert severities based on exit codes.

Logging and Troubleshooting

All operations log to C:\BIN\LOGS-\<date\>-SentinelOne-Health.log with timestamps and severity levels:

[2025-11-26 14:30:08] [ERROR] Console connectivity: DISCONNECTED

Severity levels:

  • INFO: Normal operational messages
  • SUCCESS: Validation checks passed
  • WARNING: Non-critical issues (NinjaRMM unavailable, pending updates)
  • ERROR: Critical failures requiring intervention

Logs are date-stamped and append throughout the day, allowing historical analysis of agent state changes.

Security Considerations

Credential Handling:

  • Script runs under SYSTEM account when deployed via NinjaRMM or scheduled tasks
  • No hardcoded credentials or API keys
  • Relies on Windows service authentication (SentinelOne agent's embedded token)

Execution Policy:

  • Requires administrator privileges via #Requires -RunAsAdministrator
  • Should be deployed via trusted automation platforms (NinjaRMM, GPO, SCCM)
  • Validate script signature if code signing is enforced: Get-AuthenticodeSignature .\Check-SentinelOne-Health.ps1

Tool Validation:

  • Script validates sentinelctl.exe existence before execution to prevent arbitrary command injection
  • Exit code validation prevents partial failures from appearing successful
  • Error handling ($ErrorActionPreference = 'Stop') ensures exceptions are logged

Integration Points

NinjaRMM Custom Fields:

The script populates five custom fields that can be used for:

  • Dashboard widgets showing SentinelOne fleet health percentages
  • Automated ticketing when status != HEALTHY
  • Patch compliance reporting (agent version inventory)
  • Filtered device views (e.g., all DISCONNECTED agents)

SentinelOne Console:

The script does NOT modify SentinelOne console settings. It is read-only monitoring. Administrative actions (policy changes, agent updates, quarantine) must be performed in the SentinelOne management console.

Scheduled Task / Automation Platform:

Recommended execution frequency:

  • Daily for standard monitoring
  • Hourly for high-security environments requiring real-time visibility
  • On-demand for troubleshooting specific endpoints

Avoid excessive execution (e.g., every 5 minutes) as sentinelctl.exe queries can consume CPU resources.

Known Limitations

1. Multi-Version Installations: If multiple SentinelOne agent versions are installed (non-standard scenario), the script selects the first detected sentinelctl.exe. This may not represent the active agent.

2. Offline/Disconnected Agents: If the endpoint itself is offline, the script cannot execute. NinjaRMM will report "script failed to run" rather than "DISCONNECTED" status.

3. Parse Dependency: The script relies on sentinelctl.exe text output formatting. SentinelOne updates that change output format may break regex parsing. Regular testing after agent updates is recommended.

4. No Automated Remediation: The script reports health issues but does not automatically restart services or re-register agents. This is intentional to prevent unintended service disruptions. Remediation should be reviewed and approved before execution.


SCRIPT CONTENTS

<#
.SYNOPSIS
    Checks SentinelOne agent health status and reports metrics to NinjaRMM.
 
.DESCRIPTION
    SCENARIO:
    Organizations using SentinelOne need automated monitoring of agent health to ensure
    continuous endpoint protection. This script validates service status, console connectivity,
    agent version, threat protection state, and pending actions.
 
    REQUIREMENTS:
    - SentinelOne agent installed (sentinelctl.exe present in Program Files)
    - Local administrator privileges
    - NinjaRMM agent with custom fields configured:
        * s1_agent_status (text)
        * s1_agent_version (text)
        * s1_last_update (text)
        * s1_protection_status (text)
        * s1_console_connectivity (text)
    - C:\BIN\ directory for logging (created automatically if missing)
 
    PROCESS:
    1. Validate sentinelctl.exe presence and service status
    2. Query agent version and last update timestamp
    3. Check management console connectivity
    4. Verify threat protection engine status
    5. Detect pending updates or actions
    6. Report all metrics to NinjaRMM custom fields
    7. Log detailed results with timestamps
 
.NOTES
    Author: CosmicBytez IT Operations
    Version: 1.0
    Requires: PowerShell 5.1+, Administrator privileges
#>
 
#Requires -RunAsAdministrator
 
$ErrorActionPreference = 'Stop'
 
# Configuration
$logDirectory = "C:\BIN"
$logFile = Join-Path $logDirectory "LOGS-$(Get-Date -Format 'yyyy-MM-dd')-SentinelOne-Health.log"
$sentinelCtlPath = "${env:ProgramFiles}\SentinelOne\Sentinel Agent *\SentinelCtl.exe"
$serviceName = "SentinelAgent"
 
# Initialize logging
function Write-Log {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Message,
 
        [Parameter(Mandatory = $false)]
        [ValidateSet('INFO', 'WARNING', 'ERROR', 'SUCCESS')]
        [string]$Level = 'INFO'
    )
 
    $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $logEntry = "[$timestamp] [$Level] $Message"
 
    # Create log directory if it doesn't exist
    if (-not (Test-Path $logDirectory)) {
        New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null
    }
 
    Add-Content -Path $logFile -Value $logEntry
 
    # Console output with color
    $color = switch ($Level) {
        'ERROR'   { 'Red' }
        'WARNING' { 'Yellow' }
        'SUCCESS' { 'Green' }
        default   { 'White' }
    }
    Write-Host $logEntry -ForegroundColor $color
}
 
function Set-NinjaProperty {
    param(
        [Parameter(Mandatory = $true)]
        [string]$PropertyName,
 
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string]$PropertyValue
    )
 
    try {
        if (Get-Command Ninja-Property-Set -ErrorAction SilentlyContinue) {
            Ninja-Property-Set $PropertyName $PropertyValue
            Write-Log "NinjaRMM: Set $PropertyName = $PropertyValue" -Level 'INFO'
        } else {
            Write-Log "NinjaRMM integration not available (Ninja-Property-Set not found)" -Level 'WARNING'
        }
    } catch {
        Write-Log "Failed to set NinjaRMM property ${PropertyName}: $($_.Exception.Message)" -Level 'WARNING'
    }
}
 
function Test-SentinelOneInstalled {
    Write-Log "Checking SentinelOne installation..." -Level 'INFO'
 
    $sentinelCtl = Get-Item $sentinelCtlPath -ErrorAction SilentlyContinue | Select-Object -First 1
 
    if (-not $sentinelCtl) {
        Write-Log "SentinelOne agent not found at expected path" -Level 'ERROR'
        Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue "NOT_INSTALLED"
        return $null
    }
 
    Write-Log "SentinelOne sentinelctl.exe found: $($sentinelCtl.FullName)" -Level 'SUCCESS'
    return $sentinelCtl.FullName
}
 
function Get-SentinelService {
    Write-Log "Checking SentinelOne service status..." -Level 'INFO'
 
    try {
        $service = Get-Service -Name $serviceName -ErrorAction Stop
 
        $status = $service.Status
        Write-Log "Service '$serviceName' status: $status" -Level $(if ($status -eq 'Running') { 'SUCCESS' } else { 'WARNING' })
 
        if ($status -ne 'Running') {
            Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue "SERVICE_STOPPED"
            return $false
        }
 
        return $true
    } catch {
        Write-Log "Service '$serviceName' not found: $($_.Exception.Message)" -Level 'ERROR'
        Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue "SERVICE_NOT_FOUND"
        return $false
    }
}
 
function Get-SentinelAgentInfo {
    param(
        [Parameter(Mandatory = $true)]
        [string]$SentinelCtlPath
    )
 
    Write-Log "Querying SentinelOne agent information..." -Level 'INFO'
 
    try {
        $agentInfo = & $SentinelCtlPath status 2>&1
 
        if ($LASTEXITCODE -ne 0) {
            Write-Log "sentinelctl status command failed with exit code $LASTEXITCODE" -Level 'ERROR'
            return $null
        }
 
        # Parse output
        $agentData = @{
            Version = ""
            LastUpdate = ""
            ConnectionStatus = ""
            ProtectionStatus = ""
            AgentId = ""
        }
 
        foreach ($line in $agentInfo) {
            if ($line -match "Agent version:\s*(.+)") {
                $agentData.Version = $matches[1].Trim()
            } elseif ($line -match "Last updated:\s*(.+)") {
                $agentData.LastUpdate = $matches[1].Trim()
            } elseif ($line -match "Connected to management:\s*(.+)") {
                $agentData.ConnectionStatus = $matches[1].Trim()
            } elseif ($line -match "Protection status:\s*(.+)") {
                $agentData.ProtectionStatus = $matches[1].Trim()
            } elseif ($line -match "Agent ID:\s*(.+)") {
                $agentData.AgentId = $matches[1].Trim()
            }
        }
 
        Write-Log "Agent Version: $($agentData.Version)" -Level 'INFO'
        Write-Log "Last Update: $($agentData.LastUpdate)" -Level 'INFO'
        Write-Log "Console Connectivity: $($agentData.ConnectionStatus)" -Level 'INFO'
        Write-Log "Protection Status: $($agentData.ProtectionStatus)" -Level 'INFO'
 
        return $agentData
    } catch {
        Write-Log "Error querying agent info: $($_.Exception.Message)" -Level 'ERROR'
        return $null
    }
}
 
function Get-SentinelThreatProtection {
    param(
        [Parameter(Mandatory = $true)]
        [string]$SentinelCtlPath
    )
 
    Write-Log "Checking threat protection engine status..." -Level 'INFO'
 
    try {
        $protectionInfo = & $SentinelCtlPath engine status 2>&1
 
        if ($LASTEXITCODE -ne 0) {
            Write-Log "sentinelctl engine status command failed with exit code $LASTEXITCODE" -Level 'WARNING'
            return "UNKNOWN"
        }
 
        $engineStatus = "UNKNOWN"
        foreach ($line in $protectionInfo) {
            if ($line -match "Engine state:\s*(.+)") {
                $engineStatus = $matches[1].Trim()
                break
            } elseif ($line -match "Protection:\s*(.+)") {
                $engineStatus = $matches[1].Trim()
                break
            }
        }
 
        Write-Log "Threat Protection Engine: $engineStatus" -Level $(if ($engineStatus -match "(?i)active|enabled|on") { 'SUCCESS' } else { 'WARNING' })
        return $engineStatus
    } catch {
        Write-Log "Error checking threat protection: $($_.Exception.Message)" -Level 'WARNING'
        return "ERROR"
    }
}
 
function Get-SentinelPendingActions {
    param(
        [Parameter(Mandatory = $true)]
        [string]$SentinelCtlPath
    )
 
    Write-Log "Checking for pending actions or updates..." -Level 'INFO'
 
    try {
        # Check for pending updates
        $updateInfo = & $SentinelCtlPath check-update 2>&1
 
        $hasPendingUpdate = $false
        foreach ($line in $updateInfo) {
            if ($line -match "(?i)update available|new version") {
                $hasPendingUpdate = $true
                Write-Log "Pending update detected: $line" -Level 'WARNING'
            }
        }
 
        if (-not $hasPendingUpdate) {
            Write-Log "No pending updates detected" -Level 'SUCCESS'
        }
 
        return $hasPendingUpdate
    } catch {
        Write-Log "Error checking pending actions: $($_.Exception.Message)" -Level 'WARNING'
        return $false
    }
}
 
function Test-SentinelConsoleConnectivity {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ConnectionStatus
    )
 
    Write-Log "Validating management console connectivity..." -Level 'INFO'
 
    $isConnected = $ConnectionStatus -match "(?i)yes|true|connected|online"
 
    if ($isConnected) {
        Write-Log "Console connectivity: CONNECTED" -Level 'SUCCESS'
        return "CONNECTED"
    } else {
        Write-Log "Console connectivity: DISCONNECTED" -Level 'ERROR'
        return "DISCONNECTED"
    }
}
 
# Main execution
Write-Log "========== SentinelOne Health Check Started ==========" -Level 'INFO'
 
try {
    # Step 1: Check if SentinelOne is installed
    $sentinelCtlExe = Test-SentinelOneInstalled
    if (-not $sentinelCtlExe) {
        Write-Log "SentinelOne agent not installed. Exiting." -Level 'ERROR'
        Set-NinjaProperty -PropertyName "s1_agent_version" -PropertyValue "N/A"
        Set-NinjaProperty -PropertyName "s1_last_update" -PropertyValue "N/A"
        Set-NinjaProperty -PropertyName "s1_protection_status" -PropertyValue "N/A"
        Set-NinjaProperty -PropertyName "s1_console_connectivity" -PropertyValue "N/A"
        exit 1
    }
 
    # Step 2: Check service status
    $serviceRunning = Get-SentinelService
    if (-not $serviceRunning) {
        Write-Log "SentinelOne service not running. Health check incomplete." -Level 'ERROR'
        Set-NinjaProperty -PropertyName "s1_agent_version" -PropertyValue "SERVICE_DOWN"
        Set-NinjaProperty -PropertyName "s1_last_update" -PropertyValue "N/A"
        Set-NinjaProperty -PropertyName "s1_protection_status" -PropertyValue "SERVICE_DOWN"
        Set-NinjaProperty -PropertyName "s1_console_connectivity" -PropertyValue "N/A"
        exit 1
    }
 
    # Step 3: Get agent information
    $agentInfo = Get-SentinelAgentInfo -SentinelCtlPath $sentinelCtlExe
    if (-not $agentInfo) {
        Write-Log "Failed to retrieve agent information" -Level 'ERROR'
        Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue "QUERY_FAILED"
        exit 1
    }
 
    # Step 4: Check threat protection
    $protectionStatus = Get-SentinelThreatProtection -SentinelCtlPath $sentinelCtlExe
 
    # Step 5: Check console connectivity
    $consoleStatus = Test-SentinelConsoleConnectivity -ConnectionStatus $agentInfo.ConnectionStatus
 
    # Step 6: Check for pending actions
    $hasPendingUpdates = Get-SentinelPendingActions -SentinelCtlPath $sentinelCtlExe
 
    # Step 7: Determine overall agent status
    $overallStatus = "HEALTHY"
    if ($consoleStatus -eq "DISCONNECTED") {
        $overallStatus = "DISCONNECTED"
    } elseif ($protectionStatus -notmatch "(?i)active|enabled|on") {
        $overallStatus = "PROTECTION_DISABLED"
    } elseif ($hasPendingUpdates) {
        $overallStatus = "UPDATE_PENDING"
    }
 
    Write-Log "Overall Agent Status: $overallStatus" -Level $(if ($overallStatus -eq "HEALTHY") { 'SUCCESS' } else { 'WARNING' })
 
    # Step 8: Report to NinjaRMM
    Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue $overallStatus
    Set-NinjaProperty -PropertyName "s1_agent_version" -PropertyValue $agentInfo.Version
    Set-NinjaProperty -PropertyName "s1_last_update" -PropertyValue $agentInfo.LastUpdate
    Set-NinjaProperty -PropertyName "s1_protection_status" -PropertyValue $protectionStatus
    Set-NinjaProperty -PropertyName "s1_console_connectivity" -PropertyValue $consoleStatus
 
    Write-Log "========== SentinelOne Health Check Completed ==========" -Level 'SUCCESS'
 
    # Exit with appropriate code
    if ($overallStatus -eq "HEALTHY") {
        exit 0
    } else {
        exit 2  # Warning status
    }
 
} catch {
    Write-Log "Critical error during health check: $($_.Exception.Message)" -Level 'ERROR'
    Write-Log "Stack trace: $($_.ScriptStackTrace)" -Level 'ERROR'
    Set-NinjaProperty -PropertyName "s1_agent_status" -PropertyValue "HEALTH_CHECK_FAILED"
    exit 1
}

Related Reading

  • Deploy SentinelOne Policy
  • SentinelOne Control vs Complete Feature Comparison
  • SentinelOne Deep Visibility Threat Hunting
#sentinelone#edr#Security#threat-hunting#deployment#policy#automation#api#detection-rules#firewall

Related Articles

Deploy SentinelOne Policy

Deploy, manage, and validate SentinelOne security policies across your endpoint estate using the SentinelOne Management API. This automated workflow supports:

25 min read

SentinelOne Control vs Complete Feature Comparison

This document provides a comprehensive comparison between SentinelOne Singularity Control and Singularity Complete SKUs to help MSP teams understand the...

17 min read

SentinelOne Deep Visibility Threat Hunting

Deep Visibility is SentinelOne's EDR telemetry engine that provides comprehensive endpoint data collection for threat hunting, incident investigation, and...

22 min read
Back to all HOWTOs