Skip to content

Commit

Permalink
Merge pull request #30 from teamviewer/TEAM-60324_add_cleanup_duplica…
Browse files Browse the repository at this point in the history
…te_devices_script

Added Remove-TeamViewerDuplicateDevicesV2 example script
  • Loading branch information
AchilleasMitos-TV authored Nov 26, 2024
2 parents 9b21a8e + ec720fa commit b07790a
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 0 deletions.
44 changes: 44 additions & 0 deletions Remove-TeamViewerDuplicateDevicesV2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Remove-TeamViewerDuplicateDevicesV2

Removes TeamViewer devices (MDv2) that have a duplicate counterpart in the same company.

The script fetches a list of TeamViewer devices (MDv2) of the TeamViewer company that corresponds to a given API token.
The list will be searched for devices that have the same name (alias). Duplicate devices will be sorted by their last seen timestamp,
and the older ones will be removed.

## Prerequisites

This script requires the `TeamViewerPS` powershell module to be installed in at least Version 2.1.0.

```powershell
Install-Module TeamViewerPS
```

## Examples

### List removal candidate devices

```powershell
Remove-TeamViewerDuplicateDevicesV2 -WhatIf
```

### Remove old duplicate devices. User needs to confirm

```powershell
Remove-TeamViewerDuplicateDevicesV2
```

### Remove old duplicate devices without further confirmation

```powershell
Remove-TeamViewerDuplicateDevicesV2 -Force
```

## More help

To get further help about the script and its parameters, execute the
`Get-Help` PowerShell cmdlet:

```powershell
Get-Help -Detailed .\Remove-TeamViewerDuplicateDevicesV2.ps1
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (c) 2019-2024 TeamViewer Germany GmbH
# See file LICENSE

BeforeAll {
$testApiToken = [securestring]@{}

. "$PSScriptRoot\Remove-TeamViewerDuplicateDevicesV2.ps1" -ApiToken $testApiToken -InformationAction SilentlyContinue

Mock Get-TeamViewerCompanyManagedDevice { @(
[pscustomobject]@{ TeamViewerId = '123456789'; Name = 'unique device'; LastSeenAt = [datetime]'2024-12-16' },
[pscustomobject]@{ TeamViewerId = 'older device A'; Name = 'duplicate device A'; LastSeenAt = [datetime]'2024-12-17' },
[pscustomobject]@{ TeamViewerId = 'online device A'; Name = 'duplicate device A'; IsOnline = $True },
[pscustomobject]@{ TeamViewerId = 'newer device B'; Name = 'duplicate device B'; LastSeenAt = [datetime]'2024-12-18' },
[pscustomobject]@{ TeamViewerId = 'newer device A'; Name = 'duplicate device A'; LastSeenAt = [datetime]'2024-12-19' },
[pscustomobject]@{ TeamViewerId = 'older device B'; Name = 'duplicate device B'; LastSeenAt = [datetime]'2024-12-17' }
) }

Mock Remove-TeamViewerManagedDeviceManagement -RemoveParameterValidation 'Device' {}
}

Describe 'Remove-TeamViewerDuplicateDevicesV2' {

It 'Should not remove any devices if -WhatIf parameter has been set' {
$result = (Remove-TeamViewerDuplicateDevicesV2 -force:$false -WhatIf)
$result | Should -HaveCount 3
$result[0].TeamViewerId | Should -Be 'older device A'
$result[0].Status | Should -Be 'Unchanged'
$result[1].TeamViewerId | Should -Be 'newer device A'
$result[1].Status | Should -Be 'Unchanged'
$result[2].TeamViewerId | Should -Be 'older device B'
$result[2].Status | Should -Be 'Unchanged'

Assert-MockCalled Get-TeamViewerCompanyManagedDevice -Times 1 -Scope It
Assert-MockCalled Remove-TeamViewerManagedDeviceManagement -Times 0 -Scope It
}

It 'Should remove duplicate devices with an older last-seen timestamp' {
$result = (Remove-TeamViewerDuplicateDevicesV2 -force:$true)
$result | Should -HaveCount 3
$result[0].TeamViewerId | Should -Be 'older device A'
$result[0].Status | Should -Be 'Removed'
$result[1].TeamViewerId | Should -Be 'newer device A'
$result[1].Status | Should -Be 'Removed'
$result[2].TeamViewerId | Should -Be 'older device B'
$result[2].Status | Should -Be 'Removed'

Assert-MockCalled Get-TeamViewerCompanyManagedDevice -Times 1 -Scope It
Assert-MockCalled Remove-TeamViewerManagedDeviceManagement -Times 3 -Scope It
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<#
.SYNOPSIS
Removes TeamViewer duplicate devices (MDv2) based on their alias.
.DESCRIPTION
Removes TeamViewer devices (MDv2) that have a duplicate counterpart in the same company.
The script fetches a list of TeamViewer devices (MDv2) of the TeamViewer company that corresponds to a given API token.
The list will be searched for devices that have the same name (alias). Duplicate devices will be sorted by their last seen timestamp,
and the older ones will be removed.
.PARAMETER ApiToken
The TeamViewer API token to use.
Must be a user access token.
The token requires the following access permissions: company admin
.PARAMETER Force
If set, the script will NOT ask the user for confirmation of the removal.
The default value is `false`, causing the script to ask the user one more time before starting to remove devices.
.EXAMPLE
Remove-TeamViewerDuplicateDevicesV2'
.EXAMPLE
Remove-TeamViewerDuplicateDevicesV2 -WhatIf
.EXAMPLE
Remove-TeamViewerDuplicateDevicesV2 -Force
.NOTES
This script requires the TeamViewerPS module to be installed.
This can be done using the following command:
```
Install-Module TeamViewerPS
```
Copyright (c) 2019-2024 TeamViewer Germany GmbH
See file LICENSE
Version 2.1
#>

[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $true)]
[securestring] $ApiToken,

[switch] $Force = $false
)

if (-Not $MyInvocation.BoundParameters.ContainsKey('ErrorAction')) {
$script:ErrorActionPreference = 'Stop'
}
if (-Not $MyInvocation.BoundParameters.ContainsKey('InformationAction')) {
$script:InformationPreference = 'Continue'
}

function Install-TeamViewerModule {
$module = Get-Module TeamViewerPS

if (!$module) {
Install-Module TeamViewerPS
}
elseif ($module.Version -lt '2.1.0') {
Update-Module TeamViewerPS
}
}

function Remove-TeamViewerDuplicateDevicesV2 {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
param([bool]$force, [bool]$is_verbose)

$devices = @(Get-TeamViewerCompanyManagedDevice -ApiToken $ApiToken)

$name_to_device_map = @{}
ForEach ($device in $devices) {
if ($null -eq $name_to_device_map[$device.Name]) {
$name_to_device_map[$device.Name] = New-Object System.Collections.Generic.List[System.Object]
}
$name_to_device_map[$device.Name].Add($device)
}

$name_to_device_map_sorted = @{}
$name_to_device_map.GetEnumerator() | ForEach-Object {
# Sort duplicate devices by LastSeenAt.
# Older devices should go first.
$offline_duplicate_devices = @(($_.Value | Where-Object { !$_.IsOnline -and $_.LastSeenAt }) | Sort-Object { $_.LastSeenAt })

if ($offline_duplicate_devices.Count -gt 0) {
if ($offline_duplicate_devices.Count -lt $_.Value.Count) {
# There were some online duplicate devices --> remove all of the offline
$name_to_device_map_sorted.Add($_.Key, $offline_duplicate_devices)
}
else {
# No online duplicate devices --> the last one is the "good" device --> skip it
$devices_to_remove = $offline_duplicate_devices | Select-Object -SkipLast 1
if ($null -ne $devices_to_remove) {
$name_to_device_map_sorted.Add($_.Key, $devices_to_remove)
}
}
}
}

if ($is_verbose) {
Write-Information 'All company devices:'
Write-Information ($devices | Format-List | Out-String)
}

if (!$name_to_device_map_sorted.Count) {
Write-Information 'No duplicate devices found. Exiting...'

exit
}

Write-Information 'Found the following devices that have a duplicate alias to other devices in your company, and have been offline for longer:'
Write-Information ($name_to_device_map_sorted | Format-List | Out-String)

if ($name_to_device_map_sorted.Count -gt 0 -And
!$WhatIfPreference -And
!$force -And
!$PSCmdlet.ShouldContinue('Do you really want to remove those devices?', 'Remove managed devices')) {
Write-Information 'Aborting...'

exit
}

$name_to_device_map_sorted.GetEnumerator() | ForEach-Object {
$duplicate_devices_to_be_deleted = $_.Value

ForEach ($device_to_be_deleted in $duplicate_devices_to_be_deleted) {
$status = 'Unchanged'

if ($force -Or $PSCmdlet.ShouldProcess($device_to_be_deleted.TeamViewerId, 'Remove device')) {
try {
Remove-TeamViewerManagedDeviceManagement -ApiToken $ApiToken -Device $device_to_be_deleted

$status = 'Removed'
}
catch {
Write-Warning "Failed to remove device '$($device_to_be_deleted.Name)' with TeamViewerID: '$($device_to_be_deleted.TeamViewerId)'"

$status = 'Failed'
}
}
Write-Output ([pscustomobject]@{
Name = $device_to_be_deleted.Name
ManagementId = $device_to_be_deleted.Id
LastSeen = $device_to_be_deleted.LastSeenAt
TeamViewerID = $device_to_be_deleted.TeamViewerId
Status = $status
})
}
}
}

if ($MyInvocation.InvocationName -ne '.') {
Install-TeamViewerModule

$is_verbose = $PSBoundParameters.ContainsKey('Verbose')

Remove-TeamViewerDuplicateDevicesV2 -force $Force -is_verbose $is_verbose
}

0 comments on commit b07790a

Please sign in to comment.