Skip to content

Deployment with Group Policy (GPO)

If you run Active Directory but do not have Intune, Configuration Manager, or another endpoint management tool, you can deploy the SenseOn Universal Sensor with Group Policy alone. This guide covers deploying to domain-joined Windows devices using a computer startup script, and an alternative that installs without waiting for a reboot.

⚠ Group Policy Software Installation cannot be used. The Software Installation node in Group Policy only accepts an MSI, and it offers no way to pass your tenant's installer key to that MSI. SenseOn is installed by a script that reads the key from an environment variable, so deployment has to run that script. The two supported routes are a startup script and a scheduled task. SenseOn does not publish a standalone MSI for customer deployment.

💡 Endpoints with no direct internet. Devices that cannot reach the internet directly can still be deployed this way, as long as they can reach the SenseOn install URL and telemetry endpoints through a proxy. Point the installer at the proxy and give the running sensor its own proxy file, both covered in Deploying through a proxy. A host with no outbound path at all, through a proxy or otherwise, cannot be reached by this method; for that case see If you must pre-install on the golden image.


Before You Start

You will need:

  • Rights to create and link a Group Policy Object, and to write to a domain share.
  • Your Windows install command and installer key, from Settings > Universal Sensor.
  • Target devices able to reach the SenseOn install and telemetry endpoints. See Endpoint Requirements for the domains involved, and Proxy Configuration if your estate uses a proxy.
  • An organisational unit (OU), or a security group, containing the computer accounts you want to deploy to.

⚠ Treat the installer key as a secret. The key enrols any device that presents it. A script holding the key must not be readable by ordinary users, which rules out the NETLOGON share for most environments, since every authenticated user can read it. Choose where the script lives covers the safer option. If a key is exposed, rotate it in Settings > Universal Sensor. Rotating invalidates the previous key, so update your script before you rotate, or pending installations will fail.


Option 1: Deploy with a Computer Startup Script

Startup scripts run as SYSTEM before any user signs in, so the install runs with the privileges it needs and does not depend on who is logged on.

Step 1: Create the install script

Group Policy runs a startup script at every boot, and re-running the SenseOn install command on a device that already has it can fail rather than complete as a no-op. The script below therefore checks first and exits if SenseOn is present, which makes it safe to leave linked indefinitely.

Save it as Install-SenseOn.ps1, substituting your tenant hostname and installer key:

<#
    Installs the SenseOn Universal Sensor if it is not already present.
    Intended to run as a Group Policy computer startup script (runs as SYSTEM).
#>

$ErrorActionPreference = "Stop"

$logDir = Join-Path $env:ProgramData "SenseOnDeploy"
if (-not (Test-Path $logDir)) { New-Item -Path $logDir -ItemType Directory -Force | Out-Null }
$log = Join-Path $logDir "Install-SenseOn.log"

function Write-Log($message) {
    "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')  $message" | Out-File -FilePath $log -Append -Encoding utf8
}

# Already installed? The bootstrapper is the service which installs and maintains the
# sensor, so its presence is the reliable test. Exit quietly so the next boot is cheap.
if (Get-Service -Name "senseon-bootstrapper" -ErrorAction SilentlyContinue) {
    Write-Log "senseon-bootstrapper present, nothing to do."
    exit 0
}

# Older Windows builds negotiate TLS 1.0 by default, which the download will refuse.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

try {
    Write-Log "Starting SenseOn install."
    $env:SENSEON_INSTALLER_KEY = "<your-installer-key>"
    Invoke-WebRequest -UseBasicParsing -Uri "https://<your-tenant>.senseon.io/install.ps1" | Invoke-Expression
    Write-Log "Install command completed."
    exit 0
}
catch {
    Write-Log "Install failed: $($_.Exception.Message)"
    exit 1
}

The script writes to C:\ProgramData\SenseOnDeploy\Install-SenseOn.log on each device, which is where to look first if a device does not appear in the platform.

🛡 Optional: verify the install script checksum

If your security policy requires checksum verification before executing remote scripts, verify the script on your admin workstation before you deploy:

Invoke-WebRequest -UseBasicParsing -Uri "https://<your-tenant>.senseon.io/install.ps1" -OutFile install.ps1
Get-FileHash install.ps1 -Algorithm SHA256

