Powershell script to remove devices that have been disconnected longer than X days


Userlevel 7

A common request we get is to remove old devices from the console, especially ones that might have been re-imaged. Currently you can do this on the devices page by sorting by Last Disconnected Date and selecting devices to remove. However, this can become unwieldy if you have pages and pages of devices to remove.


This script automates the removal using an API call to check the last disconnected date and remove any devices older than the number of days you specify in the code.


There are four areas in the code you’ll need to update to get the script to function:




  1. $orgID = 'YOUR_ORG_ID' - put your Org ID, which can be found by looking at the URL of your console and selecting the value after the “?o=”: https://console.automox.com/dashboard?o=999999. In this example URL the Org ID is the 999999 portion.


  2. $apiKey = 'YOUR_API_KEY' - in your console, go to Settings->API and select the API key. Note that the API key is per admin user, so you and another admin in your console will have different API keys.


  3. $maxDays = 120 - any device that has been disconnected for more than 120 days will be deleted from the console. You can adjust this to the number of days you prefer.


  4. $logPath = 'C:\temp\' - set this to the folder of your choosing


Once you’ve made those four changes, you can run the script below on any Windows device using Powershell.


Note: This script will automatically remove devices from your console and this is not a reversible operation. Any device that you remove unintentionally using this script will have to have the agent reinstalled to return it to your console.


If you wish to run the script in a test mode to see what will be deleted, you can uncomment this line:


#echo "device: $serverName `t last disconnected date: $lastCheckin `t days disconnected: $span.Days"

and comment out the line that does the deletion:


$delResponse = Invoke-WebRequest -UseBasicParsing -Method Delete -Uri $delURI

That will show you a list of all your devices with the date of last disconnect and number of days since that disconnect, and which devices would have been deleted by the script.


Remove Old Disconnected Devices Script:


#    [-------------------------------------DISCLAIMER-------------------------------------]
# This script is provided as-is with no implicit
# warranty or support. It's always considered a best practice
# to test scripts in a DEV/TEST environment, before running them
# in production.
# Please proceed with caution.
# Do not distribute your API Key to any untrusted 3rd party.
# [-------------------------------------DISCLAIMER-------------------------------------]

# The SETUP section gets your API return and is not specific to any particular use-case.
# The OPERATIONAL section is specific to one scenario and can be overhauled for your specific uses.

############################# SETUP Section #############################

#modify log path as desired
$logPath = 'C:\temp\'

#Easier to maintain, especially if multiple organizations, or for repurposing for different API Tables
$apiInstance = 'https://console.automox.com/api/'
$apiTable = 'servers'
#replace the two variables below with your Org ID and your API key
$orgID = 'YOUR_ORG_ID'
$apiKey = 'YOUR_API_KEY'
$orgAndKey = "?o=$orgID&api_key=$apiKey"

#Number of days disconnected before deleting - adjust to your desired range
$maxDays = 120

#optional query to filter, if the whole server list is too long, you could add the date filter here
$query = ''

#initialize empty arrays to store server IDs to be deleted
$toDelete = @()
$failDelete = @()
$successDelete = @()

#put components together
$getURI = $apiInstance + $apiTable + $orgAndKey + $query

#Get the json body of the Web Request
$jsonReturn = (Invoke-WebRequest -UseBasicParsing -Method Get -Uri $getURI).Content

#Convert to object with manipulatable properties/values
$servers = $jsonReturn | ConvertFrom-Json

#Export to C

############################# END Setup Section #############################


############################# OPERATIONAL Section #############################

#Check each server for checkin time, conditionally take action
foreach ($server in $servers) {
#pull out wanted details
$serverID = $server.id
$serverName = $server.name

#check to make sure last_disconnect_time isn't null, which it will be for currently connected devices, in which case the lastcheckin variable will be set to today's date
$lastCheckin = Get-Date
if ($server.last_disconnect_time) {
$lastCheckin = [datetime]$server.last_disconnect_time
}


#Calculate time since last checking to now
$span = New-TimeSpan -Start $lastCheckin

#uncomment line below if you want to see all the servers with their last disconnect time and number of days disconnected for troubleshooting
#echo "device: $serverName `t last disconnected date: $lastCheckin `t days disconnected: $span.Days"


if ($span.Days -ge $maxDays) {
#Delete or data collection code here

#Delete method takes serverID only
#Hardcoded would look like this $delURI = https://console.automox.com/api/servers/$serverID?o=YOUR_ORG_ID&api_key=YOUR_API_KEY

$toDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnect_time"=$lastCheckin}
$delURI = $apiInstance + $apiTable + '/' + $serverID + $orgAndKey

#Attempt to delete and track failures
try {
$delResponse = Invoke-WebRequest -UseBasicParsing -Method Delete -Uri $delURI
Write-Output "Successfully Deleted Server: $serverName"
$successDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnectn_time"=$lastCheckin}
}
catch {
$failDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnect_time"=$lastCheckin}
Write-Output "Failed to Delete Server: $serverName"
}
}
#Output logging into json files for later review/manipulation
$toDelete | ConvertTo-Json | Out-File $logPath\ToBeDeleted.json
$successDelete | ConvertTo-Json | Out-File $logPath\Delete_Success.json
$failDelete | ConvertTo-Json | Out-File $logPath\Delete_Failed.json
}

If you have any questions or problems getting this to function correctly please let me know!


17 replies

Unbelievable data blog

Wow @Nic, I didn’t know you made this. This is an awesome solution for folks for the time being! Hopefully this becomes a native feature in the future.

Userlevel 7

I merely updated an old script that someone in support wrote (maybe @rich?) to support the new API commands 🙂

This could be very helpful for me, so I appreciate you sharing. I’m trying to run a test of the script but I get the following error:


Missing closing '}' in statement block or type definition. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : MissingEndCurlyBrace


I have commented/uncommented the lines as instructed for the test. I’m not sure where it is exactly that I need to insert a bracket.

Userlevel 7

You might have accidentally commented out a bracket, or maybe there was a copy paste error? If you want to post the code you have now that’s throwing the error then I can see if I can spot the problem.

Thanks for the quick response. Here’s what I used:


$logPath = 'C:\Users\hivester\Documents'

#Easier to maintain, especially if multiple organizations, or for repurposing for different API Tables
$apiInstance = 'https://console.automox.com/api/'
$apiTable = 'servers'
#replace the two variables below with your Org ID and your API key
$orgID = 'myorgID'
$apiKey = 'myAPIkey'
$orgAndKey = "?o=$orgID&api_key=$apiKey"

#Number of days disconnected before deleting - adjust to your desired range
$maxDays = 90

#optional query to filter, if the whole server list is too long, you could add the date filter here
$query = ''

#initialize empty arrays to store server IDs to be deleted
$toDelete = @()
$failDelete = @()
$successDelete = @()

#put components together
$getURI = $apiInstance + $apiTable + $orgAndKey + $query

#Get the json body of the Web Request
$jsonReturn = (Invoke-WebRequest -UseBasicParsing -Method Get -Uri $getURI).Content

#Convert to object with manipulatable properties/values
$servers = $jsonReturn | ConvertFrom-Json

#Export to C

############################# END Setup Section #############################


############################# OPERATIONAL Section #############################

