|
| 1 | +<# |
| 2 | + .SYNOPSIS |
| 3 | + Removes TeamViewer duplicate devices (MDv2) based on their alias. |
| 4 | +
|
| 5 | + .DESCRIPTION |
| 6 | + Removes TeamViewer devices (MDv2) that have a duplicate counterpart in the same company. |
| 7 | + The script fetches a list of TeamViewer devices (MDv2) of the TeamViewer company that corresponds to a given API token. |
| 8 | + The list will be searched for devices that have the same name (alias). Duplicate devices will be sorted by their last seen timestamp, |
| 9 | + and the older ones will be removed. |
| 10 | +
|
| 11 | + .PARAMETER ApiToken |
| 12 | + The TeamViewer API token to use. |
| 13 | + Must be a user access token. |
| 14 | + The token requires the following access permissions: company admin |
| 15 | +
|
| 16 | + .PARAMETER Force |
| 17 | + If set, the script will NOT ask the user for confirmation of the removal. |
| 18 | + The default value is `false`, causing the script to ask the user one more time before starting to remove devices. |
| 19 | +
|
| 20 | + .EXAMPLE |
| 21 | + Remove-TeamViewerDuplicateDevicesV2' |
| 22 | +
|
| 23 | + .EXAMPLE |
| 24 | + Remove-TeamViewerDuplicateDevicesV2 -WhatIf |
| 25 | +
|
| 26 | + .EXAMPLE |
| 27 | + Remove-TeamViewerDuplicateDevicesV2 -Force |
| 28 | +
|
| 29 | + .NOTES |
| 30 | + This script requires the TeamViewerPS module to be installed. |
| 31 | + This can be done using the following command: |
| 32 | +
|
| 33 | + ``` |
| 34 | + Install-Module TeamViewerPS |
| 35 | + ``` |
| 36 | +
|
| 37 | + Copyright (c) 2019-2024 TeamViewer Germany GmbH |
| 38 | + See file LICENSE |
| 39 | + Version 2.1 |
| 40 | +#> |
| 41 | + |
| 42 | +[CmdletBinding(SupportsShouldProcess = $true)] |
| 43 | +param( |
| 44 | + [Parameter(Mandatory = $true)] |
| 45 | + [securestring] $ApiToken, |
| 46 | + |
| 47 | + [switch] $Force = $false |
| 48 | +) |
| 49 | + |
| 50 | +if (-Not $MyInvocation.BoundParameters.ContainsKey('ErrorAction')) { |
| 51 | + $script:ErrorActionPreference = 'Stop' |
| 52 | +} |
| 53 | +if (-Not $MyInvocation.BoundParameters.ContainsKey('InformationAction')) { |
| 54 | + $script:InformationPreference = 'Continue' |
| 55 | +} |
| 56 | + |
| 57 | +function Install-TeamViewerModule { |
| 58 | + $module = Get-Module TeamViewerPS |
| 59 | + |
| 60 | + if (!$module) { |
| 61 | + Install-Module TeamViewerPS |
| 62 | + } |
| 63 | + elseif ($module.Version -lt '2.1.0') { |
| 64 | + Update-Module TeamViewerPS |
| 65 | + } |
| 66 | +} |
| 67 | + |
| 68 | +function Remove-TeamViewerDuplicateDevicesV2 { |
| 69 | + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] |
| 70 | + param([bool]$force, [bool]$is_verbose) |
| 71 | + |
| 72 | + $devices = @(Get-TeamViewerCompanyManagedDevice -ApiToken $ApiToken) |
| 73 | + |
| 74 | + $name_to_device_map = @{} |
| 75 | + ForEach ($device in $devices) { |
| 76 | + if ($null -eq $name_to_device_map[$device.Name]) { |
| 77 | + $name_to_device_map[$device.Name] = New-Object System.Collections.Generic.List[System.Object] |
| 78 | + } |
| 79 | + $name_to_device_map[$device.Name].Add($device) |
| 80 | + } |
| 81 | + |
| 82 | + $name_to_device_map_sorted = @{} |
| 83 | + $name_to_device_map.GetEnumerator() | ForEach-Object { |
| 84 | + # Sort duplicate devices by LastSeenAt. |
| 85 | + # Older devices should go first. |
| 86 | + $offline_duplicate_devices = @(($_.Value | Where-Object { !$_.IsOnline -and $_.LastSeenAt }) | Sort-Object { $_.LastSeenAt }) |
| 87 | + |
| 88 | + if ($offline_duplicate_devices.Count -gt 0) { |
| 89 | + if ($offline_duplicate_devices.Count -lt $_.Value.Count) { |
| 90 | + # There were some online duplicate devices --> remove all of the offline |
| 91 | + $name_to_device_map_sorted.Add($_.Key, $offline_duplicate_devices) |
| 92 | + } |
| 93 | + else { |
| 94 | + # No online duplicate devices --> the last one is the "good" device --> skip it |
| 95 | + $devices_to_remove = $offline_duplicate_devices | Select-Object -SkipLast 1 |
| 96 | + if ($null -ne $devices_to_remove) { |
| 97 | + $name_to_device_map_sorted.Add($_.Key, $devices_to_remove) |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + if ($is_verbose) { |
| 104 | + Write-Information 'All company devices:' |
| 105 | + Write-Information ($devices | Format-List | Out-String) |
| 106 | + } |
| 107 | + |
| 108 | + if (!$name_to_device_map_sorted.Count) { |
| 109 | + Write-Information 'No duplicate devices found. Exiting...' |
| 110 | + |
| 111 | + exit |
| 112 | + } |
| 113 | + |
| 114 | + Write-Information 'Found the following devices that have a duplicate alias to other devices in your company, and have been offline for longer:' |
| 115 | + Write-Information ($name_to_device_map_sorted | Format-List | Out-String) |
| 116 | + |
| 117 | + if ($name_to_device_map_sorted.Count -gt 0 -And |
| 118 | + !$WhatIfPreference -And |
| 119 | + !$force -And |
| 120 | + !$PSCmdlet.ShouldContinue('Do you really want to remove those devices?', 'Remove managed devices')) { |
| 121 | + Write-Information 'Aborting...' |
| 122 | + |
| 123 | + exit |
| 124 | + } |
| 125 | + |
| 126 | + $name_to_device_map_sorted.GetEnumerator() | ForEach-Object { |
| 127 | + $duplicate_devices_to_be_deleted = $_.Value |
| 128 | + |
| 129 | + ForEach ($device_to_be_deleted in $duplicate_devices_to_be_deleted) { |
| 130 | + $status = 'Unchanged' |
| 131 | + |
| 132 | + if ($force -Or $PSCmdlet.ShouldProcess($device_to_be_deleted.TeamViewerId, 'Remove device')) { |
| 133 | + try { |
| 134 | + Remove-TeamViewerManagedDeviceManagement -ApiToken $ApiToken -Device $device_to_be_deleted |
| 135 | + |
| 136 | + $status = 'Removed' |
| 137 | + } |
| 138 | + catch { |
| 139 | + Write-Warning "Failed to remove device '$($device_to_be_deleted.Name)' with TeamViewerID: '$($device_to_be_deleted.TeamViewerId)'" |
| 140 | + |
| 141 | + $status = 'Failed' |
| 142 | + } |
| 143 | + } |
| 144 | + Write-Output ([pscustomobject]@{ |
| 145 | + Name = $device_to_be_deleted.Name |
| 146 | + ManagementId = $device_to_be_deleted.Id |
| 147 | + LastSeen = $device_to_be_deleted.LastSeenAt |
| 148 | + TeamViewerID = $device_to_be_deleted.TeamViewerId |
| 149 | + Status = $status |
| 150 | + }) |
| 151 | + } |
| 152 | + } |
| 153 | +} |
| 154 | + |
| 155 | +if ($MyInvocation.InvocationName -ne '.') { |
| 156 | + Install-TeamViewerModule |
| 157 | + |
| 158 | + $is_verbose = $PSBoundParameters.ContainsKey('Verbose') |
| 159 | + |
| 160 | + Remove-TeamViewerDuplicateDevicesV2 -force $Force -is_verbose $is_verbose |
| 161 | +} |
0 commit comments