Delete objects with duplicate alias using last_seen attribute

Hi,

Since we are including the Teamviewer agent in our OS-deployment we get duplicate alias when a computer is reinstalled.

I just wrote this script that removes duplicate objects with the same alias and only keeps the most recent object.

I am not the best at writing scripts so please test it and get back here if you think something should be changed.

It only deletes the outer loop object to keep the logic a little bit more simple.

Update with your token

If you want to test it without actually deleting objects you can comment out the following row to see what the end result would be:

Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api/v1/devices/$ID" -Method Delete -Headers $header


#script to identify duplicates alias in Teamviewer and deleting the objects with the oldest last seen timestamp


#define token
$token = "ENTERYOURTOKENHERE"
$bearer = "Bearer",$token


$header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$header.Add("authorization", $bearer)


#Getting all the devices from API
$devices = (Invoke-RestMethod -Uri "Https://webapi.teamviewer.com/api/v1/devices" -Method Get -Headers $header).devices


#Total number of devices
write-host "Total Number of devices" $devices.Count


#Looping through all devices
ForEach($device in $devices)
{
	#Settings variable for device ID
	$ID = $device.device_id
	
	#Setting device last seen variable
	$deviceLastseen = $device.last_seen
	
	#resetting device deleted
	$devicedeleted = $false
	
	#Looping through all devices again to be able to compare each object with all other objects
	ForEach($deviceloop in $devices)
	{
		
		#Only do something if the device is not already delted
		if($devicedeleted -ne $true)
		{
			#Setting inner loop variable for device last seen
			$deviceLastseenloop = $deviceloop.last_seen
			
			#Only do something if last seen values are populated
			if ($deviceLastseen -ne $null -and $deviceLastseenloop -ne $null)
			{
				#Compare other loop device to inner loop device by alias, if they are the same but device ID is not, enter if statement.
				if($device.alias -eq $deviceloop.alias -and $device.device_id -ne $deviceloop.device_id )
				{
					#cleanup date formatting
					$deviceLastseen = ($device.last_seen).Split("T")[0]
					$deviceLastseenloop = ($deviceloop.last_seen).Split("T")[0]
				
					Write-Host "Comparing "$device.alias $deviceLastseen $device.teamviewer_id "to" $deviceloop.alias "|" $deviceLastseenloop "|" $deviceloop.teamviewer_id -ForegroundColor Yellow
				
					#If duplicate found and outer loop device is older delete object
					if($deviceLastseen -lt $deviceLastseenloop)
					{
						#Deleting outer loop device $ID = $device.device_id set above
						Invoke-WebRequest -Uri "Https://webapi.teamviewer.com/api/v1/devices/$ID" -Method Delete -Headers $header
						Write-Host "Deleted device:"$device.alias "|" $deviceLastseen "|" $device.teamviewer_id -ForegroundColor Green
						$count++
						$devicedeleted = $true
					}
				
				}
			}
			#reset last seen value
			$deviceLastseenloop = $null
		}
	}
	#reset last seen value
	$deviceLastseen = $null
	
}


#Total number of delted objects
write-host "Total number of deleted objects" $count
#Reset count
$count = $null


#read devices again
$devices = (Invoke-RestMethod -Uri "Https://webapi.teamviewer.com/api/v1/devices" -Method Get -Headers $header).devices


#Total number of devices
write-host "Total Number of devices" $devices.Count

I take no responsibility for you using this script. Its on your own risk :)

Best regards

Dan

