Agent Deployment
Install and configure the TATER compliance agent on Windows, macOS, and Linux endpoints for automated evidence collection, OS compliance scanning, and speed testing.
The agent makes outbound HTTPS connections to api.tatersecurity.com and www.tatersecurity.com. If your environment uses an SSE/SASE platform (Microsoft Global Secure Access, Zscaler, Netskope, Cisco Umbrella, Palo Alto Prisma) or a corporate proxy with TLS inspection, you almost certainly need to add bypass rules. See Agent Network Requirements for the full domain allowlist and SSE/SASE bypass guide. Most agent-not-reporting cases trace back to TLS inspection breaking the API connection.
If your environment also enforces EDR / AV path or process exclusions, AppLocker / WDAC application allow-listing, or a strict PowerShell execution policy, provide your security team the agent's current SHA-256 hashes (from Settings > Endpoint Agent or the /api/agent/version endpoint), install paths, and service names so they can add the appropriate exclusions.
Agent Overview
The TATER Agent is a lightweight, cross-platform Go binary that runs as a system service on Windows, macOS, and Linux endpoints. It collects compliance data, runs security benchmark checks, and uploads results to the TATER API. Key features:
- Windows: CIS benchmark scanning (registry, services, firewall, audit policy) via PowerShell controls
- macOS: 55 security controls (FileVault, Firewall, Gatekeeper/SIP, auto-updates, screen lock, sharing, login window, sudo hardening, APFS encryption, and more) via bash scripts
- Linux: 60 security controls (firewall, SSH hardening, disk encryption, SELinux/AppArmor, auditd, kernel hardening, and more) via bash scripts
- Network speed testing using self-hosted test files
- Automatic result upload to the TATER API
- Auto-update with SHA-256 hash verification
- System tray application for status monitoring (Windows and macOS)
- Local compliance dashboard (opens in browser)
| Platform | Binary | Service | Tray | Controls |
|---|---|---|---|---|
| Windows (x64) | tater-agent.exe | Windows SCM | Yes | PowerShell (.ps1) |
| macOS (Apple Silicon) | tater-agent-darwin-arm64 | launchd | Yes | Bash (.sh) |
| macOS (Intel) | tater-agent-darwin-amd64 | launchd | Yes | Bash (.sh) |
| Linux (x64) | tater-agent-linux-amd64 | systemd | No (headless) | Bash (.sh) |
| Linux (ARM64) | tater-agent-linux-arm64 | systemd | No (headless) | Bash (.sh) |
MSI Installation
Interactive Installation
Download the MSI
Download TATER-Agent.msi from the TATER Settings → Endpoint Agent page, or from https://www.tatersecurity.com/Agent/TATER-Agent.msi.
Run the installer
Double-click the MSI file. The installation wizard will prompt for the TATER API base URL, API key, and Organization ID.
Enter configuration
Provide the API base URL (e.g., https://api.tatersecurity.com/api), your API key, and your organization ID. The installer auto-appends /api if not present.
Complete installation
Click Install. The agent service starts automatically and the tray application launches.
Silent Installation
For unattended deployments, use msiexec with the /qn flag:
# Basic silent install
msiexec /i TATER-Agent.msi /qn APIBASE="https://api.tatersecurity.com/api" APIKEY="your-key" TENANTID="your-tenant" ORGANIZATIONID="your-org"
# With logging for troubleshooting
msiexec /i TATER-Agent.msi /qn APIBASE="https://api.tatersecurity.com/api" APIKEY="your-key" TENANTID="your-tenant" ORGANIZATIONID="your-org" /l*v "%TEMP%\tater-install.log"
# Uninstall silently
msiexec /x TATER-Agent.msi /qn
MSI Properties
MSI properties use uppercase KEY=value syntax on the msiexec command line. The installer writes these to config.json during installation (see Configuration File Reference below).
| Property | Required | config.json Key | Description |
|---|---|---|---|
APIBASE | Yes | apiBase | TATER API base URL. The MSI auto-appends /api if missing. |
APIKEY | Yes | apiKey | API key for authenticating scan uploads. Generate from Manage → Connections → API Keys. |
TENANTID | Yes | tenantId | Your Azure AD tenant ID (GUID). |
ORGANIZATIONID | Yes | organizationId | Organization ID (format: org-xxxxxxxx). Found on Settings → Endpoint Agent. |
APPID | No | appId | App registration client ID for app-only cloud scan authentication. |
CERTTHUMBPRINT | No | certificateThumbprint | Certificate thumbprint for app-only authentication. Note: the config.json key is certificateThumbprint - not certThumbprint. |
M365ORG | No | organization | Your Microsoft 365 tenant domain (e.g. contoso.onmicrosoft.com). Note: the config.json key is organization - not m365Org. |
SCHEDULEFREQUENCY | No | (schedule object) | Scan schedule frequency: Daily (default), Weekly, or Hourly. |
SCHEDULEHOUR | No | (schedule object) | Hour of day to run (0–23, default 3). Only used when SCHEDULEFREQUENCY is Daily or Weekly. |
The MSI installer uses uppercase KEY=value Windows Installer property syntax, while the Go agent binary reads directly from config.json. These use different key names in several cases:
CERTTHUMBPRINT(MSI) →certificateThumbprint(config.json) - completely different casing and nameM365ORG(MSI) →organization(config.json) - completely different nameORGANIZATIONID(MSI) →organizationId(config.json) - case change only
When writing a config.json directly (macOS, Linux, or custom Windows deploy), always use the camelCase config.json key names, not the MSI property names.
Installation Paths (Windows MSI)
The TATER MSI creates files in two separate directories:
| Path | Contents | Notes |
|---|---|---|
C:\ProgramData\TATER\ | Agent binary (tater-agent.exe) + config, logs, controls | Hardcoded via CommonAppDataFolder\TATER in Directories.wxs. The MSI does NOT install to Program Files. |
C:\ProgramData\TATER\ | All runtime data | Always this path - not affected by install directory selection. |
C:\ProgramData\TATER\config.json | Agent configuration | Written by MSI from installer properties. Edit to reconfigure without reinstalling. |
C:\ProgramData\TATER\Logs\ | Agent log files | Rotated automatically; last 10 logs retained. |
C:\ProgramData\TATER\Controls\ | PowerShell control scripts | Downloaded from TATER at runtime for compliance checks. |
C:\ProgramData\TATER\Scans\ | Local scan result cache | Last 10 scan results retained. |
Windows Service: The MSI installs a Windows service named TATERAgent. Detection scripts should query this service directly:
Get-Service -Name "TATERAgent" -ErrorAction SilentlyContinue
Configuration File Reference
The agent reads configuration from config.json at startup. On Windows the MSI writes this file; on macOS and Linux your install script must write it directly.
{
"apiBase": "https://api.tatersecurity.com/api",
"apiKey": "tater_xxxxxxxxxxxx",
"tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"organizationId": "org-xxxxxxxxxxxxxxxx",
// Optional: app-only authentication for cloud scanning
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"certificateThumbprint": "AABBCC...",
"organization": "contoso.onmicrosoft.com",
// Optional: agent behavior
"products": "All",
"scanIntervalHours": 24,
"controlsPath": "C:\\ProgramData\\TATER\\Controls"
}
| Key | Type | Description |
|---|---|---|
apiBase | string | TATER API base URL. Must end in /api. |
apiKey | string | API key for scan upload authentication. |
tenantId | string | Azure AD tenant ID (GUID). |
organizationId | string | TATER Organization ID (format: org-xxxxxxxx). |
appId | string | App registration client ID for app-only cloud authentication. |
certificateThumbprint | string | Certificate thumbprint (hex, uppercase). Used with appId for app-only auth. |
organization | string | Microsoft 365 tenant domain (e.g. contoso.onmicrosoft.com). |
products | string | Compliance products to scan. Default: All. Options: All, AllCloud, AllEndpoint. |
scanIntervalHours | integer | Hours between automated scans. Default: 24. |
controlsPath | string | Directory containing control scripts. Windows default: %ProgramData%\TATER\Controls. |
logPath | string | Directory for agent log files. Windows default: %ProgramData%\TATER\Logs. |
interScriptDelayMs | integer | Optional EDR throttle (v2.4.20+). Fixed delay between control-script spawns, in ms. Default 0 (no throttle). See "EDR-sensitive endpoints" callout below. |
interScriptJitterMs | integer | Optional EDR throttle (v2.4.20+). Additional randomized delay added to each spawn pause (0 to interScriptJitterMs, in ms). Default 0. See "EDR-sensitive endpoints" callout below. |
The agent spawns one powershell.exe per control script. On endpoints with aggressive EDR behavioral monitoring (SentinelOne, CrowdStrike, Defender for Endpoint in HIPS mode), the sustained spawn cadence can amplify anti-tamper telemetry (Event 143 storms from Service Performance subkey touches at PS startup) and trip behavioral heuristics. ADO #560.
Recommended throttle for those endpoints (add to config.json):
"interScriptDelayMs": 250,
"interScriptJitterMs": 1250Each control pair now waits 250–1500ms before the next spawn. For a ~1300-control fleet this adds roughly 5–27 minutes per scan vs. unthrottled, with the per-spawn anti-tamper events no longer arriving as a tight burst. The effective values are echoed once at scan start in the agent log when either knob is > 0.
The TATER Agent supports Windows 10/11 or Windows Server 2019+, macOS 12+ (Apple Silicon or Intel), and Linux (amd64 or arm64, systemd required). The agent service runs as SYSTEM (Windows) or root (Linux/macOS) and requires local administrator privileges for compliance checks (registry, services, firewall, audit policy).
Intune Deployment (Windows)
Two deployment methods are supported via Intune, plus traditional Group Policy / SCCM. Pick based on the host type and what you need from ongoing health monitoring:
| Method | Best for | Initial install | Auto-upgrade | Self-heals drift | AVD multi-session |
|---|---|---|---|---|---|
| Win32 App (recommended) | Standard workstations - the most reliable rollout path in field-tested deployments | Yes (msiexec) | Yes (Intune supersedence + agent auto-update) | Limited (re-install on detection-rule miss) | No (unsupported by Microsoft) |
| Proactive Remediation | AVD multi-session hosts + ongoing health monitoring layer on top of Win32 deployment | Yes (fallback when Win32 unsupported) | Yes (Remediate's Phase 3b binary swap) | Yes (re-runs on schedule, catches dead apiBase / stale versions / broken state) | Yes |
| Group Policy / SCCM | On-prem AD environments without Intune | Yes | No | No | N/A |
For standard Windows workstations, deploy via Win32 App - it's the most reliable initial-install path in real-world Caron Bletzer rollouts. Optionally layer Proactive Remediation on top (using the Detect-TATERAgent.ps1 + Remediate-TATERAgent.ps1 scripts) to catch post-deployment drift (stale binary, broken config, decommissioned apiBase URL, service stopped, etc).
For AVD / Windows Server multi-session hosts where Win32 App is unsupported, use Proactive Remediation as the primary install path - the Remediate script handles full installation in addition to ongoing health monitoring.
Win32 App (Recommended)
The Win32 App method packages the MSI as an Intune-deployable bundle (.intunewin). It's the most reliable initial-deployment path for standard Windows workstations - field-tested across the CB fleet as significantly more dependable than Proactive Remediation for first-install rollouts.
1. Get the .intunewin package
Two options:
Option A: Download the pre-built package (recommended - saves you from installing the Win32 Content Prep Tool):
iwr https://www.tatersecurity.com/Agent/TATER-Agent.intunewin -UseBasicParsing -OutFile TATER-Agent.intunewinThe package is rebuilt and published to the SWA on every TATER release - it always wraps the current MSI from Installer\bin\Release\TATER-Agent.msi.
Option B: Build locally (only needed if you want to customize the MSI or use a non-current version):
# From the TATER repo root
cd Installer
.\Build-IntuneWin.ps1
# Output: Installer\bin\IntuneWin\TATER-Agent.intunewinThe build script auto-downloads IntuneWinAppUtil.exe on first run (no manual install of the Win32 Content Prep Tool needed).
The SWA's incremental sync occasionally leaves /Agent/* URLs returning 404 (~6 KB of HTML) for 5-15 minutes after a TATER release deploy. If you happen to download during that window, iwr -OutFile writes the 6 KB HTML page to your destination file with a .intunewin extension - Intune then rejects it with a confusing "package format" error. Always verify the SHA256 before uploading:
(Get-FileHash TATER-Agent.intunewin -Algorithm SHA256).Hash
# Should match the current published SHA at:
# https://api.tatersecurity.com/api/agent/version (msiSha256 field is the MSI; the .intunewin wraps it)
# If you get something completely different (or a tiny ~6 KB file), the SWA
# was mid-sync - wait 5-10 min and re-download, or pull from the source
# of truth at:
# https://github.com/.../TATER/raw/main/Agent/TATER-Agent.intunewin
# (or your local clone at C:\path\to\TATER\Agent\TATER-Agent.intunewin)Quick file-size sanity check: the .intunewin is ~5.5 MB. If your downloaded file is <100 KB, it's the 404 HTML page - do not upload it.
2. Add the Win32 app in Intune
- Open Microsoft Intune admin center → Apps → All apps → Add
- App type: Windows app (Win32)
- Select app package file: upload
TATER-Agent.intunewin - App information page - suggested values:
- Name: TATER Compliance Agent
- Description: Continuous compliance scanning, vulnerability inventory, and remote operations agent for TATER Security.
- Publisher: TATER Security
- Logo:
TATER.pngfrom the repo (or skip) - Category: Computer management
3. Install and uninstall commands
Install command - replace the placeholders with your actual values from TATER Manage → Connections → API Keys (key) and the org's properties (tenant + org IDs):
msiexec /i TATER-Agent.msi /qn APIBASE="https://api.tatersecurity.com/api" APIKEY="<your-api-key>" TENANTID="<your-tenant-id>" ORGANIZATIONID="<your-org-id>"Uninstall command:
msiexec /x TATER-Agent.msi /qnInstall behavior: System. Device restart behavior: No specific action (the agent installs as a Windows service and starts immediately - no reboot needed).
4. Requirements
- Operating system architecture: x64
- Minimum operating system: Windows 10 1903 (any supported Windows 10/11/Server 2019+ build works)
5. Detection rule
Use a File rule rather than MSI product code so future agent updates (which happen via in-place binary swap, NOT MSI repair) don't break detection:
- Rules format: Manually configure detection rules
- Rule type: File
- Path:
C:\ProgramData\TATER - File or folder:
tater-agent.exe - Detection method: File or folder exists
- Associated with a 32-bit app on 64-bit clients: No
Why C:\ProgramData\TATER and not C:\Program Files\TATER? The WiX installer roots [TATERDIR] at CommonAppDataFolder\TATER (= %ProgramData%\TATER) so the binary, config, logs, and controls all sit together at a path that Windows services can read and write without elevation gymnastics (see Installer/Directories.wxs line 8). The MSI never places the binary under Program Files. Pointing the Intune detection rule at C:\Program Files\TATER\tater-agent.exe - what older guidance suggested - means Intune sees "file missing" after every successful install and reports the deployment as failed forever, even though the agent is running normally.
(MSI product-code detection works for the very first install but breaks after the agent auto-updates - see ADO #568 for why - so the file-existence rule is more reliable long-term.)
6. Assign and deploy
- Assignments tab: assign to the target Entra ID group containing the devices that should run the agent (typically the org's Windows-workstation group).
- Recommended assignment type: Required (so Intune installs automatically on next sync) rather than Available (user-initiated).
- Review + create.
Devices receive the install on their next Intune sync (typically every 8 hours, or trigger manually via Settings > Accounts > Access work or school > Sync). Install logs land in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log.
7. Post-install verification (one-liner)
On any newly-deployed device, the field-tested verification script confirms the agent is correctly installed, configured, and reachable. Run from an elevated PowerShell:
Remove-Item $env:TEMP\Verify.ps1 -Force -ErrorAction SilentlyContinue
iwr https://www.tatersecurity.com/Agent/Verify-TATERAgent.ps1 -UseBasicParsing -OutFile $env:TEMP\Verify.ps1
powershell.exe -ExecutionPolicy Bypass -File $env:TEMP\Verify.ps1Add -Fix at the end to auto-heal anything that's wrong (rewrite dead apiBase, force-upgrade stale binary, restart stopped service, kill orphan tray instances). See Verify-TATERAgent.ps1 reference.
Expected healthy report:
[ OK ] Installed version - v2.4.13[ OK ] config: apiBase - https://api.tatersecurity.com/api[ OK ] Service is Running[ OK ] Canonical API reachable- Final line:
All checks passed. TATER agent is healthy.
Most field machines are on Windows PowerShell 5.1, not PowerShell 7. The above one-liner is written for 5.1 compatibility:
-UseBasicParsingonInvoke-WebRequestis REQUIRED. Without it, WinPS 5.1 tries the Internet Explorer engine and fails with "Operation cancelled due to security concerns".- Use
powershell.exe -ExecutionPolicy Bypass -File ...(NOTpwsh.exe- most Windows machines don't have PS 7 installed). - An inline
iex (iwr ...).Contentform ALSO works on WinPS 5.1 today because the SWA serves.ps1withContent-Type: text/plain. If it ever returns garbled byte-array errors, fall back to the-OutFilepath above which works universally.
8. Ongoing upgrades
Two paths handle subsequent version upgrades:
- Agent auto-update (preferred): v2.4.9+ checks
/api/agent/versiondaily, downloads the new binary, SHA-256 verifies, and replaces in place. Works without Intune intervention. Agents pre-v2.4.6 have a broken auto-update endpoint (see ADO #569) - for those, use theVerify-TATERAgent.ps1 -Fixone-liner OR add the Proactive Remediation health-monitoring layer to force-upgrade them on the next sync. - Intune supersedence: when the MSI version itself changes (rare - we only rev the MSI for installer-side changes), supersede the previous Win32 App with the new
.intunewin. Intune handles the uninstall-then-install on managed devices.
9. Layer Proactive Remediation for ongoing health monitoring (optional but recommended)
Win32 App handles the install. Proactive Remediation handles drift - stale binaries, broken configs, decommissioned apiBase URLs, stopped services. Set up both for a complete deployment lifecycle. The Proactive Remediation section below describes the scripts in detail.
Proactive Remediation (AVD primary install + health monitoring layer)
Proactive Remediation serves two distinct roles depending on host type:
- Primary install for AVD multi-session hosts - Win32 App deployment is unsupported on Windows Server multi-session OS (Microsoft limitation). For AVD pools, use Proactive Remediation as the install path. The Remediate script handles full installation when the service is missing.
- Ongoing health-monitoring layer on top of Win32 App deployment - After Win32 App installs the agent, Proactive Remediation re-runs on a schedule (every 24h by default) to detect drift: stale binary version, broken config, decommissioned
apiBase, stopped service, etc. When drift is detected, the Remediate script auto-heals via the same field-verified binary swap pattern used byVerify-TATERAgent.ps1 -Fix.
Whichever role you use it for, the scripts run in SYSTEM context with the same plumbing.
If you have older Intune scripts that check for %ProgramData%\TATER\TATER-Agent.ps1 or a scheduled task running PowerShell, those are v1.3.4 (legacy PS agent) patterns. The current v2.x agent is a Go binary (tater-agent.exe) running as a Windows service named TATERAgent. Detection scripts looking for the PS1 file or scheduled task will never find them after a successful install - producing an infinite remediation loop where Intune flags every device as Non-compliant despite the agent working correctly. Use the v2.x scripts below.
The latest hardened versions of these scripts live as standalone files in Intune/ in the TATER repo:
Intune/Detect-TATERAgent.ps1- v2026.05.25 hardened: placeholder API key detection, writes per-rundetect-status.jsonfor forensic collection, BOM-tolerant config parsingIntune/Remediate-TATERAgent.ps1- v2026.05.25 hardened: rejects placeholder values up front, verifiesapi.tatersecurity.comreachability before install, force-reinstalls when service exists but config is invalid (broken-state recovery), writesinstall-status.jsonon every run, posts a best-effort install beacon to/agent/diagnosticsso silent-fleet devices still show up in TATER's Activity Log withvia=agent-installerIntune/Collect-TATERStatus.ps1- one-shot forensic helper to run via Endpoint Central / RDP on any deployed-but-silent device; emits a single JSON blob with service state, binary version + SHA, config (API key redacted), all sentinels, log tail, MSI install log, network reachability. Paste output into the TATER analyst session for triage.
The inline scripts below are kept for copy-paste convenience but lag the repo. Always prefer the standalone files for production rollouts.
Agent v2.4.11+ writes a periodic heartbeat to /api/agent/diagnostics every 30 minutes via a background goroutine (60 s after startup so the initial scan + auto-update can flow first). Before v2.4.11, diagnostics were only written on explicit operator action - so a healthy, scanning, uploading agent could still show Offline on the Devices page once its install-time diagnostic aged past the 90-minute Online window. With v2.4.11, the page receives 3 heartbeats per cycle and stays accurate without intervention. The heartbeat is wired into both service mode and interactive/tray mode (idempotent - Cosmos upsert by deviceName means concurrent processes are safe).
This complements the four health signals in the detection script: the heartbeat ensures the API-side view of the device matches reality, while the detection script ensures the agent process itself is healthy on the host.
Companion fix (2026-05-29): the fleet-list endpoint (GET /api/agent/diagnostics) previously capped its lookup at the 50 most recent reports across the org. With every device emitting 48 heartbeats per day, that window only covered the chattiest ~10–15 devices - so fleets larger than ~20 endpoints silently dropped devices from the Devices / Fleet list. The default is now 1000 reports (configurable via ?limit=N, 1–5000) with a _meta.truncated sentinel for very large estates. See the FAQ entry for diagnostic curl recipe.
Create two PowerShell scripts. The detection script below covers four health signals: service installed, service running, config valid, and recent agent output (so a stuck service that never produces logs gets re-remediated):
Detect-TATERAgent.ps1 - returns exit code 1 (non-compliant) if any health signal fails:
# Detect-TATERAgent.ps1 - Intune Proactive Remediation Detection (Go agent v2.x)
$TATERDir = Join-Path $env:ProgramData 'TATER'
$ConfigPath = Join-Path $TATERDir 'config.json'
$LogDir = Join-Path $TATERDir 'Logs'
$ScansDir = Join-Path $TATERDir 'Scans'
$MaxAgeHours = 48
$issues = @()
# 1 - Windows service installed and running
$svc = Get-Service -Name 'TATERAgent' -ErrorAction SilentlyContinue
if (-not $svc) {
$issues += "TATERAgent Windows service not installed"
} elseif ($svc.Status -ne 'Running') {
$issues += "TATERAgent service is $($svc.Status), expected Running"
} elseif ($svc.StartType -eq 'Disabled') {
$issues += "TATERAgent service start type is Disabled"
}
# 2 - config.json present with required keys
if (-not (Test-Path $ConfigPath)) {
$issues += "config.json not found at $ConfigPath"
} else {
try {
$cfg = Get-Content $ConfigPath -Raw | ConvertFrom-Json
foreach ($key in @('apiBase', 'tenantId', 'organizationId')) {
if (-not $cfg.$key) { $issues += "config.json missing required key: $key" }
}
if (-not $cfg.apiKey -and -not $cfg.encryptedApiKey) {
$issues += "config.json missing apiKey or encryptedApiKey"
}
} catch {
$issues += "config.json is not valid JSON: $_"
}
}
# 3 - Recent log or scan evidence (only if service is otherwise healthy)
if ($svc -and $svc.Status -eq 'Running' -and (Test-Path $ConfigPath)) {
$lastEvidence = $null
if (Test-Path $LogDir) {
$latest = Get-ChildItem -Path $LogDir -Filter 'TATER-Agent_*.log' -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($latest) { $lastEvidence = $latest.LastWriteTime }
}
if (Test-Path $ScansDir) {
$latest = Get-ChildItem -Path $ScansDir -Filter '*.json' -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($latest -and (-not $lastEvidence -or $latest.LastWriteTime -gt $lastEvidence)) {
$lastEvidence = $latest.LastWriteTime
}
}
if (-not $lastEvidence) {
$issues += "No agent log or scan files found - service running but agent has not produced output yet"
} else {
$ageHours = ((Get-Date) - $lastEvidence).TotalHours
if ($ageHours -gt $MaxAgeHours) {
$issues += "Agent last produced output $([math]::Round($ageHours,1))h ago (threshold: ${MaxAgeHours}h)"
}
}
}
# 4 - Last-upload sentinel (ADO #535) - catches silent upload failures
# Agent v2.4.0+ writes C:\ProgramData\TATER\last-upload.json after every
# successful POST. If the file exists, treat its timestamp as authoritative
# (it confirms server-side acceptance, not just local activity).
$SentinelPath = Join-Path $TATERDir 'last-upload.json'
if (Test-Path $SentinelPath) {
try {
$sentinel = Get-Content $SentinelPath -Raw | ConvertFrom-Json
$lastUpload = [DateTime]::Parse($sentinel.timestamp)
$uploadAge = ((Get-Date).ToUniversalTime() - $lastUpload).TotalHours
if ($uploadAge -gt $MaxAgeHours) {
$issues += "Last successful upload was $([math]::Round($uploadAge,1))h ago (threshold: ${MaxAgeHours}h). Agent is scanning locally but cannot reach the TATER API."
}
} catch {
$issues += "last-upload.json is malformed: $_"
}
} elseif ($svc -and $svc.Status -eq 'Running') {
# Sentinel absent on a running v2.4.0+ agent means uploads have never
# succeeded since install. Pre-2.4.0 agents won't write the file, so we
# only flag this for agents that we've explicitly confirmed are 2.4.0+.
$exePath = Join-Path $env:ProgramFiles 'TATER\tater-agent.exe'
if (Test-Path $exePath) {
$verInfo = (Get-Item $exePath).VersionInfo
if ($verInfo.ProductVersion -and $verInfo.ProductVersion -ge '2.4.0') {
$issues += "Agent v$($verInfo.ProductVersion) has never produced a successful upload (no last-upload.json sentinel). Likely API auth failure - see Manage > Activity Log for via=agent entries."
}
}
}
if ($issues.Count -gt 0) {
Write-Output "NON-COMPLIANT: $($issues -join ' | ')"
exit 1
}
Write-Output "COMPLIANT: TATERAgent service running, config valid, evidence within ${MaxAgeHours}h"
exit 0
Remediate-TATERAgent.ps1 - installs the MSI, writes config.json directly (overwrites any defaults the MSI dropped), restarts the service, and triggers a one-shot scan:
# Remediate-TATERAgent.ps1 - Intune Proactive Remediation (Go agent v2.x)
# Edit these values before deploying
$Config = @{
apiBase = "https://api.tatersecurity.com/api"
apiKey = "your-api-key"
tenantId = "your-azure-tenant-id"
organizationId = "your-org-id"
products = "All"
appId = "your-cloud-scan-app-id" # optional, for cloud scans
certificateThumbprint = "your-cloud-scan-cert-thumbprint" # optional, for cloud scans
organization = "your-tenant.onmicrosoft.com" # optional, for cloud scans
tenantEnvironment = "commercial" # commercial | usGovGcc | usGovGccHigh | usGovDoD
}
$TATERDir = Join-Path $env:ProgramData 'TATER'
$ConfigPath = Join-Path $TATERDir 'config.json'
$LogDir = Join-Path $TATERDir 'Logs'
$MSI_URL = "https://www.tatersecurity.com/Agent/TATER-Agent.msi"
$TempDir = "C:\Windows\Temp\TATERInstall"
$MSIPath = Join-Path $TempDir 'TATER-Agent.msi'
function Write-Log { param([string]$m) Write-Output "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $m" }
try {
# 1. Install MSI if service is missing
$svc = Get-Service -Name 'TATERAgent' -ErrorAction SilentlyContinue
if (-not $svc) {
Write-Log "TATERAgent service not installed - downloading and installing MSI..."
if (-not (Test-Path $TempDir)) { New-Item -ItemType Directory -Path $TempDir -Force | Out-Null }
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $MSI_URL -OutFile $MSIPath -UseBasicParsing -ErrorAction Stop
# Pass required MSI properties - the MSI's GenerateConfig custom action will
# fail the install if APIBASE / APIKEY / TENANTID / ORGANIZATIONID are missing.
# We still rewrite config.json from $Config in step 3 below, but the MSI itself
# must succeed first or the service is never installed. Start-Process accepts
# an array of arguments and quotes each one automatically - no need for
# PowerShell backtick-escape soup.
$logPath = Join-Path $TempDir 'tater-install.log'
$msiArgs = @(
'/i', $MSIPath,
'/qn',
'/l*v', $logPath,
"APIBASE=$($Config.apiBase)",
"APIKEY=$($Config.apiKey)",
"TENANTID=$($Config.tenantId)",
"ORGANIZATIONID=$($Config.organizationId)"
)
$proc = Start-Process -FilePath 'msiexec.exe' -ArgumentList $msiArgs -Wait -PassThru
if ($proc.ExitCode -ne 0 -and $proc.ExitCode -ne 3010) {
throw "MSI install failed with exit code $($proc.ExitCode) - see $TempDir\tater-install.log"
}
Write-Log "MSI installed (exit code: $($proc.ExitCode))"
} else {
Write-Log "TATERAgent service already installed (status: $($svc.Status))"
}
# 2. Ensure data dir exists
foreach ($dir in @($TATERDir, $LogDir)) {
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
}
# 3. Write config.json (no BOM - Go agent strips BOMs but writing clean is safer)
Write-Log "Writing config.json..."
$json = $Config | ConvertTo-Json -Depth 3
[System.IO.File]::WriteAllText($ConfigPath, $json, [System.Text.UTF8Encoding]::new($false))
Write-Log "config.json written"
# 4. Auto-start + (re)start the service so it picks up the new config
Set-Service -Name 'TATERAgent' -StartupType Automatic -ErrorAction Stop
$svc = Get-Service -Name 'TATERAgent'
if ($svc.Status -eq 'Running') {
Write-Log "Restarting TATERAgent..."
Restart-Service -Name 'TATERAgent' -Force -ErrorAction Stop
} else {
Write-Log "Starting TATERAgent..."
Start-Service -Name 'TATERAgent' -ErrorAction Stop
}
# 5. Do NOT spawn a one-shot scan here (ADO #557)
# Earlier versions ran `Start-Process tater-agent.exe -scan` to seed
# fresh evidence. The Proactive Remediation script runs in the calling
# user's context (often a local admin like JesseMilesAdmin), while the
# Windows service starts in SYSTEM context. The two processes then ran
# in PARALLEL - two tater-agent.exe instances, different identities,
# competing for the same %ProgramData%\TATER files. Confirmed on
# X1-01-2025-08 and X1-09-2025-08 in May 2026 (CB tenant).
# The freshly-started service performs an initial scan within its
# first poll interval (default 60s), which the detection script
# picks up on the next Intune sync (default 8h). If you need faster
# feedback for testing, RDP into the device and run:
# sc.exe stop TATERAgent
# sc.exe start TATERAgent
# or remotely via TATER Manage → Devices → Run command.
Write-Log "SUCCESS: TATERAgent remediated"
exit 0
} catch {
Write-Log "ERROR: $($_.Exception.Message)"
exit 1
} finally {
Remove-Item -Path $MSIPath -Force -ErrorAction SilentlyContinue
}
1. Create the Proactive Remediation
In Intune admin center, go to Devices > Scripts and remediations > Create. Name it "TATER Agent Deployment".
2. Upload scripts
Upload Detect-TATERAgent.ps1 as the detection script and Remediate-TATERAgent.ps1 as the remediation script. Set Run script in 64-bit PowerShell to Yes.
3. Configure schedule
Set Run frequency to Every 1 hour (ensures self-healing). Set Run this script using the logged-on credentials to No (runs as SYSTEM).
4. Assign to groups
Assign to All Windows Devices or a specific device group. For AVD session hosts, use the host pool device group.
Proactive Remediation requires Microsoft Intune Plan 1 (included in Microsoft 365 E3/E5, Business Premium, or as a standalone add-on). It is available under Endpoint Analytics in the Intune admin center.
Group Policy / SCCM Deployment
For Group Policy or SCCM deployment, create a deployment package with the MSI and a transform (.mst) file or use command-line properties:
# Group Policy software installation
# Place the MSI on a network share accessible by target machines
# Create a GPO with Software Installation pointing to:
\\fileserver\share\TATER-Agent.msi
# For SCCM, create a package with the following program command line:
msiexec /i TATER-Agent.msi /qn APIBASE="https://api.tatersecurity.com/api" APIKEY="your-key" TENANTID="your-tenant" ORGANIZATIONID="your-org"
macOS Deployment
Platform Scripts (Recommended)
The recommended way to deploy the TATER Agent on macOS via Intune is Platform Scripts (formerly Shell Scripts). A single idempotent script installs the agent, writes the config file, registers the launchd daemon, and starts the service. The script is safe to run multiple times - it skips steps that are already complete.
The Go agent reads configuration only from /Library/Application Support/TATER/config.json. It does not accept --apiBase, --apiKey, --tenantId, or other config flags - those are silently ignored. If your LaunchDaemon's ProgramArguments array passes 16 string flags to tater-agent, the agent starts with empty config, fails the cfg.ApiBase == "" validation check, and exits. launchctl load still reports success, so the install script appears to succeed, but the agent never actually scans. Also ensure RunAtLoad is true - otherwise the agent only fires at the 3 AM scheduled interval. Use the script below, which writes a proper config.json and invokes tater-agent with no flags.
The TATER macOS agent binary is currently not signed or notarized with an Apple Developer ID. Files downloaded via curl automatically receive the com.apple.quarantine extended attribute, which causes macOS Gatekeeper to silently block execution - even when launched by launchd running as root. launchctl load reports success, but the process never starts, so the agent appears installed but never produces logs, scans, or API posts. The binary is also unlaunchable from Finder/Terminal until the xattr is removed. The script below now runs xattr -d com.apple.quarantine after each download. If you've already deployed an earlier version of this script and your devices show installed-but-not-reporting, run sudo xattr -c /usr/local/bin/tater-agent && sudo launchctl kickstart -k system/com.tatersecurity.agent to clear the attribute and restart.
tater_agent_install.sh - create this script and deploy it via Intune:
#!/bin/bash
# tater_agent_install.sh - TATER Agent idempotent installer for Intune Platform Scripts
# Deploy via: Devices > Scripts > macOS > Add
# ── Configure these four values ────────────────────────────────────────────
API_BASE="https://api.tatersecurity.com/api"
API_KEY="your-api-key"
TENANT_ID="your-azure-tenant-id"
ORG_ID="your-org-id"
# ───────────────────────────────────────────────────────────────────────────
set -euo pipefail
ARCH=$(uname -m)
if [[ "$ARCH" == "arm64" ]]; then
BINARY_URL="https://www.tatersecurity.com/Agent/tater-agent-darwin-arm64"
else
BINARY_URL="https://www.tatersecurity.com/Agent/tater-agent-darwin-amd64"
fi
INSTALL_DIR="/usr/local/bin"
DATA_DIR="/Library/Application Support/TATER"
PLIST_PATH="/Library/LaunchDaemons/com.tatersecurity.agent.plist"
BINARY_PATH="$INSTALL_DIR/tater-agent"
# Download binary if not already installed or if outdated
if [[ ! -f "$BINARY_PATH" ]]; then
curl -fsSL "$BINARY_URL" -o "$BINARY_PATH"
chmod 755 "$BINARY_PATH"
chown root:wheel "$BINARY_PATH"
# CRITICAL: strip the com.apple.quarantine xattr that curl applies to downloads.
# Without this, macOS Gatekeeper silently blocks the unsigned binary from running
# - launchctl load reports success but the process never actually starts.
xattr -d com.apple.quarantine "$BINARY_PATH" 2>/dev/null || true
xattr -c "$BINARY_PATH" 2>/dev/null || true
fi
# Create data directory
mkdir -p "$DATA_DIR/Logs"
mkdir -p "$DATA_DIR/Controls/macOS"
# ADO #566 - Provision macOS control scripts. The agent's runner_darwin.go
# discovers .sh scripts under {controlsPath}/macOS/ at scan time. Without
# these files the agent runs an empty scan and the API returns 400. We
# fetch them from the marketing SWA on every install - idempotent and
# tolerates re-runs (curl overwrites).
CTRL_BASE="https://www.tatersecurity.com/Controls/macOS"
for n in 001_FileVault 002_Firewall 003_GatekeeperSIP 004_AutoUpdates 005_ScreenLock \
006_RemoteLogin 007_Sharing 008_PasswordPolicy 009_TimeMachine 010_GuestAccount \
011_AirDrop 012_XProtect 013_NTP 014_Bluetooth 015_SecureBoot \
016_SoftwareUpdates 017_RemoteManagement 018_LoginWindow 019_Audit 020_NetworkSecurity \
021_SafariSafeDownloads 022_TerminalSecureEntry 023_ScreenSaverPassword 024_FirewallStealthMode 025_FirewallLogging \
026_RemoteAppleEvents 027_InternetSharing 028_MediaSharing 029_PrinterSharing 030_NFSExports \
031_WakeForNetwork 032_PowerNapDisabled 033_FindMyMac 034_iCloudDriveDocSync 035_DiagnosticsSubmission \
036_SiriEnabled 037_LocationServices 038_AnalyticsSharing 039_PasswordHints 040_FastUserSwitching \
041_AutomaticLoginOff 042_ConsoleLoginPrompt 043_SSHKeyPermissions 044_SudoTimeout 045_SudoSeparateTty \
046_LibraryValidation 047_BootROMVersion 048_KernelExtensions 049_SystemIntegrityProtection 050_APFSEncryptedVolumes \
051_TimeMachineEncrypted 052_CertificateTrustSettings 053_HomeFolderPermissions 054_UmaskSetting 055_GuestAccessSMB; do
out="$DATA_DIR/Controls/macOS/MAC_${n}.sh"
curl -fsSL "$CTRL_BASE/MAC_${n}.sh" -o "$out" || { echo "Failed to fetch MAC_${n}"; }
chmod 755 "$out" 2>/dev/null || true
done
chown -R root:wheel "$DATA_DIR/Controls" 2>/dev/null || true
CTL_COUNT=$(ls -1 "$DATA_DIR/Controls/macOS" 2>/dev/null | grep -c '\.sh$' || echo 0)
echo "Provisioned $CTL_COUNT macOS control scripts"
# Write config (idempotent)
cat > "$DATA_DIR/config.json" <<EOF
{
"apiBase": "$API_BASE",
"apiKey": "$API_KEY",
"tenantId": "$TENANT_ID",
"organizationId": "$ORG_ID",
"controlsPath": "$DATA_DIR/Controls",
"scanIntervalHours": 24
}
EOF
# Register launchd daemon
cat > "$PLIST_PATH" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.tatersecurity.agent</string>
<key>ProgramArguments</key>
<array><string>$BINARY_PATH</string></array>
<key>WorkingDirectory</key><string>$DATA_DIR</string>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key><string>$DATA_DIR/Logs/tater-agent.stdout.log</string>
<key>StandardErrorPath</key><string>$DATA_DIR/Logs/tater-agent.stderr.log</string>
</dict>
</plist>
PLIST
chmod 644 "$PLIST_PATH"
chown root:wheel "$PLIST_PATH"
# Load/reload the daemon
launchctl unload "$PLIST_PATH" 2>/dev/null || true
launchctl load "$PLIST_PATH"
echo "TATER Agent installed and started successfully."
exit 0
1. Upload the script to Intune
In Intune admin center, go to Devices > Scripts > macOS > Add. Upload tater_agent_install.sh.
2. Configure script settings
Set Run script as signed-in user to No (runs as root). Set Hide script notifications on devices to Yes. Script frequency: Not configured (runs once on enrollment; re-run manually as needed).
3. Assign to groups
Assign to All macOS Devices or a specific device group. The script is idempotent - safe to re-run on existing devices.
Manual macOS Installation
# Download and install (Apple Silicon)
sudo TATER_API_BASE="https://api.tatersecurity.com/api" \
TATER_API_KEY="your-api-key" \
TATER_TENANT_ID="your-tenant-id" \
TATER_ORG_ID="your-org-id" \
bash install.sh
# Check service status
launchctl list com.tatersecurity.agent
# View logs
tail -f "/Library/Application Support/TATER/Logs/tater-agent.stdout.log"
# Restart service
sudo launchctl unload /Library/LaunchDaemons/com.tatersecurity.agent.plist
sudo launchctl load /Library/LaunchDaemons/com.tatersecurity.agent.plist
# Uninstall
sudo bash uninstall.sh
Intune Detection Rule
Set the detection rule to: Custom script that checks test -f /usr/local/bin/tater-agent, or use File exists at /usr/local/bin/tater-agent.
macOS Security Controls (20)
| Control | Check | Tool |
|---|---|---|
| MAC_001 | FileVault disk encryption | fdesetup status |
| MAC_002 | Application Firewall + stealth mode | socketfilterfw |
| MAC_003 | Gatekeeper + System Integrity Protection | spctl, csrutil |
| MAC_004 | Automatic software updates | defaults read |
| MAC_005 | Screen lock password (within 5s) | defaults read |
| MAC_006 | Remote Login (SSH) disabled | systemsetup |
| MAC_007 | No sharing services enabled | launchctl list |
| MAC_008 | Password policy configured | pwpolicy |
| MAC_009 | Time Machine backup + encryption | tmutil |
| MAC_010 | Guest account disabled | defaults read |
| MAC_011 | AirDrop not set to Everyone | defaults read |
| MAC_012 | XProtect definitions current | XProtect bundle plist |
| MAC_013 | NTP time sync enabled | systemsetup |
| MAC_014 | Bluetooth not discoverable | defaults read |
| MAC_015 | Secure Boot (Full Security) | bputil / nvram |
| MAC_016 | No pending software updates | softwareupdate -l |
| MAC_017 | Remote Management (ARD) disabled | launchctl |
| MAC_018 | Login window: Name + Password | defaults read |
| MAC_019 | OpenBSM audit daemon running | launchctl |
| MAC_020 | Wi-Fi using WPA2/WPA3 | airport -I |
| MAC_021 | Safari "Open safe files" disabled | defaults read |
| MAC_022 | Terminal Secure Keyboard Entry | defaults read |
| MAC_023 | Screen saver requires password | defaults read |
| MAC_024 | Firewall stealth mode enabled | socketfilterfw |
| MAC_025 | Firewall logging enabled | socketfilterfw |
| MAC_026 | Remote Apple Events disabled | systemsetup / launchctl |
| MAC_027 | Internet Sharing disabled | defaults read (com.apple.nat) |
| MAC_028 | Media Sharing disabled | defaults read (per user) |
| MAC_029 | Printer Sharing disabled | cupsctl |
| MAC_030 | No NFS exports configured | /etc/exports |
| MAC_031 | Wake for network access disabled | pmset -g |
| MAC_032 | Power Nap disabled | pmset -g |
| MAC_033 | Find My Mac status (informational) | nvram |
| MAC_034 | iCloud Desktop and Documents sync | defaults read (per user) |
| MAC_035 | Diagnostics submission to Apple off | DiagnosticMessagesHistory.plist |
| MAC_036 | Siri status (review) | defaults read (per user) |
| MAC_037 | Location Services status | locationd plist / launchctl |
| MAC_038 | Analytics sharing with developers off | DiagnosticMessagesHistory.plist |
| MAC_039 | Password hints disabled | defaults read |
| MAC_040 | Fast User Switching disabled | defaults read |
| MAC_041 | Automatic login disabled | defaults read |
| MAC_042 | Login window: name + password prompt | defaults read |
| MAC_043 | SSH host key permissions (600) | stat / systemsetup |
| MAC_044 | Sudo timeout 5 minutes or less | /etc/sudoers |
| MAC_045 | Sudo tty_tickets not disabled | /etc/sudoers |
| MAC_046 | Library Validation not disabled | defaults read |
| MAC_047 | Firmware version (informational) | system_profiler |
| MAC_048 | No third-party kernel extensions | kextstat |
| MAC_049 | SIP + authenticated-root enabled | csrutil |
| MAC_050 | APFS Data volumes encrypted | diskutil apfs list |
| MAC_051 | Time Machine destinations encrypted | tmutil destinationinfo |
| MAC_052 | No custom cert trust overrides | security dump-trust-settings |
| MAC_053 | Home folders not group/world readable | ls -ld |
| MAC_054 | No weakened system umask | launchctl getenv |
| MAC_055 | SMB guest access disabled | defaults read (com.apple.smb.server) |
Linux Deployment
# Download and install (auto-detects amd64/arm64)
sudo TATER_API_BASE="https://api.tatersecurity.com/api" \
TATER_API_KEY="your-api-key" \
TATER_TENANT_ID="your-tenant-id" \
TATER_ORG_ID="your-org-id" \
bash install.sh
# Check service status
sudo systemctl status TATERAgent
# View logs
sudo journalctl -u TATERAgent -f
# Restart service
sudo systemctl restart TATERAgent
# Uninstall
sudo tater-agent -uninstall
sudo rm /usr/local/bin/tater-agent
Linux installs to /usr/local/bin/tater-agent with config at /var/lib/tater/config.json (root) or ~/.config/tater/config.json (user). The agent registers as a systemd service and runs 60 bash security controls (firewall, SSH hardening, disk encryption, SELinux/AppArmor, auditd, kernel hardening, etc.).
Agent Auto-Update
The TATER Agent automatically checks for updates on each run:
- Agent queries
GET /api/agent/version(no authentication required) - The API returns the latest version number, download URL, and SHA-256 hash
- If a newer version is available, the agent downloads the updated MSI from the TATER SWA
- SHA-256 hash is verified against the API-provided hash to ensure integrity
- The update is applied silently on the next agent restart
The /api/agent/version endpoint requires no authentication, allowing agents behind firewalls to check for updates without API key exposure. The response includes: { version, downloadUrl, sha256 }.
Speed Test
If your tenant uses Microsoft Global Secure Access, Zscaler, Netskope, Cisco Umbrella, or Palo Alto Prisma Access, the speed-test endpoints below need to be bypassed from traffic forwarding and SSL inspection - otherwise the test measures proxy throughput, not real-world ISP capacity. See the Agent Network Requirements guide for the FQDN bypass list and per-vendor configuration steps.
The agent includes a built-in network speed test that measures download bandwidth:
- Tests use self-hosted files at
https://www.tatersecurity.com/Agent/speedtest/100mb.binand50mb.bin - No dependency on third-party services (Cloudflare caps at ~25MB)
- Results are uploaded to the TATER API and visible on the Scans page in the "Speed Test" group
- Speed test data is also displayed in individual device detail views
Tray Application
The TATER Tray application runs in the system tray and provides:
- Agent status indicator (running, idle, scanning)
- Last scan timestamp and result summary
- Manual scan trigger
- Speed test trigger
- Access to agent logs
- Hidden from the Windows taskbar - only visible in the system tray notification area
- Uses the TATER shield logo icon
History Cleanup
The agent automatically manages disk space by keeping only the most recent data:
- Keeps the last 10 log files
- Keeps the last 10 scan result files
- Keeps the last 10 speed test result files
- Older files are deleted at the start of each agent run
Post-install Verification
After deploying to a test device, run these checks to confirm the agent is healthy before rolling out to the full fleet. The first scan typically completes within 10 minutes of install.
Windows
# 1. Service is installed and running
Get-Service -Name 'TATERAgent'
# Expected: Status = Running, StartType = Automatic
# 2. Config file is present and valid JSON
Get-Content "$env:ProgramData\TATER\config.json" | ConvertFrom-Json |
Format-List apiBase, tenantId, organizationId
# Expected: all three fields populated; no parse errors
# 3. Agent has produced output recently (logs or scans)
Get-ChildItem "$env:ProgramData\TATER\Logs", "$env:ProgramData\TATER\Scans" `
-Recurse -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 5 FullName, LastWriteTime
# Expected: at least one file modified within the last hour after install
# 4. Trigger a one-shot scan if no recent output
& "$env:ProgramFiles\TATER\tater-agent.exe" -scan
macOS
# 1. LaunchDaemon is loaded and process is running
sudo launchctl print system/com.tatersecurity.agent | head -20
# Expected: state = running
# 2. Config file is present
cat "/Library/Application Support/TATER/config.json"
# Expected: apiBase, tenantId, organizationId all populated
# 3. No quarantine xattr blocking the binary (see macOS section above)
xattr /usr/local/bin/tater-agent
# Expected: no output (or no com.apple.quarantine line)
# 4. Recent log output
sudo tail -50 "/Library/Application Support/TATER/Logs/tater-agent.stdout.log"
# Expected: scan loop heartbeat or scan-completion lines
Linux
# 1. systemd service status
sudo systemctl status tater-agent
# Expected: active (running), enabled
# 2. Config file
cat /var/lib/tater/config.json
# Expected: apiBase, tenantId, organizationId populated
# 3. Recent journal output
sudo journalctl -u tater-agent -n 50 --no-pager
# Expected: scan-loop heartbeat or successful upload lines
In TATER (any platform)
- Open app.tatersecurity.com → Devices. The newly installed device should appear within 10 minutes of the first successful scan upload.
- Open Scans. There should be a fresh endpoint scan with the device's hostname in the list.
- Open Settings → Endpoint Agent. The status card "Total Devices" and "Last Scan" should reflect the new device.
Troubleshooting
Common Issues
| Issue | Solution |
|---|---|
| Intune Proactive Remediation reports Failed but service is installed | The MSI custom action requires APIBASE, APIKEY, TENANTID, ORGANIZATIONID at install time. Older versions of the Remediate script ran msiexec /i $MSIPath /qn with no properties - the install fails before the service is created. Confirm your script passes all four MSI properties on the msiexec command line. See the Remediate-TATERAgent.ps1 above for the correct pattern. Inspect C:\Windows\Temp\TATERInstall\tater-install.log on a failed device to see which property the installer rejected. |
| Intune detection always reports Non-Compliant after install | You're likely running a v1.x detection script that looks for %ProgramData%\TATER\TATER-Agent.ps1 or a scheduled task. The current v2.x agent is a Go binary running as a Windows service. Replace the detection script with the v2.x version above (checks the TATERAgent Windows service + config file + recent log output). |
| macOS install succeeds but agent never reports / can't be launched manually | The agent binary is unsigned, and curl applies com.apple.quarantine on download - macOS Gatekeeper silently blocks execution even when launchd runs as root. The current install script strips the xattr automatically. To fix already-deployed devices: sudo xattr -c /usr/local/bin/tater-agent && sudo launchctl kickstart -k system/com.tatersecurity.agent. |
| MSI install fails with BadImageFormatException | Ensure the MSI custom actions are compiled as AnyCPU, not x64-only. |
| Agent installed but no scans appearing in TATER | Almost always one of: (1) outbound HTTPS to api.tatersecurity.com blocked by an SSE/SASE platform doing TLS inspection - see Agent Network Requirements; (2) wrong API key (check config.json); (3) wrong Organization ID (check it starts with org-); (4) the API key was generated in a different organization than the one configured. Check the agent log file for HTTP 401/403 responses to narrow it down. |
| Agent cannot reach API | Verify HTTPS connectivity to api.tatersecurity.com on port 443. Check proxy settings and TLS inspection rules. SSE/SASE platforms typically need a bypass rule for *.tatersecurity.com. |
| Scans not uploading | Check the API key is valid and the Organization ID is correct. Review agent logs in the TATER data directory (%ProgramData%\TATER\Logs on Windows, /Library/Application Support/TATER/Logs on macOS, /var/lib/tater/logs on Linux). |
| Speed test shows 0 Mbps | Verify access to www.tatersecurity.com/Agent/speedtest/. Check for firewall rules blocking large file downloads. |
| Auto-update not working | The agent checks /api/agent/version without auth. Ensure this endpoint is accessible. Check SHA-256 hash match. |
Integrity Repair
If the agent installation becomes corrupted, run the integrity repair script:
# Run from the TATER installation directory
.\Fix-Integrity.ps1
TATER