
Set Policy on Individual Device
This script updates the assigned policy on a specific NinjaOne device
PowerShell
# --------------------------------------------------
# Author: Gavin Stone (NinjaOne)
# Attribution: Luke Whitelock (NinjaOne) for his work on the Authentication Functions
# Date: 2026-03-10
# Description: Update the assigned policy on a specific device by its device ID. Only the policyId field should be changed — no other device properties should be modified.
# Version: 1.0
# --------------------------------------------------
# User editable variables:
$NinjaOneInstance = 'eu.ninjarmm.com' # Please replace with the region instance you login to (app.ninjarmm.com, us2.ninjarmm.com, eu.ninjarmm.com, ca.ninjarmm.com, oc.ninjarmm.com)
$NinjaOneClientId = ''
$NinjaOneClientSecret = ''
# The NinjaOne device ID to update
$DeviceId = 1
# The policy ID to assign to the device (set to $null to revert to the organisation-level policy)
$NewPolicyId = 42
# Functions for Authentication
function Get-NinjaOneToken {
[CmdletBinding()]
param()
if ($Script:NinjaOneInstance -and $Script:NinjaOneClientID -and $Script:NinjaOneClientSecret ) {
if ($Script:NinjaTokenExpiry -and (Get-Date) -lt $Script:NinjaTokenExpiry) {
return $Script:NinjaToken
}
else {
if ($Script:NinjaOneRefreshToken) {
$Body = @{
'grant_type' = 'refresh_token'
'client_id' = $Script:NinjaOneClientID
'client_secret' = $Script:NinjaOneClientSecret
'refresh_token' = $Script:NinjaOneRefreshToken
}
}
else {
$body = @{
grant_type = 'client_credentials'
client_id = $Script:NinjaOneClientID
client_secret = $Script:NinjaOneClientSecret
scope = 'monitoring management'
}
}
$token = Invoke-RestMethod -Uri "https://$($Script:NinjaOneInstance -replace '/ws','')/ws/oauth/token" -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded' -UseBasicParsing
$Script:NinjaTokenExpiry = (Get-Date).AddSeconds($Token.expires_in)
$Script:NinjaToken = $token
Write-Host 'Fetched New Token'
return $token
}
}
else {
Throw 'Please run Connect-NinjaOne first'
}
}
function Connect-NinjaOne {
[CmdletBinding()]
param (
[Parameter(mandatory = $true)]
$NinjaOneInstance,
[Parameter(mandatory = $true)]
$NinjaOneClientID,
[Parameter(mandatory = $true)]
$NinjaOneClientSecret,
$NinjaOneRefreshToken
)
$Script:NinjaOneInstance = $NinjaOneInstance
$Script:NinjaOneClientID = $NinjaOneClientID
$Script:NinjaOneClientSecret = $NinjaOneClientSecret
$Script:NinjaOneRefreshToken = $NinjaOneRefreshToken
try {
$Null = Get-NinjaOneToken -ea Stop
}
catch {
Throw "Failed to Connect to NinjaOne: $_"
}
}
function Invoke-NinjaOneRequest {
param(
$Method,
$Body,
$InputObject,
$Path,
$QueryParams,
[Switch]$Paginate,
[Switch]$AsArray
)
$Token = Get-NinjaOneToken
if ($InputObject) {
if ($AsArray) {
$Body = $InputObject | ConvertTo-Json -depth 100
if (($InputObject | Measure-Object).count -eq 1 ) {
$Body = '[' + $Body + ']'
}
}
else {
$Body = $InputObject | ConvertTo-Json -depth 100
}
}
try {
if ($Method -in @('GET', 'DELETE')) {
if ($Paginate) {
$After = 0
$PageSize = 1000
$NinjaResult = do {
$Result = Invoke-WebRequest -uri "https://$($Script:NinjaOneInstance)/api/v2/$($Path)?pageSize=$PageSize&after=$After$(if ($QueryParams){"&$QueryParams"})" -Method $Method -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -UseBasicParsing
$Result
$ResultCount = ($Result.id | Measure-Object -Maximum)
$After = $ResultCount.maximum
} while ($ResultCount.count -eq $PageSize)
}
else {
$NinjaResult = Invoke-WebRequest -uri "https://$($Script:NinjaOneInstance)/api/v2/$($Path)$(if ($QueryParams){"?$QueryParams"})" -Method $Method -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json; charset=utf-8' -UseBasicParsing
}
}
elseif ($Method -in @('PATCH', 'PUT', 'POST')) {
$NinjaResult = Invoke-WebRequest -uri "https://$($Script:NinjaOneInstance)/api/v2/$($Path)$(if ($QueryParams){"?$QueryParams"})" -Method $Method -Headers @{Authorization = "Bearer $($token.access_token)" } -Body $Body -ContentType 'application/json; charset=utf-8' -UseBasicParsing
}
else {
Throw 'Unknown Method'
}
}
catch {
Throw "Error Occured: $_"
}
try {
return $NinjaResult.content | ConvertFrom-Json -ea stop
}
catch {
return $NinjaResult.content
}
}
# Connect to NinjaOne API
try {
Connect-NinjaOne -NinjaOneInstance $NinjaOneInstance -NinjaOneClientID $NinjaOneClientId -NinjaOneClientSecret $NinjaOneClientSecret
}
catch {
Write-Output "Failed to connect to NinjaOne API: $_"
exit 1
}
# ─── Script Logic ─────────────────────────────────────────────────────────────
# Validate inputs
if (-not $DeviceId) {
Write-Host "Error: Please set the `$DeviceId variable to the target device's ID."
exit 1
}
if (-not $NewPolicyId -and $NewPolicyId -ne 0) {
Write-Host "Error: Please set the `$NewPolicyId variable to the policy ID to assign (or `$null to revert to the organisation policy)."
exit 1
}
# Fetch the device first to confirm it exists and show current state
Write-Host "Fetching device $DeviceId..."
try {
$Device = Invoke-NinjaOneRequest -Method GET -Path "device/$DeviceId"
} catch {
Write-Host "Error: Could not find device with ID $DeviceId. Please check the ID and try again."
exit 1
}
Write-Host "Device: $($Device.systemName) (ID: $($Device.id))"
Write-Host "Current Policy: $(if ($Device.policyId) { $Device.policyId } else { '(organisation default)' })"
Write-Host "New Policy: $(if ($NewPolicyId) { $NewPolicyId } else { '(revert to organisation default)' })"
if ($Device.policyId -eq $NewPolicyId) {
Write-Host "`nDevice is already assigned to policy $NewPolicyId. No changes made."
exit 0
}
# Build the update body — only include policyId to avoid changing anything else
$UpdateBody = @{
policyId = $NewPolicyId
}
Write-Host "`nUpdating policy..."
try {
Invoke-NinjaOneRequest -Method PATCH -Path "device/$DeviceId" -InputObject $UpdateBody
Write-Host "Successfully updated device '$($Device.systemName)' (ID: $DeviceId) to policy ID $NewPolicyId."
} catch {
Write-Host "Error: Failed to update device policy: $_"
exit 1
}
Set-DevicePolicy
Overview
This script updates the assigned policy on a specific NinjaOne device. It sends only the policyId field in the PATCH request, ensuring no other device properties are modified.
Attribution
- Author: Gavin Stone (NinjaOne)
Requirements / Prerequisites
- NinjaOne API Credentials:
NinjaOneClientIdNinjaOneClientSecret
- NinjaOne Instance URL: e.g.,
eu.ninjarmm.com - Policy ID to change too: You can find this by loading a policy, and it's the number that appears at the top, IE for editor/policy/106 it would be 106
How It Works
- Authentication: The script authenticates with the NinjaOne API using OAuth2 Client Credentials, obtaining an access token via
Connect-NinjaOne. - Fetch Device: Retrieves the target device via
device/{id}to confirm it exists and display its current policy assignment. - Compare Policies: Checks whether the device is already assigned to the requested policy and exits early if no change is needed.
- Update Policy: Sends a PATCH request to
device/{id}with only{ policyId: <value> }in the body, ensuring no other device properties are touched. - Confirm Result: Displays a success message with the device name and new policy ID.
Usage
-
Set Variables:
-
Open
Set-DevicePolicy.ps1in an editor (e.g., VS Code, PowerShell ISE). -
Fill in your NinjaOne credentials and any script-specific variables at the top:
$NinjaOneInstance = "eu.ninjarmm.com" $NinjaOneClientId = "your_client_id" $NinjaOneClientSecret = "your_client_secret" $DeviceId = 1 $NewPolicyId = 42 # You can find this by loading a policy, and it's the number that appears at the top
-
-
Run the Script:
.\Set-DevicePolicy.ps1
Expected Output
Fetching device 142...
Device: DESK-001 (ID: 142)
Current Policy: 15
New Policy: 42
Updating policy...
Successfully updated device 'DESK-001' (ID: 142) to policy ID 42.
Troubleshooting
-
Issue: Authentication fails with an error message.
- Solution: Verify that
$NinjaOneClientIdand$NinjaOneClientSecretare correct and that the API client has the required scopes (monitoring,management).
- Solution: Verify that
-
Issue: The script cannot connect to the NinjaOne API.
- Solution: Ensure that
$NinjaOneInstanceis correct (e.g.,eu.ninjarmm.com,app.ninjarmm.com,oc.ninjarmm.com) and accessible from your network.
- Solution: Ensure that
-
Issue: Error: Could not find device with ID.
- Solution: Verify the device ID exists in your NinjaOne instance. You can find device IDs in the NinjaOne dashboard or by querying the
/v2/devicesendpoint.
- Solution: Verify the device ID exists in your NinjaOne instance. You can find device IDs in the NinjaOne dashboard or by querying the
-
Issue: 403 Forbidden when updating the device.
- Solution: Ensure your API client credentials have the 'management' scope and write permissions for the target device's organisation.
Notes
- Ensure that your NinjaOne API credentials are kept secure and not shared.
- The PATCH request sends only
policyId— no other device fields (displayName, location, userData, etc.) are included, so they remain unchanged. - To update multiple devices, you can wrap the script in a loop or modify it to accept an array of device IDs.