-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Remove-TeamViewerDuplicateDevicesV2 example script
The script searches for duplicate devices (where duplicate = have the same alias) and removes the devices with an older last-seen timestamp. Resolves JIRA task TEAM-60324.
- Loading branch information
1 parent
9b21a8e
commit ec720fa
Showing
3 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
50 changes: 50 additions & 0 deletions
50
Remove-TeamViewerDuplicateDevicesV2/Remove-TeamViewerDuplicateDevicesV2.Tests.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
161 changes: 161 additions & 0 deletions
161
Remove-TeamViewerDuplicateDevicesV2/Remove-TeamViewerDuplicateDevicesV2.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |