Remove inactive computers
I'm using TeamViewer 13 Corporate, and I've been using it for several years now.
Many of the computers in our organization have been retired or changed out, but the naming convention for TeamViewer computer is the same for all of our users regarless if they've had one, two, three or even a hundred computers assigned to them. Is it possible to add a feature that would allow you to search for computers that have been offline for a cetain time frame, like two or three moths for example? Then from that list, be able to do a bulk delete? I'm aware that the bulk delete has been asked for in many other posts as well, and it makes no sense to me that this feature would not be available by design.
Also, there are many computers listed in "Unnamed devices" folder, for one time connects I've used in the past, is there no way I can delete these from my system as well? I'm just trying to make my console clean and relevant, but you guys seem to be tying our hands with these basic functions by only permitting us to delete computers one at a time.
I would apreciate any response from TeamViewer staff on this matter.
Thank you
Best Answers
-
I was running into this same problem but wasn't satisfied with the workaround provided. I spend countless hours trying to automate any and everything so this was right up my alley.
It will delete any device that hasn't been seen in the last 30 days. Just insert your API Token in the $token variable and you'll be good to go.
Hope this helps all the fellow admins.
$token = "INSERTYOURAPITOKENHERE"
$bearer = "Bearer",$token
$header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$header.Add("authorization", $bearer)
$devices = (Invoke-RestMethod -Uri "Https://webapi.teamviewer.com/api/v1/devices" -Method Get -Headers $header).devices
$30Days = ((Get-Date).AddDays(-30)).GetDateTimeFormats()[5]
ForEach($device in $devices)
{
if ($device.online_state -eq "Offline")
{
$ID = $device.device_id
$Lastseen = $device.last_seen
if ($Lastseen -ne $null)
{
$LastSeen = ($device.last_seen).Split("T")[0]
[datetime]$DateLastSeen = $LastSeen
if ($DateLastSeen -le $30Days)
{
Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api/v1/devices/$ID" -Method Delete -Headers $header
Write-Host "Deleted device:"$device.alias -ForegroundColor Yellow
}$Lastseen = $null
}
}
}8 -
@roryschmitz Design and Deploy won't be the correct API token. I actually just use the same API Token I use for my Full Version installer but if you don't already have that just follow these steps to create one:
1. When you are logged in click your Profile in the top right then click Edit Profile.
2. Click the Apps tab on the left and then create a new script token.
3. Change Group Management to "View, create, delete, edit and share groups"
4. Change Computers & Contacts to "View, add, edit and delete entries"
5. Click Save then copy your API Token into the script.
6
Answers
-
We would also very much like the feature to bulk remove retired computers. We recently reinstalled 4000 units with Windows 10, thus reinstalling teamviewer. Now, they alle are doubled in the console.
3 -
I was running into this same problem but wasn't satisfied with the workaround provided. I spend countless hours trying to automate any and everything so this was right up my alley.
It will delete any device that hasn't been seen in the last 30 days. Just insert your API Token in the $token variable and you'll be good to go.
Hope this helps all the fellow admins.
$token = "INSERTYOURAPITOKENHERE"
$bearer = "Bearer",$token
$header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$header.Add("authorization", $bearer)
$devices = (Invoke-RestMethod -Uri "Https://webapi.teamviewer.com/api/v1/devices" -Method Get -Headers $header).devices
$30Days = ((Get-Date).AddDays(-30)).GetDateTimeFormats()[5]
ForEach($device in $devices)
{
if ($device.online_state -eq "Offline")
{
$ID = $device.device_id
$Lastseen = $device.last_seen
if ($Lastseen -ne $null)
{
$LastSeen = ($device.last_seen).Split("T")[0]
[datetime]$DateLastSeen = $LastSeen
if ($DateLastSeen -le $30Days)
{
Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api/v1/devices/$ID" -Method Delete -Headers $header
Write-Host "Deleted device:"$device.alias -ForegroundColor Yellow
}$Lastseen = $null
}
}
}8 -
@KyleHoneycutt Brilliant! Is this just a powershell cmdlet or do we run this from somewhere else?
0 -
@roryschmitz Indeed it's in PowerShell.
Hope you enjoy!
0 -
@KyleHoneycutt Thanks, I'm getting the following errors when it's running through the script. It appears to find all of the stale comptures out there, but is this error pops up for each machines:
Invoke-WebRequest : {"error":"invalid_token","error_description":"Access token does not have the required permissions
for this function.","error_code":2}
At C:\Downloads\TV_Cleanup.ps1:30 char:21
+ ... Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc
eption
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Deleted device: COMPUTERNAMEUnsure why the access token wouldn't have the required permissions? We only have the one token that I set up. Maybe I'm not using the correct API token, but I just copied it from the Design & Deploy area in the web admin. It's the one under custom TV Host package I created. Is that the correct token?
0 -
@roryschmitz Design and Deploy won't be the correct API token. I actually just use the same API Token I use for my Full Version installer but if you don't already have that just follow these steps to create one:
1. When you are logged in click your Profile in the top right then click Edit Profile.
2. Click the Apps tab on the left and then create a new script token.
3. Change Group Management to "View, create, delete, edit and share groups"
4. Change Computers & Contacts to "View, add, edit and delete entries"
5. Click Save then copy your API Token into the script.
6 -
@KyleHoneycutt That worked! You're a life saver and I really appreciate it.
0 -
@roryschmitzMy pleasure, glad I could help!
0 -
@KyleHoneycutt I ended up posting your great solution over at the Spiceworks forums as well and linked back to here. Hope that is OK? If there's a way I can buy you a beer or two, please let me know.
Here's the discussion link: [The URL link has been removed by a moderator.]
0 -
@roryschmitz Perfectly fine with me, spread it around as much as you wish! If you're ever in the Dallas area hit me up and we can definitely have a few beers. Cheers!
0 -
Hi there!
Thanks a lot for providing a solution here.. :-)
I am having another issue though, regarding the comparison of the dates. I'm trying to clean out devices not seen in a year, so i modified the script to use '360' instead of '30', but i don't think that is the issue - the problem is the time/date formats. I get a lot of this error (in danish):
Could not compare "03/21/2018 00:00:00" to "søndag den 11. marts 2018". Error: "Cannot convert value "søndag den 11. marts 2018" to type "System.DateTime". Error: "Strengen blev ikke genkendt som en gyldig DateTime. Der er et ukendt ord, der starter ved indekset 0.""
At C:\Users\adm_ianfje\Documents\TeamViewer_Cleanup_Inactive_Computers_Script.ps1:31 char:25
+ if ($DateLastSeen -le $360Days)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : ComparisonFailureI am totally new at powershell scripting, so i got no clue how to fix this. Please help. :-)
0 -
I'm not a PS expert either, but as a quick test, I modified this line:
$30Days = ((Get-Date).AddDays(-30)).GetDateTimeFormats()[5]
to this:
$30Days = ((Get-Date).AddDays(-365)).GetDateTimeFormats()[5]
and I did not receive any errors. That could also be due to mine not finding any machines older than 365 days as I just removed everything older than 30 days. It's a little messy, but it might be a quick test. There shouldn't be any reason you couldn't replace '30' with '365' throughout the script.
0 -
@IanFriis Hey Ian,
I'm not sure if PowerShell can convert the Danish language into a System.DateTime Object which is why you're getting that error.
The way the script works is that it gets the date string from TeamViewer and then converts that string into a DateTime object so that it can be used as a comparison operator. Without converting it, it can't compare correctly.
I think the easiest thing for you to do would be to change your local system language to English or run the Script on a server that has English as the OS language.
If that workaround isn't feasible for you just let me know and we can try to come up with another solution for you.
0 -
@KyleHoneycutt @roryschmitz thank you for replying
I solved the problem by setting my system language to english on the computer running the script. After a reboot the script ran without errors!
Great to finally see those outdated computers removed from our list.
Thanks again - have a great day!
1 -
Hi Kyle, we are getting the same error as Ian. Our system runs in german language and we would like to keep it that way. The error we receive is:
Could not compare "03/13/2019 00:00:00" to "19.9.2018". Error: "Cannot convert value "19.9.2018" to type "System.DateTime".
i tried a little bit with converting the format but i didn´t manage to get this script running.
Thanks in advance,
Thomas
0 -
This was a great help. I decided to recreate this in Python 3. If anyone is interested, let me know!
0 -
Hi,
Not sure if it still relevant but i had the same issue with the German format on my Win10 device, and after changing to the English (United states) formats the script was working correctly.
0 -
Hi @Closed account
How can I run this script? sorry i'm not good with technolgy
For the home studio
0 -
Thanks for the script I modified it so it works and all languages (I think)
Example of running the script Delete-staledevices.ps1 -token "Apikey" -staledays 150[CmdletBinding()]
param(
[Parameter(Mandatory=$True)] [int32]$StaleDays,
[Parameter(Mandatory=$True)] [String] $Token = ""
)
$bearer = "Bearer",$token
$counter = 0
$header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$header.Add("authorization", $bearer)
$devices = (Invoke-RestMethod -Uri "Https://webapi.teamviewer.com/api/v1/devices" -Method Get -Headers $header).devices
$Days = ((Get-Date).AddDays(-$staleDays))
$Days = Get-Date $Days -Format s
ForEach($device in $devices)
{
if ($device.online_state -eq "Offline")
{
$ID = $device.device_id
$Lastseen = $device.last_seen
if ($Lastseen -ne $null)
{
$LastSeen = ($device.last_seen).Split("T")[0]
[datetime]$DateLastSeen = $LastSeen
if ($DateLastSeen -le $Days)
{
$counter ++
Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api/v1/devices/$ID" -Method Delete -Headers $header -UseBasicParsing
Write-Host "Deleted device:"$device.alias $counter -ForegroundColor Yellow
}$Lastseen = $null
}
}
}0 -
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)] [int32]$StaleDays,
[Parameter(Mandatory=$True)] [String] $Token = ""
)
$bearer = "Bearer",$token
$counter = 0
$header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$header.Add("authorization", $bearer)
$devices = (Invoke-RestMethod -Uri "Https://webapi.teamviewer.com/api/v1/devices" -Method Get -Headers $header).devices
$Days = ((Get-Date).AddDays(-$staleDays))
$Days = Get-Date $Days -Format s
ForEach($device in $devices)
{
if ($device.online_state -eq "Offline")
{
$ID = $device.device_id
$Lastseen = $device.last_seen
if ($Lastseen -ne $null)
{
$LastSeen = ($device.last_seen).Split("T")[0]
[datetime]$DateLastSeen = $LastSeen
if ($DateLastSeen -le $Days)
{
$counter ++
Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api/v1/devices/$ID" -Method Delete -Headers $header -UseBasicParsing
Write-Host "Deleted device:"$device.alias $counter -ForegroundColor Yellow
}$Lastseen = $null
}
}
}Nice the this script work perfectly in German !!!
thx !!!
0 -
Thanks for the script. How can I apply this on our teamviewer environment?
Many thanks!
0 -
Save the Above Script in Name Like "TeamViewerDeleteMachines_olderX_Days.ps1"
simply start CMD run this command with AdminRights
powershell "PATHtoYOURpowershellScript\TeamViewerDeleteMachines_olderX_Days.ps1" -token YOURTOKENfromTeamVIEWER -staledays 60
The -staledays 60 stands for the Days you want to delete
1 -
Perfect, this is working! Can I schedule this script on my teamviewer environment?
1 -
Yes, you can schedule this. I run a scheduled task every day to clear out the stale machines. It keeps things tidy and manageable.
0 -
Brilliant, worked like a charm!
1 -
I've just tried to run this and I'm finding that the returned object does not contain the last_seen attribute
Anybody else seen this or have any ideas?
0 -
Sorted my own issue. If a device is currently online, the last_seen attribute is not returned
Seems that if you export an array of objects to a csv, it determines the field headers from the first array object.
0 -
question is it possible to filter out with groups?
other question we are using vdi envirmont and on all the clients there is a teamvieuwer application running. But when the user end of the day close the vdi new vdi with same id will be created automaticly . And in teamvieuwer then I see 2 the same id only 1 is offline 1 is online. Any solution to this?
0 -
Our machines do no appear in the "Groups" section on the site. They are under "Device Groups" instead. The means it uses https://webapi.teamviewer.com/api/v1/managed/devices
I've been bouncing around chatgpt and gemini to create a script that removes devices not seen in the last 90 days so excuse the syntax if it's a little long winded but it does the trick. I'm going to leave this on a sever running via task scheduler so I wanted it to log which machines are being deleted.
$token = "TOKENID" # Replace with your actual token $bearer = "Bearer " + $token $inactiveThreshold = (New-TimeSpan -Seconds (86400 * 90)).TotalMilliseconds # 90 days in milliseconds $currentTime = Get-Date $deletedDevices = @() # Array to store deleted device information $csvPath = "C:\logs\tvdeleteddevices.csv" $header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $header.Add("authorization", $bearer) # Function to delete a device function Remove-TeamViewerDevice { param ( [Parameter(Mandatory=$true)] [string] $deviceId, [string] $deviceName, [string] $lastSeen ) $managedDevicesUri = "https://webapi.teamviewer.com/api/v1/managed/devices/$deviceId" try { Invoke-RestMethod -Uri $managedDevicesUri -Method Delete -Headers $header Write-Host "Device $deviceId deleted successfully." $deviceObject = New-Object PSObject -Property @{ "Device ID" = $deviceId "Device Name" = $deviceName "Last Seen" = $lastSeen } return $deviceObject } catch { Write-Host "Error deleting device ${deviceId}: " -NoNewline Write-Host $_.Exception.Message return $null } } # Initial call for devices try { $managedDevicesUri = "https://webapi.teamviewer.com/api/v1/managed/devices" $response = Invoke-RestMethod -Uri $managedDevicesUri -Method Get -Headers $header if ($response.resources -ne $null) { foreach ($device in $response.resources) { $deviceName = $device.name $lastSeen = if ($device.last_seen -ne $null) {[DateTime]::Parse($device.last_seen).ToString("yyyy-MM-dd HH:mm:ss")} else {"Never"} # Skip online devices and devices with missing Last Seen if ($device.isOnline -eq $true -or $device.last_seen -eq $null) { continue } # Check if the device is inactive if (($currentTime - [DateTime]::Parse($device.last_seen)).TotalMilliseconds -gt $inactiveThreshold) { $deletedDevice = Remove-TeamViewerDevice -deviceId $device.id -deviceName $deviceName -lastSeen $lastSeen if ($deletedDevice -ne $null) { $deletedDevices += $deletedDevice } } } # Handle pagination if a nextPaginationToken is provided (optional) # ... (similar logic as before) } else { Write-Host "No devices found or empty response." } } catch { Write-Host "Error retrieving devices: $($_.Exception.Message)" } # Export deletedDevices array to CSV (if any) if ($deletedDevices.Count -gt 0) { $deletedDevices | Select-Object 'Device ID', 'Device Name', 'Last Seen' | Export-Csv -Path $csvPath -NoTypeInformation -Append Write-Host "Deleted devices list exported to $csvPath" } else { Write-Host "No devices were deleted based on the current settings." }
0