Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AzureAuth Windows uninstall script #340

Merged
merged 15 commits into from
Oct 12, 2023
Merged
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
132 changes: 132 additions & 0 deletions install/uninstall.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Enable a default -Verbose flag for debug output.
[CmdletBinding()]
$VerbosePreference = "Continue"

# Halt script execution at the first failed command.
$script:ErrorActionPreference='Stop'

$azureauthDefaultLocation = ([System.IO.Path]::Combine($Env:LOCALAPPDATA, "Programs", "AzureAuth"))

function Get-CustomLocationsFromPath {
$customLocations = [System.Collections.ArrayList]@()
$azureauthsInPath = (Get-Command -Name azureauth -ErrorAction SilentlyContinue -CommandType Application -All).Source

ForEach($az in $azureauthsInPath) {
$azureauthParent = (Get-Item $az).Directory.FullName
if (!(Is-ChildOfDefaultLocation($azureauthParent))) {
$_ = $customLocations.Add($azureauthParent)
}
}

return $customLocations
}

function Write-WarningForCustomLocations {
# We only warn the user of any custom locations that are found in the PATH.
# Installations in custom locations that are not listed in PATH cannot
# be found and uninstalled.
$customLocations = Get-CustomLocationsFromPath
$customLocationsCount = $customLocations.Count

if ($customLocationsCount -ne 0) {
$warning = "Uninstallation from custom locations is unsupported. Custom locations must be removed manually.
`rFound ${customLocationsCount} potential installations outside of the default location:"
ForEach($location in $customLocations) {
$warning += "`n ${location}"
}
Write-Warning $warning
}
}

# Send WM_SETTINGCHANGE after changing Environment variables.
# Refer to https://gist.github.com/alphp/78fffb6d69e5bb863c76bbfc767effda
function Send-SettingChange {
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
"@
$HWND_BROADCAST = [IntPtr] 0xffff;
$WM_SETTINGCHANGE = 0x1a;
$result = [UIntPtr]::Zero

[void] ([Win32.Nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 5000, [ref] $result))
}

function Is-ChildOfDefaultLocation {
param ([string]$path)

$parent = (Split-Path $path -Parent)
return ($parent -eq $azureauthDefaultLocation)
}

function Remove-FromPath {
$registryPath = 'Registry::HKEY_CURRENT_USER\Environment'
$currentPath = (Get-ItemProperty -Path $registryPath -Name PATH -ErrorAction SilentlyContinue).Path

# Reconstruct the $PATH without any azureauth directories.
$updatedPath = "";
if (($null) -ne $currentPath) {
$paths = $currentPath.Split(";")
$pathArr = @()
ForEach($path in $paths){
if(!$path.Equals("") -And !(Is-ChildOfDefaultLocation($path))) {
$pathArr += "${path}"
}
elseif (!$path.Equals("")) {
Write-Verbose "Removing PATH entry '${path}'"
}
}
$updatedPath = ($pathArr -join ";") + ";"
}

Set-ItemProperty -Path $registryPath -Name PATH -Value $updatedPath
Send-SettingChange
}

function Remove-InstallationFolder {
param ([string]$directory)

if (Test-Path -Path $directory) {
Write-Verbose "Removing all installations at '${directory}'"
Remove-Item -Force -Recurse $directory
} else {
Write-Verbose "There were no installations found at '${directory}'"
}
}

function Remove-Directories {
Remove-InstallationFolder $azureauthDefaultLocation
}

function Kill-Process {
# Uninstall will fail if there are instances of AzureAuth running.
# We suppress taskkill output here because this is a best effort attempt and we don't want the user to see its output.
# Here, Get-Process is used to first determine whether there is an existing azureauth process. If there is, kill the existing process first.
$ProcessCheck = Get-Process -Name azureauth -ErrorAction SilentlyContinue -ErrorVariable ProcessError
if ($null -ne $ProcessCheck) {
Write-Verbose "Stopping any currently running azureauth instances"
taskkill /f /im azureauth.exe 2>&1 | Out-Null

# After killing the process it is still possible for there there to be locks on the files it was using (including
# its own DLLs). The OS may take an indeterminate amount of time to clean those up, but so far we've observed 1
# second to be enough.
Start-Sleep -Seconds 1
}
}

function Uninstall {
if (![string]::IsNullOrEmpty($Env:AZUREAUTH_INSTALL_DIRECTORY) `
-And $Env:AZUREAUTH_INSTALL_DIRECTORY -ne $azureauthDefaultLocation) {
Write-Warning "Ignoring AZUREAUTH_INSTALL_DIRECTORY environment variable. Uninstallation for custom locations is not supported."
}

Kill-Process

Remove-Directories
Remove-FromPath

Write-WarningForCustomLocations
Write-Output "Uninstalled AzureAuth!"
}

Uninstall