Compare the hash against the value shown next to the command in Settings > Universal Sensor. If it matches, replace the Invoke-WebRequest ... | Invoke-Expression line in Install-SenseOn.ps1 with the contents of the verified script, keeping the $env:SENSEON_INSTALLER_KEY line above it.

Step 2: Choose where the script lives

Because the script contains your installer key, where you put it matters.

Location Who can read it Use it?
The GPO's own Machine\Scripts\Startup folder Domain Admins and, by default, Authenticated Users. The ACL can be tightened to Domain Computers and Domain Admins only. Recommended. The folder travels with the GPO and can be locked down.
The NETLOGON share Every authenticated user in the domain Avoid unless you accept that any signed-in user can read the key.

To use the GPO's own folder, open the GPO in the Group Policy Management Editor, navigate to the startup scripts setting described in Step 3, select Show Files, and copy Install-SenseOn.ps1 into the folder that opens. This is the Machine\Scripts\Startup folder inside the GPO's directory in SYSVOL.

Once the file is in place, restrict who can read it. Remove Authenticated Users from the file's ACL and grant read access to Domain Computers and Domain Admins instead. Domain Computers is what matters, because a startup script is read by the computer account rather than by the signed-in user.

ℹ Note: Tightening the ACL on the file does not affect Group Policy processing, as long as Domain Computers retains read access. If you remove that too, devices silently fail to run the script.

  1. Open Group Policy Management on a domain controller or a workstation with the Remote Server Administration Tools installed.
  2. Right-click the OU holding your target computer accounts and select Create a GPO in this domain, and Link it here. Name it something recognisable, for example Deploy SenseOn Universal Sensor.
  3. Right-click the new GPO and select Edit.
  4. Navigate to Computer Configuration > Policies > Windows Settings > Scripts (Startup/Shutdown).
  5. Double-click Startup, then select Show Files and place the script as described in Step 2.
  6. Still in the Startup properties, on the Scripts tab, select Add and enter:
    • Script Name: powershell.exe
    • Script Parameters: -ExecutionPolicy Bypass -NoProfile -File "%~dp0Install-SenseOn.ps1"
  7. Select OK to close the properties.

💡 Why the Scripts tab rather than the PowerShell Scripts tab. The PowerShell Scripts tab runs your script under the machine's effective execution policy, so a restrictive policy stops the install. Calling powershell.exe from the Scripts tab with -ExecutionPolicy Bypass avoids that. If your estate already sets an execution policy that permits signed or local scripts, the PowerShell Scripts tab is fine and slightly tidier.

Step 4: Make sure the network is ready

A startup script can run before the network stack is ready, and the install needs to download from your tenant. Without this step, the first boot after linking the GPO often fails and the device is only picked up on a later boot.

In the same GPO, enable both of the following:

  • Computer Configuration > Policies > Administrative Templates > System > Logon > Always wait for the network at computer startup and logon.
  • Computer Configuration > Policies > Administrative Templates > System > Group Policy > Specify startup policy processing wait time. Set a value that suits your estate, for example 60 seconds.

Also check Computer Configuration > Policies > Administrative Templates > System > Scripts > Maximum wait time for Group Policy scripts. The default is 600 seconds for all startup scripts combined. The SenseOn install usually completes well inside that, but if you run several startup scripts, confirm the budget is enough.

Deploying through a proxy

A startup script runs as SYSTEM before any user signs in, and SYSTEM does not inherit the proxy a signed-in user has. A proxy that works when you run the install command by hand can therefore be missing when the same command runs from Group Policy, and the download fails with no obvious cause. On endpoints that only reach SenseOn through a proxy, point the installer at that proxy explicitly rather than relying on the machine picking it up.

The install script takes a -Proxy host:port option that routes both its own download and the bootstrapper's first contact through an HTTP CONNECT proxy. The running sensor then uses a separate proxy.json file for its ongoing connection, so a fully offline endpoint needs both. See Installing Through or Around a Proxy for the option itself, and Proxy Configuration for the proxy.json format.

Use this variant of Install-SenseOn.ps1, setting $Proxy to the site's proxy in host:port form:

<#
    Installs the SenseOn Universal Sensor through a proxy.
    Runs as a Group Policy computer startup script (SYSTEM).
#>

$ErrorActionPreference = "Stop"
$Proxy        = "proxy.process.local:3128"     # the site's proxy, host:port
$InstallerKey = "<your-installer-key>"
$Tenant       = "<your-tenant>.senseon.io"

