Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Change Log


## 2.5.0 (2026-02-11)

### Updated

- Updates `Get-TeamViewerRole` to list all the possible permissions
- Updates `Set-TeamViewerManagedDevice` with additional description endpoint

### Added

- Adds `Get-TeamViewerInstallationType` that returns the TV installation type (MSI, exe or Unknown) from locally installed TV client
- Adds `Get-TeamViewerRoleByUser` that returns the assigned role ids of the user
- Adds `Get-TeamViewerEffectivePermission` that lists all effective permissions in a TeamViewer company
- Adds new endpoint ID for function `Get-TeamViewerSsoDomain`


## 2.4.0 (2025-06-19)

### Added
Expand Down
82 changes: 82 additions & 0 deletions Cmdlets/Public/Get-TeamViewerInstallationType.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
function Get-TeamViewerInstallationType {

[CmdletBinding()]
[OutputType([string])]
param()

$regPath = 'HKLM:\SOFTWARE\TeamViewer'
$regPathWow = 'HKLM:\SOFTWARE\WOW6432Node\TeamViewer'
$MsiDatabaseFound = $false
$MsiRegistryValueFound = $false



#first check MSI database
try {
$MsiProduct = Get-CimInstance -ClassName Win32_Product -Filter "Name='TeamViewer'" -ErrorAction Stop
if ($MsiProduct) {
$MsiDatabaseFound = $true
}
}
catch {
Write-Verbose "MSI database check failed or TeamViewer not found via WMI"
}

#check MsiInstallation value
foreach ($path in @($regPath, $regPathWow)) {
try {
$MsiInstallationValue = Get-ItemProperty -Path $path -Name 'MsiInstallation' -ErrorAction Stop

if ($null -ne $MsiInstallationValue.MsiInstallation -and $MsiInstallationValue.MsiInstallation -eq 1) {
$MsiRegistryValueFound = $true
break
}
}
catch [System.Management.Automation.ItemNotFoundException] {
Write-Verbose "TeamViewer registry path not found: $path"
}
catch {
Write-Verbose "registry check for MsiInstallation failed at $path"
}
}

if ($MsiDatabaseFound -and $MsiRegistryValueFound) {
return 'MSI'
}

#check for exeInstallation
try {
$uninstallPaths = @(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall',
'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
)

foreach ($uninstallPath in $uninstallPaths) {
if (Test-Path -Path $uninstallPath) {
$teamViewerKey = Get-ChildItem -Path $uninstallPath -ErrorAction SilentlyContinue |
Where-Object { $_.GetValue('DisplayName') -like '*TeamViewer*' }

if ($teamViewerKey) {
$uninstallValue = Get-ItemProperty -Path $teamViewerKey.PSPath -Name 'UninstallString' -ErrorAction SilentlyContinue
if ($uninstallValue -and $uninstallValue.UninstallString) {
#extract the executable path using regex
$uninstallFile = $uninstallValue.UninstallString -replace '^"?([^"]+)"?.*$', '$1'
$uninstallFile = $uninstallFile.Trim('"')
#verify if it's a file and if it exists
if (Test-Path -Path $uninstallFile -PathType Leaf) {
return 'exe'
}
else {
return 'Unknown'
}
}
}
}
}
}
catch {
Write-Verbose "Error checking UninstallString"
}

return 'Unknown'
}
2 changes: 1 addition & 1 deletion Cmdlets/TeamViewerPS.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
RootModule = 'TeamViewerPS.psm1'

# Version number of this module.
ModuleVersion = '2.4.0'
ModuleVersion = '2.5.0'

# Supported PSEditions.
# CompatiblePSEditions = @()
Expand Down
53 changes: 53 additions & 0 deletions Docs/Help/Get-TeamViewerInstallationType.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
external help file: TeamViewerPS-help.xml
Module Name: TeamViewerPS
online version: https://github.com/teamviewer/TeamViewerPS/blob/main/Docs/Help/Get-TeamViewerInstallationType.md
schema: 2.0.0
---

