Public/Test-TeamsAddinRegistry.ps1
function Test-TeamsAddinRegistry { [CmdletBinding()] param( [Parameter()] [string]$UserSID ) # Determine user context if (-not $UserSID) { $outlookProcess = Get-Process -Name "OUTLOOK" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($outlookProcess) { Write-Output "Found Outlook process, attempting to determine user context" try { $process = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = $($outlookProcess.Id)" if ($process) { $owner = $process | Invoke-CimMethod -MethodName GetOwner if ($owner.ReturnValue -eq 0) { $account = New-Object System.Security.Principal.NTAccount($owner.Domain, $owner.User) $UserSID = $account.Translate([System.Security.Principal.SecurityIdentifier]).Value Write-Output "Detected User SID: $UserSID" } } } catch { Write-Warning "Could not determine Outlook process owner: $_" $UserSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value } } if (-not $UserSID) { Write-Output "Using current user context" $UserSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value } } $hkuPath = "Registry::HKEY_USERS\$UserSID" Write-Output "Checking Teams Add-in registry entries for user context: $UserSID" $registryChecks = @{ "Main Add-in Registration (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Microsoft\Office\Outlook\Addins\TeamsAddin.FastConnect" Values = @{ "LoadBehavior" = 3 "FriendlyName" = "Microsoft Teams Meeting Add-in for Microsoft Office" "Description" = "Microsoft Teams Meeting Add-in for Microsoft Office" } } "Main Add-in Registration (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Wow6432Node\Microsoft\Office\Outlook\Addins\TeamsAddin.FastConnect" Values = @{ "LoadBehavior" = 3 "FriendlyName" = "Microsoft Teams Meeting Add-in for Microsoft Office" "Description" = "Microsoft Teams Meeting Add-in for Microsoft Office" } } "COM Class Registration (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}" Values = @{} } "COM Class InprocServer32 (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\InprocServer32" Values = @{ "ThreadingModel" = "Apartment" } } "COM Class ProgID (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\ProgID" Values = @{ "(default)" = "TeamsAddin.FastConnect.1" } } "COM Class VersionIndependentProgID (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\VersionIndependentProgID" Values = @{ "(default)" = "TeamsAddin.FastConnect" } } "COM Class TypeLib (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\TypeLib" Values = @{ "(default)" = "{C0529B10-073A-4754-9BB0-72325D80D122}" } } "COM Class Version (64-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\Version" Values = @{ "(default)" = "1.0" } } "COM Class Registration (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\Wow6432Node\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}" Values = @{} } "COM Class InprocServer32 (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\Wow6432Node\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\InprocServer32" Values = @{ "ThreadingModel" = "Apartment" } } "COM Class ProgID (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\Wow6432Node\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\ProgID" Values = @{ "(default)" = "TeamsAddin.FastConnect.1" } } "COM Class VersionIndependentProgID (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\Wow6432Node\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\VersionIndependentProgID" Values = @{ "(default)" = "TeamsAddin.FastConnect" } } "COM Class TypeLib (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\Wow6432Node\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\TypeLib" Values = @{ "(default)" = "{C0529B10-073A-4754-9BB0-72325D80D122}" } } "COM Class Version (32-bit)" = @{ Path = "$hkuPath\SOFTWARE\Classes\Wow6432Node\CLSID\{19A6E644-14E6-4A60-B8D7-DD20610A871D}\Version" Values = @{ "(default)" = "1.0" } } } $results = @{ IsComplete = $true UserContext = $UserSID Findings = @() } foreach ($check in $registryChecks.GetEnumerator()) { Write-Output "`nChecking $($check.Key)..." if (-not (Test-Path $check.Value.Path)) { $results.IsComplete = $false $results.Findings += [PSCustomObject]@{ Component = $check.Key Status = "Missing" Details = "Registry key not found: $($check.Value.Path)" Severity = "Error" } continue } $values = Get-ItemProperty -Path $check.Value.Path -ErrorAction SilentlyContinue foreach ($expectedValue in $check.Value.Values.GetEnumerator()) { if ($values.$($expectedValue.Key) -ne $expectedValue.Value) { $results.IsComplete = $false $results.Findings += [PSCustomObject]@{ Component = $check.Key Status = "Invalid" Details = "$($expectedValue.Key) = $($values.$($expectedValue.Key)) (Expected: $($expectedValue.Value))" Severity = "Warning" } } else { $results.Findings += [PSCustomObject]@{ Component = $check.Key Status = "Valid" Details = "$($expectedValue.Key) = $($expectedValue.Value)" Severity = "Info" } } } } # Format and display results Write-Output "`nTeams Add-in Registry Status Summary:" Write-Output "User Context: $($results.UserContext)" Write-Output "Overall Status: $(if ($results.IsComplete) { 'Complete' } else { 'Incomplete' })" $results.Findings | ForEach-Object { $color = switch ($_.Severity) { "Error" { "Red" } "Warning" { "Yellow" } "Info" { "Green" } } Write-Host "`n$($_.Component) - $($_.Status)" -ForegroundColor $color Write-Host $_.Details } return $results } |