Comments

  • danieljoos
    danieljoos Posts: 6 Staff member 🤠

    Hi Dan,

    Thanks for posting this script.

    If you want, you can simplify this using our open-source TeamViewerPS Powershell module. It is possible to do all that in basically one line of Powershell 😉. However, I've split the line to make it better readable:

    # Install the module, if not already done
    Install-Module TeamViewerPS
    
    # Store the API token in the current Powershell session
    Connect-TeamViewerApi
    
    Get-TeamViewerDevice |   # Get all devices `
      Where-Object { $_.LastSeenAt } |   # Filter for devices with a 'last-seen' date `
      Group-Object -Property Name |      # Group them by device name `
      Where-Object {$_.Count -gt 1} |    # Filter for duplicates `
      ForEach-Object {
        $_.Group | `
        Sort-Object -Property LastSeenAt -Descending | # Sort the duplicate device entries by 'last-seen' (desc) `
        Select-Object -Skip 1 } |                      # Skip the first entry (newest) `
      Remove-TeamViewerDevice -Verbose                 # Remove the rest
    

    You can find more information about the TeamViewerPS Powershell module here:


    Best regards,

    Daniel

  • danisaksson
    danisaksson Posts: 2 ✭✭

    Ok, thanks!

    I learned some stuff creating the script so it was not a total waste :)

    / Dan

  • Mr_BobaBoba
    Mr_BobaBoba Posts: 2 ✭✭

    Hi, When i tried to run the powershell (as admin)

    it said Access token does not have the required permissions for this function


    Where can i generate the api token so that it has the permissions?

  • echapa
    echapa Posts: 9 ✭✭

    Hello @danieljoos @danisaksson

    I tried both scripts on this thread and both seemed to work properly for the devices listed under Groups -> All. However, when I look into Managed Groups -> All (and another group we created for our "Managed Devices") there seem to be a lot more duplicates in there that the scripts are not "finding".

    First I thought this was because they were querying the "/api/v1/devices" endpoint and not the "api/v1/managed/devices" one, but then I switched both scripts to use the "managed devices" endpoint (for the TeamViewerPS module, the command is Get-TeamViewerManagedDevice) and they are returning the same number of devices as the "devices" one, and still not returning the duplicates that I can see under Managed Groups -> All in the portal.

    Any ideas?

    Thanks

    PS. I have a support ticket open for this, but just wondering if you had any clues.

  • echapa
    echapa Posts: 9 ✭✭
    edited August 2022

    Actually just realized both scripts are based on the "Last_seen" attribute that doesn't exist for devices that are online (it may have existed in the past), therefore, if there's a duplicate of an online device it won't be deleted by these scripts because they won't be identified as duplicates.

  • echapa
    echapa Posts: 9 ✭✭

    I've modified @danieljoos's script to take into account Online devices don't have a "last_seen" attribute, I'm going to bet they used to have it before, which is why his script was working fine in the past.

    Provided "As is", use at your own risk - I've commented the deletion line (last line) so you are 100% sure what will be deleted before actually deleting it:

    #Install-Module TeamViewerPS
    $ApiToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    # Store the API token in the current Powershell session
    $Secure = ConvertTo-SecureString $ApiToken -AsPlainText -Force
    
    $devices=Get-TeamViewerDevice -ApiToken $Secure
    $GroupedByName = $devices | Group-Object -Property Name # Filter for devices with a 'last-seen' date
    $GroupedDuplicates = $GroupedByName | Where-Object {$_.Count -gt 1}    # Filter for duplicates
    ForEach ($DuplicateGroup in $GroupedDuplicates) {
    $Duplicates = $DuplicateGroup.Group | Sort-Object -Property OnlineState,LastSeenAt -Descending # Sort the duplicate device entries by OnlineState,'last-seen' (desc)
        $ToDelete = $Duplicates | Select-Object -Skip 1
        $Online = $ToDelete | Where-Object { $_.OnlineState -eq "Online" }
        if ($null -ne $Online) { #abort! online devices found in deletion list
            "Deletion aborted due to online devices found in deletion list"
        } else { #No online devices found in deletion list
            $ToDelete | Select-Object Name,TeamViewerID,LastSeen,OnlineState
            #Uncomment the next line to actually delete duplicates
            #$ToDelete | Remove-TeamViewerDevice -ApiToken $Secure #Remove the rest 
        }
    }
    


  • echapa
    echapa Posts: 9 ✭✭

    I've modified @danieljoos 's script a bit so it takes into account that Online devices don't have a "Last_seen" attribute.

    The script is provided as is, with no warranty. Use at your own risk. I've commented the last line that actually deletes devices, just so that you can take a look at what is actually getting deleted before doing so:

    #Install-Module TeamViewerPS
    $ApiToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    # Store the API token in the current Powershell session
    $Secure = ConvertTo-SecureString $ApiToken -AsPlainText -Force
    
    $devices=Get-TeamViewerDevice -ApiToken $Secure
    $GroupedByName = $devices | Group-Object -Property Name # Filter for devices with a 'last-seen' date
    $GroupedDuplicates = $GroupedByName | Where-Object {$_.Count -gt 1}    # Filter for duplicates
    ForEach ($DuplicateGroup in $GroupedDuplicates) {
        $Duplicates = $DuplicateGroup.Group | Sort-Object -Property OnlineState,LastSeenAt -Descending # Sort the duplicate device entries by OnlineState,'last-seen' (desc)
        $ToDelete = $Duplicates | Select-Object -Skip 1
        $Online = $ToDelete | Where-Object { $_.OnlineState -eq "Online" }
        if ($null -ne $Online) { #abort! online devices found in deletion list
            "Deletion aborted due to online devices found in deletion list"
        } else { #No online devices found in deletion list
            $ToDelete | Select-Object Name,TeamViewerID,LastSeen
            #Uncomment the next line to actually delete duplicates
            #$ToDelete | Remove-TeamViewerDevice -ApiToken $Secure #Remove the rest 
        }
    }
    
  • Btowns
    Btowns Posts: 2 ✭✭

    I switched the script to look at managed devices since that's what we're using in our environment. Unfortunately it looks like the managed/device endpoint doesn't return last_seen. Also, it looks like devices that are managed don't appear in the standard devices list so I'm thinking there's no way to get the last time online to decide which of the duplicates to remove. The only thing I can think of is to delete offline duplicates when one in the duplicate group is online.

    Here's all that I'm getting back from https://webapi.teamviewer.com/api/v1/managed/devices.

    "id": "00000000-0000-0000-0000-0000000000",
    "teamviewerId": 12345678,
    "name": "SDJFN123213",
    "isOnline": false
    

    Is there something I'm missing?

  • echapa
    echapa Posts: 9 ✭✭

    @Btowns you are correct, the managed devices endpoint doesn't provide a way which record is newer or the "current" one, unless one of them is online. Thanks for pointing this out, adding this to the reasons why we aren't using managed groups at the moment.

  • bstingl
    bstingl Posts: 1 Newbie

    Its updated now for managed device groups:

    https://webapi.teamviewer.com/api/v1/docs/index#!/Managed32Groups/ManagedDevices_Get

    {

    "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

    "teamviewerId": xxxxxxxxxxxxx,

    "name": "xxxxxxxxxxxxxxxxxxx",

    "isOnline": false,

    "last_seen": "2023-05-14T17:30:00Z"

    }