# Get-TeamViewerInstallationType

## SYNOPSIS

Returns the TeamViewer installation type.

## SYNTAX

```powershell
Get-TeamViewerInstallationType
```

## DESCRIPTION

The command checks the TeamViewer installation and returns the installation type (MSI or exe) and $null when it could not be determined.

## EXAMPLES

### Example 1

```powershell
PS /> Get-TeamViewerInstallationType
```

Returns the installation type of TeamViewer (MSI, exe or Unknown).

## PARAMETERS

### CommonParameters

### None

## INPUTS

### None

## OUTPUTS

### System.String

Returns a string indicating the installation type: "MSI", "exe", or "Unknown".

## NOTES

## RELATED LINKS

2 changes: 2 additions & 0 deletions Docs/TeamViewerPS.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ The following functions are available in this category:

[`Get-TeamViewerId`](Help/Get-TeamViewerId.md)

[`Get-TeamViewerInstallationType`](Help/Get-TeamViewerInstallationType.md)

[`Get-TeamViewerService`](Help/Get-TeamViewerService.md)

[`Get-TeamViewerVersion`](Help/Get-TeamViewerVersion.md)
Expand Down
220 changes: 220 additions & 0 deletions Tests/Public/Get-TeamViewerInstallationType.Tests.ps1
Comment thread
stefanhubertus marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
BeforeAll {
. "$PSScriptRoot\..\..\Cmdlets\Public\Get-TeamViewerInstallationType.ps1"
@(Get-ChildItem -Path "$PSScriptRoot\..\..\Cmdlets\Private\*.ps1") | `
ForEach-Object { . $_.FullName }
}

Describe 'Get-TeamViewerInstallationType' {
Context 'MsiInstallation - both database and registry present' {
BeforeAll {
Mock Get-CimInstance {
[PSCustomObject]@{ Name = 'TeamViewer' }
}
Mock Get-ItemProperty {
[PSCustomObject]@{ MsiInstallation = 1 }
}
}

It 'Should return MSI when MSI database and MsiInstallation registry value are both present' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'MSI'
Assert-MockCalled Get-CimInstance -Times 1
}
}

Context 'MSI database found but no registry value' {
BeforeAll {
Mock Get-CimInstance {
[PSCustomObject]@{ Name = 'TeamViewer' }
}
Mock Get-ItemProperty {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
}

It 'Should not return MSI if only database entry exists' {
$result = Get-TeamViewerInstallationType
$result | Should -Not -Be 'MSI'
}
}

Context 'Registry value found but no MSI database entry' {
BeforeAll {
Mock Get-CimInstance {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ItemProperty {
[PSCustomObject]@{ MsiInstallation = 1 }
}
}

It 'Should not return MSI if only registry value exists' {
$result = Get-TeamViewerInstallationType
$result | Should -Not -Be 'MSI'
}
}

Context 'exeInstallation with valid UninstallString' {
BeforeAll {
Mock Get-CimInstance {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ItemProperty {
throw [System.Management.Automation.ItemNotFoundException]::new()
} -ParameterFilter { $Name -eq 'MsiInstallation' }
Mock Test-Path { $true }
Mock Get-ChildItem {
$registryKey = New-Object PSObject
$registryKey | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'TeamViewer'
$registryKey | Add-Member -MemberType NoteProperty -Name 'PSPath' -Value 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\TeamViewer'
$registryKey | Add-Member -MemberType ScriptMethod -Name 'GetValue' -Value { return 'TeamViewer' }
$registryKey
}
Mock Get-ItemProperty {
[PSCustomObject]@{
UninstallString = '"C:\Program Files\TeamViewer\uninstall.exe" /S'
}
} -ParameterFilter { $Name -eq 'UninstallString' }
}

It 'Should return exe when UninstallString file exists' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'exe'
}
}

Context 'Broken exeInstallation with missing UninstallString file' {
BeforeAll {
Mock Get-CimInstance {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ItemProperty {
throw [System.Management.Automation.ItemNotFoundException]::new()
} -ParameterFilter { $Name -eq 'MsiInstallation' }
Mock Get-ChildItem {
$registryKey = New-Object PSObject
$registryKey | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'TeamViewer'
$registryKey | Add-Member -MemberType NoteProperty -Name 'PSPath' -Value 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\TeamViewer'
$registryKey | Add-Member -MemberType ScriptMethod -Name 'GetValue' -Value { return 'TeamViewer' }
$registryKey
}
Mock Get-ItemProperty {
[PSCustomObject]@{
UninstallString = '"C:\Program Files\TeamViewer\uninstall.exe" /S'
}
} -ParameterFilter { $Name -eq 'UninstallString' }

Mock Test-Path {
param($Path)
if ($Path -like '*:\Software\*' -or $Path -like '*:\HKEY_*') {
return $true
}
#file does not exist
return $false
}
}

It 'Should return Unknown when UninstallString file does not exist' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'Unknown'
}
}

Context 'TeamViewer not installed' {
BeforeAll {
Mock Get-CimInstance {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ItemProperty {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ChildItem { }
Mock Test-Path { $false }
}

It 'Should return Unknown when TeamViewer is not installed' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'Unknown'
}
}

Context 'Check both 32-bit and 64-bit registry paths for MSI' {
BeforeAll {
Mock Get-CimInstance {
[PSCustomObject]@{ Name = 'TeamViewer' }
}
Mock Get-ItemProperty {
param($Path)
if ($Path -like '*WOW6432Node*') {
[PSCustomObject]@{ MsiInstallation = 1 }
}
else {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
} -ParameterFilter { $Name -eq 'MsiInstallation' }
}

It 'Should check both registry paths and return MSI if found in WOW6432Node' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'MSI'
}
}

Context 'Check both uninstall registry paths for exe' {
BeforeAll {
Mock Get-CimInstance {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ItemProperty {
throw [System.Management.Automation.ItemNotFoundException]::new()
} -ParameterFilter { $Name -eq 'MsiInstallation' }
Mock Get-ItemProperty {
[PSCustomObject]@{
UninstallString = 'C:\Program Files (x86)\TeamViewer\uninstall.exe /quiet'
}
} -ParameterFilter { $Name -eq 'UninstallString' }
Mock Get-ChildItem {
$registryKey = New-Object PSObject
$registryKey | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'TeamViewer'
$registryKey | Add-Member -MemberType NoteProperty -Name 'PSPath' -Value 'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\TeamViewer'
$registryKey | Add-Member -MemberType ScriptMethod -Name 'GetValue' -Value { return 'TeamViewer' }
$registryKey
}
Mock Test-Path { $true }
}

It 'Should check both 64-bit and 32-bit uninstall paths and return exe' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'exe'
}
}

Context 'MSI installation with MSIInstallation value of 0' {
BeforeAll {
Mock Get-CimInstance {
throw [System.Management.Automation.ItemNotFoundException]::new()
}
Mock Get-ItemProperty {
[PSCustomObject]@{ MsiInstallation = 0 }
} -ParameterFilter { $Name -eq 'MsiInstallation' }
Mock Get-ChildItem {
$registryKey = New-Object PSObject
$registryKey | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'TeamViewer'
$registryKey | Add-Member -MemberType NoteProperty -Name 'PSPath' -Value 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\TeamViewer'
$registryKey | Add-Member -MemberType ScriptMethod -Name 'GetValue' -Value { return 'TeamViewer' }
$registryKey
}
Mock Get-ItemProperty {
[PSCustomObject]@{
UninstallString = 'C:\Program Files\TeamViewer\uninstall.exe'
}
} -ParameterFilter { $Name -eq 'UninstallString' }
Mock Test-Path { $true }
}

It 'Should return exe when MsiInstallation is 0 (exeInstallation)' {
$result = Get-TeamViewerInstallationType
$result | Should -Be 'exe'
}
}
}