$logDir = Join-Path $env:ProgramData "SenseOnDeploy"
if (-not (Test-Path $logDir)) { New-Item -Path $logDir -ItemType Directory -Force | Out-Null }
$log = Join-Path $logDir "Install-SenseOn.log"
function Write-Log($m) { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')  $m" | Out-File $log -Append -Encoding utf8 }

if (Get-Service -Name "senseon-bootstrapper" -ErrorAction SilentlyContinue) {
    Write-Log "senseon-bootstrapper present, nothing to do."
    exit 0
}

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$script = Join-Path $env:TEMP "install.ps1"

try {
    # The script's own download must also go through the proxy.
    Write-Log "Downloading install script through $Proxy."
    Invoke-WebRequest -UseBasicParsing -Uri "https://$Tenant/install.ps1" -OutFile $script -Proxy "http://$Proxy"

    Write-Log "Running install through $Proxy."
    $env:SENSEON_INSTALLER_KEY = $InstallerKey
    & powershell.exe -ExecutionPolicy Bypass -NoProfile -File $script -Proxy $Proxy
    if ($LASTEXITCODE -ne 0) { throw "install.ps1 exited $LASTEXITCODE" }

    # Give the running sensor its own proxy for ongoing telemetry.
    $bootstrapperDir = Join-Path $env:ProgramData "senseon-bootstrapper"
    if (-not (Test-Path $bootstrapperDir)) { New-Item -Path $bootstrapperDir -ItemType Directory -Force | Out-Null }
    $parts = $Proxy.Split(":")
    @{ proxy_host = $parts[0]; proxy_port = [int]$parts[1] } | ConvertTo-Json -Compress |
        Out-File (Join-Path $bootstrapperDir "proxy.json") -Encoding ascii
    Write-Log "Install complete, proxy.json written."
    exit 0
}
catch {
    Write-Log "Install failed: $($_.Exception.Message)"
    exit 1
}

ℹ Two separate proxy settings. -Proxy covers installation and the bootstrapper's first fetch. proxy.json covers the running sensor's ongoing connection. On a fully offline estate you need both, which is why the script writes proxy.json as its last step.

💡 Deploying proxy.json on its own. If you would rather not write the file from the script, deploy it with a Group Policy Preferences file item (Computer Configuration > Preferences > Windows Settings > Files) to %ProgramData%\senseon-bootstrapper\proxy.json. Deploy it alongside, or ahead of, the install so the sensor has a proxy from first start.

Whichever proxy you use, it must be allowed to reach the SenseOn install and telemetry endpoints listed in Connectivity Requirements. If the proxy cannot reach those, the install fails even when the endpoint reaches the proxy.

Different proxies per site

Where each site has its own proxy, either link a per-site copy of this GPO carrying that site's $Proxy value to the site's OU, or have one script try each candidate proxy in turn, install through the first that works, and save that one. Replace the download, install, and proxy.json steps in the script above with:

$Proxies = @("site-a-proxy:3128", "site-b-proxy:3128", "site-c-proxy:3128")
$working = $null
foreach ($p in $Proxies) {
    try {
        Invoke-WebRequest -UseBasicParsing -Uri "https://$Tenant/install.ps1" -OutFile $script -Proxy "http://$p" -TimeoutSec 30
        $env:SENSEON_INSTALLER_KEY = $InstallerKey
        & powershell.exe -ExecutionPolicy Bypass -NoProfile -File $script -Proxy $p
        if ($LASTEXITCODE -eq 0) { $working = $p; Write-Log "Installed via $p."; break }
    }
    catch { Write-Log "Proxy $p did not work, trying the next." }
}
if (-not $working) { Write-Log "No proxy in the list worked."; exit 1 }

# Save the proxy that worked so the running sensor keeps using it.
$bootstrapperDir = Join-Path $env:ProgramData "senseon-bootstrapper"
if (-not (Test-Path $bootstrapperDir)) { New-Item -Path $bootstrapperDir -ItemType Directory -Force | Out-Null }
$parts = $working.Split(":")
@{ proxy_host = $parts[0]; proxy_port = [int]$parts[1] } | ConvertTo-Json -Compress |
    Out-File (Join-Path $bootstrapperDir "proxy.json") -Encoding ascii
Write-Log "proxy.json written for $working."

The installed-check at the top of the script keeps this safe to leave linked, so a device that only reaches a working proxy on a later boot still completes.

How the proxy is saved

An endpoint keeps a single proxy setting for its ongoing connection, held in proxy.json. It does not store a list, and it does not cycle through several proxies at run time. That is why the choosing is done once, at install: the loop tries each candidate in turn and, as soon as one succeeds, writes that one proxy into proxy.json. From then on the running sensor uses the saved proxy without the script re-specifying it, so per-site differences are resolved at deployment and persisted per device.

The install-time -Proxy option and the saved proxy.json are separate settings. -Proxy gets the install and the bootstrapper's first contact through the proxy, and writing proxy.json with the same value is what carries that proxy forward for the sensor afterwards. To change a device's proxy later, edit or replace its proxy.json, as described in Proxy Configuration, or redeploy with a different value.

Step 5: Apply the policy

Startup scripts only run at boot. On a target device, either restart it, or refresh policy and then restart:

gpupdate /target:computer /force

Devices appear in Assets > Devices within a few minutes of the script running.


Option 2: Deploy Without Waiting for a Reboot

If you need devices enrolled without restarting them, use a Group Policy Preferences immediate task instead of a startup script. The task runs once, shortly after the device next refreshes policy, then deletes itself.

  1. Place Install-SenseOn.ps1 on a share that Domain Computers can read, following the same reasoning as Step 2. A dedicated share with a restricted ACL is appropriate here, since a Preferences task cannot use the GPO's own scripts folder.
  2. In the GPO, navigate to Computer Configuration > Preferences > Control Panel Settings > Scheduled Tasks.
  3. Right-click and select New > Immediate Task (At least Windows 7).
  4. On the General tab:
    • Set Action to Create.
    • Under Security options, select Change User or Group, enter SYSTEM, and confirm.
    • Select Run with highest privileges.
  5. On the Actions tab, add a Start a program action:
    • Program/script: powershell.exe
    • Add arguments: -ExecutionPolicy Bypass -NoProfile -File "\\<your-domain>\<share>\Install-SenseOn.ps1"
  6. On the Common tab, select Apply once and do not reapply.

The task runs at the next policy refresh, which is within 90 minutes by default, or immediately after gpupdate /target:computer /force on a target device.

💡 Use both together. A common pattern is the immediate task to enrol the devices you have today, and the startup script left linked to catch devices built or re-imaged later. The installed-check in the script means the two cannot collide.


Verifying the Deployment

  1. Log in to SenseOn.
  2. Go to Assets > Devices.
  3. Confirm your target hosts appear with their expected hostnames and a recent Last Seen timestamp.

On an individual device, confirm both SenseOn services are present and running:

Get-Service senseon-bootstrapper, senseon-seed

senseon-bootstrapper installs and maintains the sensor, and senseon-seed is the sensor itself. If the bootstrapper is running but the sensor is not yet present, wait around ten minutes and check again, as the bootstrapper installs it shortly after enrolment.


If Devices Do Not Appear

Work through these in order:

  1. Confirm the policy reached the device. Run gpresult /r /scope:computer on a target device and check the GPO is listed under applied policy objects. If it is not, check the GPO link, the OU membership of the computer account, and any security filtering on the GPO.
  2. Check the deployment log. Look at C:\ProgramData\SenseOnDeploy\Install-SenseOn.log. A log recording a failure tells you the script ran, which rules out policy delivery. No log at all means the script never ran.
  3. Confirm the computer account can read the script. If you tightened the ACL, verify Domain Computers still has read access. A script the computer cannot read produces no log.
  4. Check connectivity. From the device, confirm it can reach your tenant. See Endpoint Requirements, and note that TLS inspection needs a bypass for the SenseOn domains.
  5. Check the installer key. If the key has been rotated since you wrote the script, the install fails. Copy the current command from Settings > Universal Sensor.
  6. Capture verbose output. See Troubleshooting: Running the Install Script in Verbose Mode.

Removing SenseOn

Unlink or delete the GPO first, otherwise the startup script reinstalls the agent at the next boot. Then remove the agent as described in Uninstalling SenseOn, which covers the PowerShell uninstall script. That script is safe to run more than once, so it can be deployed the same way as the installer, through a startup script or an immediate task.

⚠ Remove the bootstrapper as well as the sensor. While the bootstrapper is installed it reinstalls the Universal Sensor if it goes missing, normally within about ten minutes. The uninstall script handles both packages in the right order.