#Check each server for checkin time, conditionally take action
foreach ($server in $servers) {
#pull out wanted details
$serverID = $server.id
$serverName = $server.name

#check to make sure last_disconnect_time isn't null, which it will be for currently connected devices, in which case the lastcheckin variable will be set to today's date
$lastCheckin = Get-Date
if ($server.last_disconnect_time) {
$lastCheckin = [datetime]$server.last_disconnect_time
}


#Calculate time since last checking to now
$span = New-TimeSpan -Start $lastCheckin

#uncomment line below if you want to see all the servers with their last disconnect time and number of days disconnected for troubleshooting
echo "device: $serverName `t last disconnected date: $lastCheckin `t days disconnected: $span.Days"


if ($span.Days -ge $maxDays) {
#Delete or data collection code here

#Delete method takes serverID only
#Hardcoded would look like this $delURI = https://console.automox.com/api/servers/$serverID?o=YOUR_ORG_ID&api_key=YOUR_API_KEY

$toDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnect_time"=$lastCheckin}
$delURI = $apiInstance + $apiTable + '/' + $serverID + $orgAndKey

#Attempt to delete and track failures
try {
#$delResponse = Invoke-WebRequest -UseBasicParsing -Method Delete -Uri $delURI
Write-Output "Successfully Deleted Server: $serverName"
$successDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnectn_time"=$lastCheckin}
}
catch {
$failDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnect_time"=$lastCheckin}
Write-Output "Failed to Delete Server: $serverName"
}
}
#Output logging into json files for later review/manipulation
$toDelete | ConvertTo-Json | Out-File $logPath\ToBeDeleted.json
$successDelete | ConvertTo-Json | Out-File $logPath\Delete_Success.json
$failDelete | ConvertTo-Json | Out-File $logPath\Delete_Failed.json

Unless I’m mistaken, I think it’s the bracket at line 54 (if you include the disclaimer section).


foreach ($server in $servers) {


I’m just not sure where exactly to close it.

Userlevel 7

I used an online diff checker and it looks like the single close (right) bracket on the very last line is missing. You might have done a copy and pasted that accidentally left that out. For anyone who is interested, this is the online diff checker I use:

Oh, it was that very last line. Embarrassing… Thanks for the help!

Userlevel 7

Happy to help and that it was an easy fix! We all need a second set of eyes when we’re stuck in the weeds 🙂

Here’s a version of the script updated for pagination:


#    [-------------------------------------DISCLAIMER-------------------------------------]
# This script is provided as-is with no implicit
# warranty or support. It's always considered a best practice
# to test scripts in a DEV/TEST environment, before running them
# in production.
# Please proceed with caution.
# Do not distribute your API Key to any untrusted 3rd party.
# [-------------------------------------DISCLAIMER-------------------------------------]

# The SETUP section gets your API return and is not specific to any particular use-case.
# The OPERATIONAL section is specific to one scenario and can be overhauled for your specific uses.

############################# SETUP Section #############################

#modify log path as desired
$logPath = 'C:\temp\'

#Easier to maintain, especially if multiple organizations, or for repurposing for different API Tables
$apiInstance = 'https://console.automox.com/api/'
$apiTable = 'servers'
#replace the two variables below with your Org ID and your API key
$orgID = 'YOUR_ORG_ID'
$apiKey = 'YOUR_API_KEY'
$orgAndKey = "?o=$orgID&api_key=$apiKey"
$page = 0

#Number of days disconnected before deleting - adjust to your desired range
$maxDays = 90

#initialize empty arrays to store server IDs to be deleted
$toDelete = @()
$failDelete = @()
$successDelete = @()
$data = @()

#put components together
$getURI = $apiInstance + $apiTable + $orgAndKey + $query

#Get the json body of the Web Request
while($true) {
$uri = "https://console.automox.com/api/servers?o=$orgID&api_key=$apiKey&l=500&p=$page"
$resp = (Invoke-WebRequest -Method GET -Uri $uri).Content | ConvertFrom-Json | Select-Object results
$data += $resp.results

if($resp.results.count -lt 500) {
break
}
$page += 1
}

#Convert to object with manipulatable properties/values
$servers = $data

#Export to C

############################# END Setup Section #############################


############################# OPERATIONAL Section #############################

#Check each server for checkin time, conditionally take action
foreach ($server in $servers) {
#pull out wanted details
$serverID = $server.id
$serverName = $server.name

#check to make sure last_disconnect_time isn't null, which it will be for currently connected devices, in which case the lastcheckin variable will be set to today's date
$lastCheckin = Get-Date
if ($server.last_disconnect_time) {
$lastCheckin = [datetime]$server.last_disconnect_time
}


#Calculate time since last checking to now
$span = New-TimeSpan -Start $lastCheckin

#uncomment line below if you want to see all the servers with their last disconnect time and number of days disconnected for troubleshooting
# echo "device: $serverName `t last disconnected date: $lastCheckin `t days disconnected: $span.Days"


if ($span.Days -ge $maxDays) {
#Delete or data collection code here

#Delete method takes serverID only
#Hardcoded would look like this $delURI = https://console.automox.com/api/servers/$serverID?o=YOUR_ORG_ID&api_key=YOUR_API_KEY

$toDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnect_time"=$lastCheckin}
$delURI = $apiInstance + $apiTable + '/' + $serverID + $orgAndKey

#Attempt to delete and track failures
try {
$delResponse = Invoke-WebRequest -UseBasicParsing -Method Delete -Uri $delURI
Write-Output "Successfully Deleted Server: $serverName"
$successDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnectn_time"=$lastCheckin}
}
catch {
$failDelete += @{"ServerName"=$serverName;"ServerID"=$serverID;"last_disconnect_time"=$lastCheckin}
Write-Output "Failed to Delete Server: $serverName"
}
}
#Output logging into json files for later review/manipulation
$toDelete | ConvertTo-Json | Out-File $logPath\ToBeDeleted.json
$successDelete | ConvertTo-Json | Out-File $logPath\Delete_Success.json
$failDelete | ConvertTo-Json | Out-File $logPath\Delete_Failed.json
}
Userlevel 2
Badge

Sorry for this question, but is the Evaluation Code for this script 0?

Userlevel 7

This is a powershell script that you run locally, rather than a worklet that you push out through Automox. It uses the API key to talk to the console directly and remove the old devices. Save the code as a .ps1 file and then run Powershell filename.ps1 to execute it.

Userlevel 2
Badge

thx

Hi, thanks for this vey useful script. Unfortunately, I do have an issue with it 🤔. I ran this in test mode (remarking out the delete & unmarking the echo) and got a list of machines. As it was first time using, I thought I would compare with an export I had recently made from the device console. I found the script returned less than half the devices in my export (based on older than 90 days). We currently have over 800 devices, could the problem be due to a 500 device limit on the API? If so, could you advise how to adjust the script to capture all the devices? I appreciate your help.


UPDATE: - Oops, just noticed the post from AX-Jon, I’ll take a look. I’m guessing that will fix my problem!

Badge

The first thing I did after copy/paste was to delete the two extra return lines between each line of script.  Reading the comments above, I suspect that the missing curly brace at the end is due to the rhythm of <delete> <delete> arrow down to remove said spaces.  If you do that, the final brace can easily get removed with you noticing it.   Perhaps redo the post without all the extra spacing?

Userlevel 1
Badge

The first thing I did after copy/paste was to delete the two extra return lines between each line of script.  Reading the comments above, I suspect that the missing curly brace at the end is due to the rhythm of <delete> <delete> arrow down to remove said spaces.  If you do that, the final brace can easily get removed with you noticing it.   Perhaps redo the post without all the extra spacing?

Hi Mike,

 

Thanks for your feedback! Please bear in mind that the original post is a little old and we have a newer, more up-to-date guide in our Customer Portal. I’ll link it below for reference. 

Let us know if you see any more improvements we can make in the guide article!

 

Cheers,

Brandon

Reply