UninstallTeams.ps1
|
<#PSScriptInfo .VERSION 2.0.1 .GUID 75abbb52-e359-4945-81f6-3fdb711239a9 .AUTHOR asherto .COMPANYNAME asheroto .TAGS PowerShell, Microsoft Teams, remove, uninstall, delete, erase, uninstaller, widget, chat, enable, disable, change .PROJECTURI https://github.com/asheroto/UninstallTeams .RELEASENOTES [Version 0.0.1] - Initial Release. [Version 0.0.2] - Fixed typo and confirmed directory existence before removal. [Version 0.0.3] - Added support for Uninstall registry key. [Version 0.0.4] - Added to GitHub. [Version 0.0.5] - Fixed signature. [Version 0.0.6] - Fixed various bugs. [Version 0.0.7] - Added removal AppxPackage. [Version 0.0.8] - Added removal of startup entries. [Version 1.0.0] - Added ability to optionally disable Chat widget (Win+C) which will reinstall Teams. Major refactor of code. [Version 1.0.1] - Added URL to -CheckForUpdate function when script is out of date. [Version 1.0.2] - Improve description. [Version 1.0.3] - Fixed bug with -Version. [Version 1.0.4] - Improved CheckForUpdate function by converting time to local time and switching to variables. [Version 1.0.5] - Changed -CheckForUpdates to -CheckForUpdate. [Version 1.1.0] - Various bug fixes. Added removal of Desktop and Start Menu shortcuts. Added method to prevent Office from installing Teams. Added folders and registry keys to detect. [Version 1.1.1] - Improved Chat widget warning detection. Improved output into section headers. [Version 1.1.2] - Improved DisableOfficeTeamsInstall by adding registry key if it doesn't exist. [Version 1.1.3] - Added TeamsMachineInstaller registry key for deletion. [Version 1.1.4] - Added Teams uninstall registry key for deletion. [Version 1.2.0] - Improved functionality of uninstall key removal by detecting MsiExec product GUID to uninstall teams. Added additional startup registry keys. [Version 1.2.1] - Added additional file and registry uninstall locations. [Version 1.2.2] - Improved detection of registry uninstall keys. Improved error handling. [Version 1.2.3] - Fixed bug when uninstalling Teams from the uninstall registry key and using MsiExec.exe. [Version 1.2.4] - Added AutorunsDisabled registry keys for deletion. [Version 1.2.5] - Improved path handling for Desktop and Programs folder paths by using special folders. [Version 2.0.0] - Added detection of whether Teams is installed before attempting to uninstall it. Added an explicit administrator check with a clear message (the #Requires statement is ignored when the script is piped to iex). Added removal of the Teams provisioned package so Teams does not reinstall for new user profiles. Added removal of classic Teams folders from all user profiles. Added non-zero exit code on failure for deployment tools. Fixed bug where only the last uninstall string search was used. Fixed Appx package name matching. Fixed version comparison in -CheckForUpdate. Fixed missing quote in output. Removed unused Check-GitHubRelease function. [Version 2.0.1] - Fixed script closing the console window under irm | iex by replacing bare exits with guarded exits (exit for file runs, return for iex). #> <# .SYNOPSIS Uninstalls Microsoft Teams completely. Optional parameters to disable the Chat widget (Win+C) and prevent Office from installing Teams. .DESCRIPTION Uninstalls Microsoft Teams completely. Optional parameters to disable the Chat widget (Win+C) and prevent Office from installing Teams. The script stops the Teams process, uninstalls Teams using the uninstall key, uninstalls Teams from the Program Files (x86) directory, uninstalls Teams from the AppData directory, removes the Teams AppxPackage, deletes the Microsoft Teams directory in AppData, deletes the Teams directory in AppData, removes the startup registry keys for Teams, and removes the Desktop and Start Menu icons for Teams. .PARAMETER DisableChatWidget Disables the Chat widget (Win+C) for Microsoft Teams. .PARAMETER EnableChatWidget Enables the Chat widget (Win+C) for Microsoft Teams. .PARAMETER UnsetChatWidget Removes the Chat widget registry value, effectively enabling it since that is the default. .PARAMETER AllUsers Applies the Chat widget setting to all user profiles on the machine. .PARAMETER DisableOfficeTeamsInstall Disable Office's ability to install Teams. .PARAMETER EnableOfficeTeamsInstall Enable Office's ability to install Teams. .PARAMETER UnsetOfficeTeamsInstall Removes the Office Teams registry value, effectively enabling it since that is the default. .EXAMPLE UninstallTeams -DisableChatWidget Disables the Chat widget (Win+C) for Microsoft Teams. .EXAMPLE UninstallTeams -EnableChatWidget Enables the Chat widget (Win+C) for Microsoft Teams. .EXAMPLE UninstallTeams -UnsetChatWidget Removes the Chat widget value, effectively enabling it since that is the default. .EXAMPLE UninstallTeams -DisableChatWidget -AllUsers Disables the Chat widget (Win+C) for Microsoft Teams for all user profiles on the machine. .EXAMPLE UninstallTeams -EnableChatWidget -AllUsers Enables the Chat widget (Win+C) for Microsoft Teams for all user profiles on the machine. .EXAMPLE UninstallTeams -UnsetChatWidget -AllUsers Removes the Chat widget value, effectively enabling it since that is the default, for all user profiles on the machine. .EXAMPLE UninstallTeams -DisableOfficeTeamsInstall Disable Office's ability to install Teams. .EXAMPLE UninstallTeams -EnableOfficeTeamsInstall Enable Office's ability to install Teams. .EXAMPLE UninstallTeams -UnsetOfficeTeamsInstall Removes the Office Teams registry value, effectively enabling it since that is the default. .NOTES Version : 2.0.1 Created by : asheroto .LINK Project Site: https://github.com/asheroto/UninstallTeams #> #Requires -RunAsAdministrator [CmdletBinding()] param ( [switch]$EnableChatWidget, [switch]$DisableChatWidget, [switch]$UnsetChatWidget, [switch]$EnableOfficeTeamsInstall, [switch]$DisableOfficeTeamsInstall, [switch]$UnsetOfficeTeamsInstall, [switch]$AllUsers, [switch]$Version, [switch]$Help, [switch]$CheckForUpdate ) # Version $CurrentVersion = '2.0.1' $RepoOwner = 'asheroto' $RepoName = 'UninstallTeams' $PowerShellGalleryName = 'UninstallTeams' # Versions $ProgressPreference = 'SilentlyContinue' # Suppress progress bar (makes downloading super fast) $ConfirmPreference = 'None' # Suppress confirmation prompts # Display version if -Version is specified if ($Version.IsPresent) { $CurrentVersion exit 0 } # Display full help if -Help is specified if ($Help) { Get-Help -Name $MyInvocation.MyCommand.Source -Full exit 0 } # Display $PSVersionTable and Get-Host if -Verbose is specified if ($PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose']) { $PSVersionTable Get-Host } function Get-GitHubRelease { <# .SYNOPSIS Fetches the latest release information of a GitHub repository. .DESCRIPTION This function uses the GitHub API to get information about the latest release of a specified repository, including its version and the date it was published. .PARAMETER Owner The GitHub username of the repository owner. .PARAMETER Repo The name of the repository. .EXAMPLE Get-GitHubRelease -Owner "asheroto" -Repo "winget-install" This command retrieves the latest release version and published datetime of the winget-install repository owned by asheroto. #> [CmdletBinding()] param ( [string]$Owner, [string]$Repo ) try { $url = "https://api.github.com/repos/$Owner/$Repo/releases/latest" $response = Invoke-RestMethod -Uri $url -ErrorAction Stop $latestVersion = $response.tag_name $publishedAt = $response.published_at # Convert UTC time string to local time $UtcDateTime = [DateTime]::Parse($publishedAt, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind) $PublishedLocalDateTime = $UtcDateTime.ToLocalTime() [PSCustomObject]@{ LatestVersion = $latestVersion PublishedDateTime = $PublishedLocalDateTime } } catch { Write-Error "Unable to check for updates.`nError: $_" exit 1 } } function CheckForUpdate { param ( [string]$RepoOwner, [string]$RepoName, [version]$CurrentVersion, [string]$PowerShellGalleryName ) $Data = Get-GitHubRelease -Owner $RepoOwner -Repo $RepoName # Cast to [version] so "1.10.0" compares numerically, and tolerate a "v" tag prefix if ([version]($Data.LatestVersion -replace '^v') -gt $CurrentVersion) { Write-Output "`nA new version of $RepoName is available.`n" Write-Output "Current version: $CurrentVersion." Write-Output "Latest version: $($Data.LatestVersion)." Write-Output "Published at: $($Data.PublishedDateTime).`n" Write-Output "You can download the latest version from https://github.com/$RepoOwner/$RepoName/releases`n" if ($PowerShellGalleryName) { Write-Output "Or you can run the following command to update:" Write-Output "Install-Script $PowerShellGalleryName -Force`n" } } else { Write-Output "`n$RepoName is up to date.`n" Write-Output "Current version: $CurrentVersion." Write-Output "Latest version: $($Data.LatestVersion)." Write-Output "Published at: $($Data.PublishedDateTime)." Write-Output "`nRepository: https://github.com/$RepoOwner/$RepoName/releases`n" } exit 0 } function Get-ChatWidgetStatus { param ( [switch]$AllUsers ) if ($AllUsers) { $RegistryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Chat" } else { $RegistryPath = "HKCU:\SOFTWARE\Policies\Microsoft\Windows\Windows Chat" } if (Test-Path $RegistryPath) { $ChatIconValue = (Get-ItemProperty -Path $RegistryPath -Name "ChatIcon" -ErrorAction SilentlyContinue).ChatIcon if ($null -eq $ChatIconValue) { return "Unset (default is enabled)" } elseif ($ChatIconValue -eq 1) { return "Enabled" } elseif ($ChatIconValue -eq 2) { return "Hidden" } elseif ($ChatIconValue -eq 3) { return "Disabled" } } return "Unset (default is enabled)" } function Set-ChatWidgetStatus { param ( [switch]$EnableChatWidget, [switch]$DisableChatWidget, [switch]$UnsetChatWidget, [switch]$AllUsers ) if ($AllUsers) { $RegistryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Chat" } else { $RegistryPath = "HKCU:\SOFTWARE\Policies\Microsoft\Windows\Windows Chat" } if ($EnableChatWidget) { $WhatChanged = "enabled" if (Test-Path $RegistryPath) { Set-ItemProperty -Path $RegistryPath -Name "ChatIcon" -Value 1 -Type DWord -Force } else { New-Item -Path $RegistryPath -Force | Out-Null Set-ItemProperty -Path $RegistryPath -Name "ChatIcon" -Value 1 -Type DWord -Force } } elseif ($DisableChatWidget) { $WhatChanged = "disabled" if (Test-Path $RegistryPath) { Set-ItemProperty -Path $RegistryPath -Name "ChatIcon" -Value 3 -Type DWord -Force } else { New-Item -Path $RegistryPath -Force | Out-Null Set-ItemProperty -Path $RegistryPath -Name "ChatIcon" -Value 3 -Type DWord -Force } } elseif ($UnsetChatWidget) { $WhatChanged = "unset" if (Test-Path $RegistryPath) { Remove-ItemProperty -Path $RegistryPath -Name "ChatIcon" -ErrorAction SilentlyContinue } } if ($AllUsers) { $AllUsersString = "all users" } else { $AllUsersString = "the current user" } Write-Output "Chat widget has been $WhatChanged for $AllUsersString." } function Get-OfficeTeamsInstallStatus { # According to Microsoft, HKLM is the only key that matters for this (no HKCU) $RegistryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Office\16.0\Common\OfficeUpdate" if (Test-Path $RegistryPath) { $OfficeTeamsInstallValue = (Get-ItemProperty -Path $RegistryPath).PreventTeamsInstall if ($null -eq $OfficeTeamsInstallValue) { return "Unset (default is enabled)" } elseif ($OfficeTeamsInstallValue -eq 0) { return "Enabled" } elseif ($OfficeTeamsInstallValue -eq 1) { return "Disabled" } } return "Unset (default is enabled)" } function Set-OfficeTeamsInstallStatus { param ( [switch]$EnableOfficeTeamsInstall, [switch]$DisableOfficeTeamsInstall, [switch]$UnsetOfficeTeamsInstall ) $RegistryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Office\16.0\Common\OfficeUpdate" if (-Not (Test-Path $RegistryPath)) { Write-Output "Creating registry path $RegistryPath." New-Item -Path $RegistryPath -Force | Out-Null } if ($EnableOfficeTeamsInstall) { $WhatChanged = "enabled" Set-ItemProperty -Path $RegistryPath -Name "PreventTeamsInstall" -Value 0 -Type DWord -Force } elseif ($DisableOfficeTeamsInstall) { $WhatChanged = "disabled" Set-ItemProperty -Path $RegistryPath -Name "PreventTeamsInstall" -Value 1 -Type DWord -Force } elseif ($UnsetOfficeTeamsInstall) { $WhatChanged = "unset (default is enabled)" Remove-ItemProperty -Path $RegistryPath -Name "PreventTeamsInstall" -ErrorAction SilentlyContinue } Write-Output "Office's ability to install Teams has been $WhatChanged." } function Write-Section($text) { <# .SYNOPSIS Prints a text block surrounded by a section divider for enhanced output readability. .DESCRIPTION This function takes a string input and prints it to the console, surrounded by a section divider made of hash characters. It is designed to enhance the readability of console output. .PARAMETER text The text to be printed within the section divider. .EXAMPLE Write-Section "Downloading Files..." This command prints the text "Downloading Files..." surrounded by a section divider. #> Write-Output "" Write-Output ("#" * ($text.Length + 4)) Write-Output "# $text #" Write-Output ("#" * ($text.Length + 4)) Write-Output "" } # Get uninstall registry keys function Get-UninstallRegistryKey { param ( [string]$Match ) $result = @() $uninstallKeys = @( "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall", "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall", "HKCU:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" ) foreach ($key in $uninstallKeys) { if (Test-Path $key) { Get-ChildItem $key | Where-Object { $_.GetValue("DisplayName") -like "*${Match}*" } | ForEach-Object { $result += $_.PSPath } } } return $result } # Get uninstall string from registry key function Get-UninstallString { param ( [string]$Match ) $result = @() $registryKeys = Get-UninstallRegistryKey -Match $Match foreach ($regKey in $registryKeys) { try { $displayName = (Get-ItemProperty -Path $regKey).DisplayName $uninstallString = (Get-ItemProperty -Path $regKey).UninstallString if ($displayName -and $uninstallString) { $obj = [PSCustomObject]@{ DisplayName = $displayName UninstallString = $uninstallString } $result += $obj } } catch { } } return $result } function Remove-Shortcut { param ( [string]$ShortcutName, [string]$ShortcutPathName, [string]$UserPath, [string]$PublicPath ) try { $userShortcutPath = [System.IO.Path]::Combine($UserPath, "$ShortcutName.lnk") $publicShortcutPath = [System.IO.Path]::Combine($PublicPath, "$ShortcutName.lnk") if (Test-Path -Path $userShortcutPath) { Write-Output "Deleting $ShortcutName from the user's $ShortcutPathName..." Remove-Item -Path $userShortcutPath } if (Test-Path -Path $publicShortcutPath) { Write-Output "Deleting $ShortcutName from the public $ShortcutPathName..." Remove-Item -Path $publicShortcutPath } } catch { Write-Output "An error occurred while attempting to delete the shortcut." } } function Remove-DesktopShortcuts { param ( [string]$ShortcutName ) $userDesktopPath = [System.Environment]::GetFolderPath('Desktop') $publicDesktopPath = [System.Environment]::GetFolderPath('CommonDesktopDirectory') Remove-Shortcut -ShortcutPathName "Desktop" -ShortcutName $ShortcutName -UserPath $userDesktopPath -PublicPath $publicDesktopPath } function Remove-StartMenuShortcuts { param ( [string]$ShortcutName ) $userStartMenuPath = [System.IO.Path]::Combine([System.Environment]::GetFolderPath('StartMenu'), "Programs") $publicStartMenuPath = [System.IO.Path]::Combine([System.Environment]::GetFolderPath('CommonStartMenu'), "Programs") Remove-Shortcut -ShortcutPathName "Start Menu" -ShortcutName $ShortcutName -UserPath $userStartMenuPath -PublicPath $publicStartMenuPath } # Teams locations, used for both detection and removal $TeamsInstallerPath = Join-Path ${env:ProgramFiles(x86)} "Teams Installer\Teams.exe" $TeamsUpdateExePath = Join-Path $env:APPDATA "Microsoft\Teams\Update.exe" $TeamsUpdateExePathPrgX86 = Join-Path ${env:ProgramFiles(x86)} "Microsoft\Teams\current\Update.exe" $MicrosoftTeamsPath = Join-Path $env:LOCALAPPDATA "Microsoft Teams" $TeamsPath = Join-Path $env:LOCALAPPDATA "Microsoft\Teams" $UninstallMatches = @("Microsoft Teams", "MSTeams", "Teams Machine-Wide") function Test-Admin { <# .SYNOPSIS Returns whether the current session is running elevated. .DESCRIPTION The #Requires -RunAsAdministrator statement is only honored when the script is run as a file. It is ignored when the script is piped to iex, which is the documented way to run UninstallTeams, so the check has to be repeated at runtime. #> $identity = [Security.Principal.WindowsIdentity]::GetCurrent() (New-Object Security.Principal.WindowsPrincipal($identity)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Test-TeamsInstalled { <# .SYNOPSIS Returns whether any trace of Teams that this script removes is present. .DESCRIPTION Checks the same install locations, uninstall registry keys, and Appx packages that the uninstall routine acts on, so that the script can report "not installed" instead of claiming to have uninstalled something that was never there. #> foreach ($path in @($TeamsInstallerPath, $TeamsUpdateExePath, $TeamsUpdateExePathPrgX86, $MicrosoftTeamsPath, $TeamsPath)) { if (Test-Path $path) { Write-Debug "Teams detected at $path" return $true } } foreach ($match in $UninstallMatches) { if (Get-UninstallRegistryKey -Match $match) { Write-Debug "Teams detected in uninstall registry keys matching '$match'" return $true } } foreach ($package in @("MSTeams*", "MicrosoftTeams*")) { if (Get-AppxPackage -Name $package) { Write-Debug "Teams detected as Appx package $package" return $true } if (Get-AppxPackage -Name $package -AllUsers -ErrorAction SilentlyContinue) { Write-Debug "Teams detected as Appx package $package (all users)" return $true } } if (Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "MSTeams*" -or $_.DisplayName -like "MicrosoftTeams*" }) { Write-Debug "Teams detected as provisioned package" return $true } # Classic Teams in any user profile (wildcards are valid in Test-Path) foreach ($profileGlob in @("Users\*\AppData\Local\Microsoft Teams", "Users\*\AppData\Local\Microsoft\Teams", "Users\*\AppData\Roaming\Microsoft\Teams")) { if (Test-Path (Join-Path $env:SystemDrive $profileGlob)) { Write-Debug "Teams detected in a user profile: $profileGlob" return $true } } return $false } # ============================================================================ # # Initial checks # ============================================================================ # # Check for updates if -CheckForUpdate is specified if ($CheckForUpdate) { CheckForUpdate -RepoOwner $RepoOwner -RepoName $RepoName -CurrentVersion $CurrentVersion -PowerShellGalleryName $PowerShellGalleryName } # Check if exactly one or none of -EnableChatWidget, -DisableChatWidget, or -UnsetChatWidget is specified $chatWidgetCount = ($EnableChatWidget, $DisableChatWidget, $UnsetChatWidget).Where({ $_ }).Count if ($chatWidgetCount -gt 1) { Write-Warning "Please choose only one of -EnableChatWidget, -DisableChatWidget, or -UnsetChatWidget." if ($PSCommandPath) { exit 1 } else { return } } # Check if -AllUsers is specified without one of -EnableChatWidget, -DisableChatWidget, or -UnsetChatWidget if ($AllUsers -and $chatWidgetCount -eq 0) { Write-Error "The -AllUsers switch can only be used with -EnableChatWidget, -DisableChatWidget, or -UnsetChatWidget. UninstallTeams will always remove Teams for the local machine." if ($PSCommandPath) { exit 1 } else { return } } # Similar checks for -EnableOfficeTeamsInstall, -DisableOfficeTeamsInstall, or -UnsetOfficeTeamsInstall $officeTeamsInstallCount = ($EnableOfficeTeamsInstall, $DisableOfficeTeamsInstall, $UnsetOfficeTeamsInstall).Where({ $_ }).Count if ($officeTeamsInstallCount -gt 1) { Write-Warning "Please choose only one of -EnableOfficeTeamsInstall, -DisableOfficeTeamsInstall, or -UnsetOfficeTeamsInstall." if ($PSCommandPath) { exit 1 } else { return } } # Uninstalling is the default action when no setting switch is used $Uninstall = ($chatWidgetCount -eq 0) -and ($officeTeamsInstallCount -eq 0) # Everything except a per-user Chat widget change writes to HKLM or removes machine-wide files if (($Uninstall -or $officeTeamsInstallCount -gt 0 -or $AllUsers) -and -not (Test-Admin)) { Write-Warning "UninstallTeams needs to run as an administrator." Write-Output "" Write-Output "Close this window, right-click PowerShell or Terminal, choose 'Run as administrator'," Write-Output "then run the command again. Nothing has been changed." Write-Output "" # exit would close the window under irm | iex before the user can read this if ($PSCommandPath) { exit 1 } else { return } } try { # Spacer Write-Output "" # Heading Write-Output "UninstallTeams $CurrentVersion" Write-Output "To check for updates, run UninstallTeams -CheckForUpdate" # Spacer Write-Output "" # Chat widget if ($EnableChatWidget) { Set-ChatWidgetStatus -EnableChatWidget -AllUsers:$AllUsers } elseif ($DisableChatWidget) { Set-ChatWidgetStatus -DisableChatWidget -AllUsers:$AllUsers } elseif ($UnsetChatWidget) { Set-ChatWidgetStatus -UnsetChatWidget -AllUsers:$AllUsers } # Office Teams install if ($EnableOfficeTeamsInstall) { Set-OfficeTeamsInstallStatus -EnableOfficeTeamsInstall } elseif ($DisableOfficeTeamsInstall) { Set-OfficeTeamsInstallStatus -DisableOfficeTeamsInstall } elseif ($UnsetOfficeTeamsInstall) { Set-OfficeTeamsInstallStatus -UnsetOfficeTeamsInstall } # Uninstall Teams if ($Uninstall) { $TeamsWasInstalled = Test-TeamsInstalled } if ($Uninstall -and $TeamsWasInstalled) { # Stopping Teams process Write-Output "Stopping Teams process..." # "Teams*" covers "Teams Machine-Wide*", and -Name is case-insensitive so "MSTeams*" covers "ms-teams*" Stop-Process -Name "Microsoft Teams*", "MSTeams*", "Teams*" -Force -ErrorAction SilentlyContinue ########################################################################### # Start the process of uninstalling Teams Write-Output "Deleting Teams through uninstall registry key..." # Retrieve the uninstall information for Teams $uninstallInfo = @() foreach ($match in $UninstallMatches) { $uninstallInfo += Get-UninstallString -Match $match } foreach ($info in ($uninstallInfo | Sort-Object -Property UninstallString -Unique)) { $uninstallString = $info.UninstallString if (-not [string]::IsNullOrWhiteSpace($uninstallString)) { Write-Debug "Found Teams uninstall string: $uninstallString" # Check if the uninstall string is an MSI command if ($uninstallString -match "msiexec.exe\s*/[XxIi]\{([^\}]+)\}") { $productGUID = $matches[1] Write-Debug "Found Teams product GUID: $productGUID" # Construct the MSI uninstall command with the correct format for GUID $filePath = "msiexec.exe" $argList = "/x {${productGUID}} /qn" # Correct format for GUID } else { # For non-MSI packages, assume the uninstall string is a complete command $filePath = $uninstallString.Split(" ")[0] $argList = $uninstallString.Substring($filePath.Length).Trim() } # Execute the uninstall command if ($filePath -ieq "msiexec.exe" -or (Test-Path $filePath)) { Write-Debug "Uninstalling Teams with command: $filePath $argList" $proc = Start-Process -FilePath $filePath -ArgumentList $argList -PassThru $proc.WaitForExit() } else { Write-Warning "The path $filePath does not exist." } } } ########################################################################### # Uninstall from "Teams Installer" Write-Output "Checking Teams in `"$TeamsInstallerPath`"..." if (Test-Path $TeamsInstallerPath) { Write-Output "Uninstalling Teams from `"$TeamsInstallerPath`"..." $proc = Start-Process -FilePath $TeamsInstallerPath -ArgumentList "--uninstall" -PassThru $proc.WaitForExit() } # Uninstall from AppData\Microsoft\Teams Write-Output "Checking Teams in `"$TeamsUpdateExePath`"..." if (Test-Path $TeamsUpdateExePath) { Write-Output "Uninstalling Teams from `"$TeamsUpdateExePath`"..." $proc = Start-Process -FilePath $TeamsUpdateExePath -ArgumentList "-uninstall -s" -PassThru $proc.WaitForExit() } # Uninstall from Program Files (x86)\Microsoft\Teams\current Write-Output "Checking Teams in `"$TeamsUpdateExePathPrgX86`"..." if (Test-Path $TeamsUpdateExePathPrgX86) { Write-Output "Uninstalling Teams from `"$TeamsUpdateExePathPrgX86`"..." $proc = Start-Process -FilePath $TeamsUpdateExePathPrgX86 -ArgumentList "-uninstall -s" -PassThru $proc.WaitForExit() } # Remove via AppxPackage # Package names have no spaces, so "Microsoft Teams*" never matched anything Write-Output "Removing Teams AppxPackage..." foreach ($package in @("MSTeams*", "MicrosoftTeams*")) { Get-AppxPackage -Name $package | Remove-AppxPackage -ErrorAction SilentlyContinue Get-AppxPackage -Name $package -AllUsers -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue } # Remove provisioned package so Windows doesn't reinstall Teams for new user profiles Write-Output "Removing Teams provisioned package..." Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "MSTeams*" -or $_.DisplayName -like "MicrosoftTeams*" } | Remove-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Out-Null # Delete Microsoft Teams directory Write-Output "Deleting `"$MicrosoftTeamsPath`"..." if (Test-Path $MicrosoftTeamsPath) { Remove-Item -Path $MicrosoftTeamsPath -Force -Recurse -ErrorAction SilentlyContinue } # Delete Teams directory Write-Output "Deleting `"$TeamsPath`"..." if (Test-Path $TeamsPath) { Remove-Item -Path $TeamsPath -Force -Recurse -ErrorAction SilentlyContinue } # Remove from startup registry key Write-Output "Deleting Teams startup registry keys..." Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Remove-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Remove-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Remove-ItemProperty -Path 'HKCU:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue # Remove from AutorunsDisabled registry key Write-Output "Deleting Teams startup registry keys from AutorunsDisabled..." Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\AutorunsDisabled' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Remove-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run\AutorunsDisabled' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Remove-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\AutorunsDisabled' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Remove-ItemProperty -Path 'HKCU:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run\AutorunsDisabled' -Name 'Teams', 'TeamsMachineUninstallerLocalAppData', 'TeamsMachineUninstallerProgramData', 'com.squirrel.Teams.Teams', 'TeamsMachineInstaller' -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue # Remove Teams uninstall registry keys Write-Output "Deleting Teams uninstall registry keys..." Remove-Item -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Teams" -Force -Recurse -ErrorAction SilentlyContinue Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Teams" -Force -Recurse -ErrorAction SilentlyContinue # Removing desktop shortcuts Write-Output "Deleting Teams desktop shortcuts..." Remove-DesktopShortcuts -ShortcutName "Microsoft Teams" # Removing start menu shortcuts Write-Output "Deleting Teams start menu shortcuts..." Remove-StartMenuShortcuts -ShortcutName "Microsoft Teams" Remove-StartMenuShortcuts -ShortcutName "Microsoft Teams classic (work or school)" # Removing Teams meeting addin Write-Output "Deleting Teams meeting addin..." $teamsMeetingAddin = "$env:LOCALAPPDATA\Microsoft\TeamsMeetingAddin" if (Test-Path $teamsMeetingAddin) { Remove-Item -Path $teamsMeetingAddin -Force -Recurse -ErrorAction SilentlyContinue } # Removing Teams presence addin Write-Output "Deleting Teams presence addin..." $teamsPresenceAddin = "$env:LOCALAPPDATA\Microsoft\TeamsPresenceAddin" if (Test-Path $teamsPresenceAddin) { Remove-Item -Path $teamsPresenceAddin -Force -Recurse -ErrorAction SilentlyContinue } # Remove classic Teams leftovers from every user profile (classic Teams installs per-user, # so everything above only cleaned up the profile running the script) Write-Output "Deleting Teams folders from all user profiles..." $profileDirs = Get-ChildItem (Join-Path $env:SystemDrive "Users") -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notin @("Public", "Default", "Default User", "All Users") } foreach ($profileDir in $profileDirs) { $profilePaths = @( (Join-Path $profileDir.FullName "AppData\Local\Microsoft Teams"), (Join-Path $profileDir.FullName "AppData\Local\Microsoft\Teams"), (Join-Path $profileDir.FullName "AppData\Local\Microsoft\TeamsMeetingAddin"), (Join-Path $profileDir.FullName "AppData\Local\Microsoft\TeamsPresenceAddin"), (Join-Path $profileDir.FullName "AppData\Roaming\Microsoft\Teams") ) foreach ($profilePath in $profilePaths) { if (Test-Path $profilePath) { Write-Output "Deleting `"$profilePath`"..." Remove-Item -Path $profilePath -Force -Recurse -ErrorAction SilentlyContinue } } } # ponytail: other users' HKCU Run keys are left alone (their hives aren't loaded); the entries # point at files deleted above, so they fail silently and Windows eventually prunes them } } catch { $UninstallFailed = $true Write-Warning "An error occurred during the Teams uninstallation process: $_" } # Report the outcome of the uninstall, then let user know nothing below will change if ($Uninstall) { Write-Output "" if (-not $TeamsWasInstalled) { Write-Output "Teams is not installed, there was nothing to uninstall." } elseif ($UninstallFailed) { Write-Warning "Teams was not fully uninstalled, see the error above." } else { Write-Output "Teams has been uninstalled, please restart your computer." } Write-Output "" Write-Output "The information below is only information, the settings below will not change unless you use parameters to change them." } # Output the Chat widget status of both the current user and the local machine $CurrentUserStatus = Get-ChatWidgetStatus $LocalMachineStatus = Get-ChatWidgetStatus -AllUsers # Determine the effective status if ($CurrentUserStatus -ne "Unset (default is enabled)") { $effectiveStatus = $CurrentUserStatus } elseif ($LocalMachineStatus -ne "Unset (default is enabled)") { $effectiveStatus = $LocalMachineStatus } else { $effectiveStatus = "Enabled by default" Write-Output "Both Current User and Local Machine statuses are Unset (default is enabled). Enabled by default." } Write-Section("Chat widget") Write-Output "Current User Status: $CurrentUserStatus" Write-Output "Local Machine Status: $LocalMachineStatus" Write-Output "Effective Status: $effectiveStatus" Write-Output "" # If Chat widget status is "Enabled" or "Enabled by default", show a warning if ($effectiveStatus -eq "Enabled" -or $effectiveStatus -eq "Enabled by default") { Write-Warning "Teams Chat widget is enabled. Teams could be reinstalled if the user clicks 'Continue' after using Win+C or by clicking the Chat icon in the taskbar (if enabled). Use the '-DisableChatWidget' or '-DisableChatWidget -AllUsers' switch to disable it. Current user takes precedence unless unset. Use 'Get-Help UninstallTeams -Full' for more information." } # Output the Office Teams install status $OfficeTeamsInstallStatus = Get-OfficeTeamsInstallStatus # Chat widget status Write-Section("Office's ability to install Teams") Write-Output "Status: $OfficeTeamsInstallStatus" Write-Output "" # If Office Team install status is Enabled or unset, show a warning if (($OfficeTeamsInstallStatus -eq "Enabled") -or ($OfficeTeamsInstallStatus -eq "Unset (default is enabled)")) { Write-Warning "Office is allowing Teams to install. Teams could be reinstalled if Office is installed or updated.`nUse the '-DisableOfficeTeamsInstall' switch to prevent Teams from installing with Office. Use 'Get-Help UninstallTeams -Full' for more information." } # Office note Write-Section("Office Note") Write-Output "If you just installed Microsoft Office, you may need to restart the computer once or`ntwice and then run UninstallTeams to prevent Teams from reinstalling." # Spacer Write-Output "" # Non-zero exit code so deployment tools (Intune, SCCM) can detect failure; under iex, # return keeps the console open (no $LASTEXITCODE, but deployment tools run the file) if ($UninstallFailed) { if ($PSCommandPath) { exit 1 } else { return } } # SIG # Begin signature block # MIIpaQYJKoZIhvcNAQcCoIIpWjCCKVYCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDfcQPGpbOjk2VN # n27yFV99m5adaDy2qzNnbb3TXRDXGaCCDh8wggawMIIEmKADAgECAhAIrUCyYNKc # TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z # NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw # ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0 # JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr # Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF # LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F # LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh # 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ # wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay # g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI # YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp # QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro # OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB # WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+ # YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P # AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC # hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v # dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED # MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql # +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF # UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h # mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw # YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld # AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw # 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP # LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE # QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn # KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji # WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq # yK+p/pQd52MbOoZWeE4wggdnMIIFT6ADAgECAhAKNMZR1UZgqS/qeQN0g3OKMA0G # CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjYwMjA5MDAwMDAwWhcNMjcwMjA4 # MjM1OTU5WjBvMQswCQYDVQQGEwJVUzERMA8GA1UECBMIT2tsYWhvbWExETAPBgNV # BAcTCE11c2tvZ2VlMRwwGgYDVQQKExNBc2hlciBTb2x1dGlvbnMgSW5jMRwwGgYD # VQQDExNBc2hlciBTb2x1dGlvbnMgSW5jMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A # MIICCgKCAgEAsNcdHVM982mI1sSTuI2eOkKc4SoeDvPdZyoybYQWcOxzAYJsVzEI # EoQcIjKU0KyOmPAEb/4U8VGrlATrm1BYwGLC9eymeBmUWc/VKECl6bPwos3B5K83 # qkNQshZvRtaN1S+surYIhW2vbHAtiIJnK4aY6emutJxB8TKuf68hTH13C9d0lwTG # BSHTvLnYphdRg2z/VriH39GOP9d58YI/kztkS76v2itPjoO8fmoS7UicgpjfgV/D # C6L09zg4pR9xhPWO0jpC4bDBw8pJyydSWyJNwiKYsDxSu9EoWWgYSuR3aP27seSj # Soh6p+gcAHNkwD3TmwcDxgjLQJGQZCq81Wg6XD1wNRcQj3Co+aHM4bDnrEGr3Fr+ # KybVO4JzImTMAqqiNJsJfgZFkJpo8yWX91bmfyo/gCZdq8FM74BqabuCT0POxV2i # hmj1IEujJlGXV7o1dl3HbOHfAbKBXZ56+sydA2TCANU6Tx72g6MMauaxq+HOOKng # SYkpScbzng4XafT3Ik4AMutry4XwXvVvplnp7vvTuJC/udSGHicc2gTV9cvD4tH3 # 52J8niCbtlivKvCux+BkoFrZK8C7OTjbc08EWoD5UpMuEddx/L/kWsg65NExvY2a # pHBsU4JnUe5h6ABqp70hvZJxpoX8b3n8uiWGUYzuC0UaTB+WoMgxMd0CAwEAAaOC # AgMwggH/MB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQW # BBQHFH7qQHiyfL6gvRyEHXMdJO+aJTA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcG # CCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/ # BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+G # TWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVT # aWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3Js # NC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQw # OTZTSEEzODQyMDIxQ0ExLmNybDCBlAYIKwYBBQUHAQEEgYcwgYQwJAYIKwYBBQUH # MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBcBggrBgEFBQcwAoZQaHR0cDov # L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25p # bmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcnQwCQYDVR0TBAIwADANBgkqhkiG9w0B # AQsFAAOCAgEAutKpxJB9JYzuVnoBPTWJJYB0MhRrjbKY2lBq4V58at51H9A4PZjz # KcLGenWuhgsWgzlgG6i+M/JjTZ2HG6ZXB+vGA5ZJxO5/InNIEcP2llytP6513Bre # dJqEejqqgV2wmqFdiH272+ejnER+9EgydyD/zzIFLXpJ/5AK1Hr6tE7J37fgX+4e # Kn9Lr/BOSda1FpSXprbC+mUtjMIm6NgO9c+hctEvl30osz2pzy8SzqliGeE/Nkn9 # MmcLw6KMpRRSLFDIAXgB4hFoWj8isPeNs4p3Sjb8ObrnZJdNQ8qDnWjT8kbrvAGp # wW4Kp4c7o6VEBGwT2lQnSF/2HGDphCZNj/9sNbJ1wex2HBYkn/a26uFmvGjYHrZG # SDDKXVBQEFM9BNNPHrXW2cOZyKpTftDsOK0SmX+y+kuHA2UT8HfB0LklyjUc15mz # yzYn/n2WvVZt7fzTPJgsqRLRuoKOgQ5pIJY9XRq7i9oyFeUDZKsR5EblKB7Fbqcj # txNcz7YmGLJvxDDx/qjeyvJLRKgBfm3yLRB/vL2xCTNKtmo0yK+Q5z5lrqMId+vm # lrHx9C1K2KSqn8/JtAi0sOeoENEbD5Azl/ZmEtxQKgfS9fyul4Enh57IqJ9MILAP # YOW63KIHwYscQAosM/PdjNy5DKDjwk+4jN7x9bEZJquPrl1y5XYE4j4xghqgMIIa # nAIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFB # MD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5 # NiBTSEEzODQgMjAyMSBDQTECEAo0xlHVRmCpL+p5A3SDc4owDQYJYIZIAWUDBAIB # BQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIB # BDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQg # DToGSQ+iXt+mOXStMraYrN65xFDckDdBx5LCXMYW8bswDQYJKoZIhvcNAQEBBQAE # ggIAlxB4YIhFpOGziqcKLqduI+W2vZVsDK2Osu+mDljoeqFTkOQIT/ZGQn71TboY # RMavUijlsA5/i5wP7pMKcIauQLT8I8EkzRpmO2x3JMS5d/X36aEwUa1qHVYpdSit # MIp7F/Ll9eyntiY2rtPbnwceFidh0p5H7daNYFlccUxHL2S+UiD8fUL2qJNgdfO/ # It+q9Zd+KggkTrMyVeeUGpVLFTSv2V1Uh/zfeMUfCBava2J569DoISVzri1gs5UE # gDXQZoamC+3EMwXq/KWHT4uzvj/ZS4XkXn9TUYB7kO0Bx8H8t8yqOoILkutjOhQV # 7nOQzvDZ3M8mneTajbsdmQEhymCLe4lPBfmENkA0rPCusi6aLOJiMAuYwGqqj8Bv # MRVJbvvODw++CGdArZNBoEyjJFi7nl9Y7xB1U+Sgz54IWzEIXhZk5+uQy2w7ewic # +PApJDjUvwoSYm5HpBbDj8NEv/PM8ts5zZ+7N/Xwcd2DNCgEcFCH61YAjMzMi8Fu # 6UaOXaUZC67J0h0uaCWict6L4FYU3MzoadEdBIzo4olwd98tW5GSEiDkXKkFXO36 # ACqhbhkHEjSNV+t112/Gyc6EK69sqT7lNf/RKMxKFfdRZVN77YZzbeGu+kyMU2z3 # 1BVHEbFHa98uWvQTWnXPA2UBRO/evPT2kRRdcI1h6tIlO1qhghd2MIIXcgYKKwYB # BAGCNwMDATGCF2IwghdeBgkqhkiG9w0BBwKgghdPMIIXSwIBAzEPMA0GCWCGSAFl # AwQCAQUAMHcGCyqGSIb3DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglg # hkgBZQMEAgEFAAQgJ3rRCoU7CJCEc5rS2qj1q4lF/SYkj6vmq80/XH2Yl2ECEEUa # Pl77f3IX+Tu0oZZY7+0YDzIwMjYwODMxMjAzNTIyWqCCEzowggbtMIIE1aADAgEC # AhAKgO8YS43xBYLRxHanlXRoMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1 # c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwHhcN # MjUwNjA0MDAwMDAwWhcNMzYwOTAzMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUG # A1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFNIQTI1NiBS # U0E0MDk2IFRpbWVzdGFtcCBSZXNwb25kZXIgMjAyNSAxMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEA0EasLRLGntDqrmBWsytXum9R/4ZwCgHfyjfMGUIw # YzKomd8U1nH7C8Dr0cVMF3BsfAFI54um8+dnxk36+jx0Tb+k+87H9WPxNyFPJIDZ # HhAqlUPt281mHrBbZHqRK71Em3/hCGC5KyyneqiZ7syvFXJ9A72wzHpkBaMUNg7M # OLxI6E9RaUueHTQKWXymOtRwJXcrcTTPPT2V1D/+cFllESviH8YjoPFvZSjKs3SK # O1QNUdFd2adw44wDcKgH+JRJE5Qg0NP3yiSyi5MxgU6cehGHr7zou1znOM8odbkq # oK+lJ25LCHBSai25CFyD23DZgPfDrJJJK77epTwMP6eKA0kWa3osAe8fcpK40uhk # tzUd/Yk0xUvhDU6lvJukx7jphx40DQt82yepyekl4i0r8OEps/FNO4ahfvAk12hE # 5FVs9HVVWcO5J4dVmVzix4A77p3awLbr89A90/nWGjXMGn7FQhmSlIUDy9Z2hSgc # taepZTd0ILIUbWuhKuAeNIeWrzHKYueMJtItnj2Q+aTyLLKLM0MheP/9w6CtjuuV # HJOVoIJ/DtpJRE7Ce7vMRHoRon4CWIvuiNN1Lk9Y+xZ66lazs2kKFSTnnkrT3pXW # ETTJkhd76CIDBbTRofOsNyEhzZtCGmnQigpFHti58CSmvEyJcAlDVcKacJ+A9/z7 # eacCAwEAAaOCAZUwggGRMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOQ7/PIx7f39 # 1/ORcWMZUEPPYYzoMB8GA1UdIwQYMBaAFO9vU0rp5AZ8esrikFb2L9RJ7MtOMA4G # A1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDCBlQYIKwYBBQUH # AQEEgYgwgYUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBd # BggrBgEFBQcwAoZRaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3J0MF8G # A1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNybDAg # BgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQAD # ggIBAGUqrfEcJwS5rmBB7NEIRJ5jQHIh+OT2Ik/bNYulCrVvhREafBYF0RkP2AGr # 181o2YWPoSHz9iZEN/FPsLSTwVQWo2H62yGBvg7ouCODwrx6ULj6hYKqdT8wv2UV # +Kbz/3ImZlJ7YXwBD9R0oU62PtgxOao872bOySCILdBghQ/ZLcdC8cbUUO75ZSpb # h1oipOhcUT8lD8QAGB9lctZTTOJM3pHfKBAEcxQFoHlt2s9sXoxFizTeHihsQyfF # g5fxUFEp7W42fNBVN4ueLaceRf9Cq9ec1v5iQMWTFQa0xNqItH3CPFTG7aEQJmmr # JTV3Qhtfparz+BW60OiMEgV5GWoBy4RVPRwqxv7Mk0Sy4QHs7v9y69NBqycz0BZw # hB9WOfOu/CIJnzkQTwtSSpGGhLdjnQ4eBpjtP+XB3pQCtv4E5UCSDag6+iX8MmB1 # 0nfldPF9SVD7weCC3yXZi/uuhqdwkgVxuiMFzGVFwYbQsiGnoa9F5AaAyBjFBtXV # LcKtapnMG3VH3EmAp/jsJ3FVF3+d1SVDTmjFjLbNFZUWMXuZyvgLfgyPehwJVxwC # +UpX2MSey2ueIu9THFVkT+um1vshETaWyQo8gmBto/m3acaP9QsuLj3FNwFlTxq2 # 5+T4QwX9xa6ILs84ZPvmpovq90K8eWyG2N01c4IhSOxqt81nMIIGtDCCBJygAwIB # AgIQDcesVwX/IZkuQEMiDDpJhjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJV # UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu # Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3 # MDAwMDAwWhcNMzgwMTE0MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO # RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGlt # ZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEAtHgx0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1 # mZaDLFTtQ2oRjzUXMmxCqvkbsDpz4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJa # DNs1+JH7Z+QdSKWM06qchUP+AbdJgMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6A # o+xh/AS7sQRuQL37QXbDhAktVJMQbzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M98 # 0EpLtlrNyHw0Xm+nt5pnYJU3Gmq6bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC # 2ZQ8BbfnFRQVESYOszFI2Wv82wnJRfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+Kd # PvMvaB0WkE/2qHxJ0ucS638ZxqU14lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHk # ccpL6uoG8pbF0LJAQQZxst7VvwDDjAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8 # hjj/q8d6ylgxCZSKi17yVp2NL+cnT6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDK # iDEb1AQ8es9Xr/u6bDTnYCTKIsDq1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCB # ZtVFJfVZ3j7OgWmnhFr4yUozZtqgPrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsg # Y1MCAwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9v # U0rp5AZ8esrikFb2L9RJ7MtOMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiu # HA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEF # BQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBB # BggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkw # FzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsW # gBz+Bz0RdnEwvb4LyLU0pn/N0IfFiBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j0 # 0DNqhCT3t+s8G0iP5kvN2n7Jd2E4/iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywF # LerycvZTAz40y8S4F3/a+Z1jEMK/DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2 # e26MHvVY9gCDA/JYsq7pGdogP8HRtrYfctSLANEBfHU16r3J05qX3kId+ZOczgj5 # kjatVB+NdADVZKON/gnZruMvNYY2o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXu # vTPSegOOzr4EWj7PtspIHBldNE2K9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25 # xUbI7GIN/TpVfHIqQ6Ku/qjTY6hc3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZ # jE4YtL8Pbzg0c1ugMZyZZd/BdHLiRu7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeq # GkH/wyW4N7OigizwJWeukcyIPbAvjSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQ # sfch28bZeUz2rtY/9TCA6TD8dC3JE3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS # 9/wQD7yFylIz0scmbKvFoW2jNrbM1pD2T7m3XDCCBY0wggR1oAMCAQICEA6bGI75 # 0C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIG # A1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAw # MFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD # ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGln # aUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuE # DcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNw # wrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs0 # 6wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e # 5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtV # gkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85 # tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+S # kjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1Yxw # LEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzl # DlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFr # b7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATow # ggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiu # HA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQE # AwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2 # hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290 # Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/ # Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNK # ei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHr # lnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4 # oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5A # Y8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNN # n3O3AamfV6peKOK5lDGCA3wwggN4AgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNV # BAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0 # IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMQIQCoDvGEuN8QWC # 0cR2p5V0aDANBglghkgBZQMEAgEFAKCB0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN # AQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MDgzMTIwMzUyMlowKwYLKoZIhvcNAQkQ # AgwxHDAaMBgwFgQU3WIwrIYKLTBr2jixaHlSMAf7QX4wLwYJKoZIhvcNAQkEMSIE # IOTQbrHXoh6yQDzfelEWgqdThZc6ZgBsecTMfown3EnSMDcGCyqGSIb3DQEJEAIv # MSgwJjAkMCIEIEqgP6Is11yExVyTj4KOZ2ucrsqzP+NtJpqjNPFGEQozMA0GCSqG # SIb3DQEBAQUABIICAGuZZLyBYtD0N6jvqWcPYfU6+mzfNbm5cqRxRgJx/dzfLrfC # 1BvttKRNp3dzdsjJSeAZzr+P5tXdvQKeCeoCrY3F23UEXveYwuim+HTYIXSj7h3z # md26hsitXb7eMUjiU7aSxM+e0JZ/SdOJ4ZymtnHB9VMGKBpl6Xa6/mN2P/0HcjoS # Ti1+PebDgjQXjJcYi6eN0PQtomB+vA6OvJqtVsT9aaOXVJEHSFE3NiefH/9a18N2 # cVChYlvDd8NxKZlGtlrzkM9e7wcEmQ5A77IOi1tbGpk000Y6HMJRULiIhevftFio # A4xPCoo6FMeGnsHZLsu1rSLPKAohvkSGoh2LGesL9kF9rYKBQZWC0tR0UIXxYmz+ # kQVtSUE3OQWAEqe7tvmhh+R2PTGyaVXWrXVygwsRTMjrOR/pWYiGGFjAxsOLBApE # jCtUSRDzFe4wX+rw0BgzRaCJ56L5QZbth2T0vUABPsaR6rcJmC3TN/QWiZvEQ4vE # Ay5cMzWC2uMc5lpGxLucksn1ZXDwpF4P4Pl4Ys9/scEZbq+OvrnjXjRJwINXLoPd # 4T0JR6G3Nr+4FAmKY7D0n8Qfmok9UVukEMnzOnlm4UOlJCYmgsa2+7TGX2v3G9C6 # bOCcU9PipEhF4kQyaYeUmofvZFXlr4XQyHsiebGdrmn0E5c0ju2Wctg/1Lg1 # SIG # End signature block |