Public/Uninstall-Graph.ps1

<#
    .SYNOPSIS
    Completely uninstalls and removes all Microsoft Graph PowerShell modules from the system.

    .DESCRIPTION
    Microsoft Graph comes with a large number of modules and the installed versions and dependencies can sometimes cause issues when trying to update or reinstall them.

    Another side effect is seeing multiple authentication prompts when using Microsoft Graph cmdlets, which can be frustrating.

    Uninstalling the Microsoft Graph PowerShell modules can help resolve these issues by ensuring a clean slate.

    However, the uninstallation process can be tricky because Microsoft Graph PowerShell modules
    are often interdependent, making it difficult to remove them cleanly in one go using the `Uninstall-Module` cmdlet.

    This function is designed to ensure that all Microsoft Graph modules are thoroughly removed from your system,
    and restore your PowerShell environment to a clean state.

    You can then download and do a fresh install of the latest version of Microsoft Graph PowerShell modules.

    .PARAMETER SkipAdminCheck
    Skips the administrator privileges check on Windows systems.

    .PARAMETER Entra
    Uninstalls only Microsoft.Entra* modules (does not remove Microsoft Graph modules).

    .PARAMETER All
    Uninstalls both Microsoft Graph and Microsoft.Entra* modules.

    .EXAMPLE
    Uninstall-Graph

    Runs the function with default settings to remove Microsoft Graph modules.

    .EXAMPLE
    Uninstall-Graph -SkipAdminCheck

    Runs the function without checking for administrator privileges.

    .EXAMPLE
    Uninstall-Graph -Entra

    Uninstalls only Microsoft Entra modules.

    .EXAMPLE
    Uninstall-Graph -All

    Uninstalls both Microsoft Graph and Microsoft Entra modules.
#>

function Uninstall-Graph {
    [CmdletBinding()]
    param(
        [switch]$SkipAdminCheck,
        [switch]$Entra,
        [switch]$All
    )

    # Main execution
    Write-Host "=== Microsoft Graph PowerShell Module Uninstaller ===" -ForegroundColor Cyan
    if ($All) {
        Write-Host "This cmdlet will completely remove all Microsoft Graph and Microsoft Entra PowerShell modules from your system." -ForegroundColor White
    } elseif ($Entra) {
        Write-Host "This cmdlet will completely remove all Microsoft Entra PowerShell modules from your system." -ForegroundColor White
    } else {
        Write-Host "This cmdlet will completely remove all Microsoft Graph PowerShell modules from your system." -ForegroundColor White
    }
    Write-Host "If you run into issues, try running with -Verbose for more info." -ForegroundColor White
    Write-Host ""

    # Check if running as administrator on Windows
    if (-not $SkipAdminCheck -and ($PSVersionTable.PSVersion.Major -lt 6 -or ($PSVersionTable.PSVersion.Major -ge 6 -and $IsWindows))) {
        if (-not (Test-IsAdmin)) {
            Write-Error "We recommend running with administrator privileges. If you are unable to run as administrator, please use the -SkipAdminCheck parameter to run without Administrator privileges."
            return
        }
    }

    $iteration = 1
    $maxIterations = 10

    do {
        Write-Host "=== Iteration $iteration ===" -ForegroundColor Blue

        # Get all Graph modules (both installed and available)
        $allGraphModules = Get-GraphModules -IncludeGraph:$(!$Entra) -IncludeEntra:($Entra -or $All)
        $installedGraphModules = Get-InstalledGraphModules -IncludeGraph:$(!$Entra) -IncludeEntra:($Entra -or $All)

        if ($allGraphModules.Count -eq 0 -and $installedGraphModules.Count -eq 0) {
            if ($All) {
                Write-ColorOutput "[+] No Microsoft Graph or Entra modules found. Cleanup complete!" -ForegroundColor Green
            } elseif ($Entra) {
                Write-ColorOutput "[+] No Microsoft Entra modules found. Cleanup complete!" -ForegroundColor Green
            } else {
                Write-ColorOutput "[+] No Microsoft Graph modules found. Cleanup complete!" -ForegroundColor Green
            }
            break
        }

        Write-Host "Found $($allGraphModules.Count) Graph modules in module paths" -ForegroundColor White
        Write-Host "Found $($installedGraphModules.Count) installed Graph modules from PowerShell Gallery" -ForegroundColor White

        # First, try to uninstall using Uninstall-Module for gallery-installed modules
        if ($installedGraphModules.Count -gt 0) {
            Write-ColorOutput "`n[x] Uninstalling modules using Uninstall-Module..." -ForegroundColor Yellow
            Uninstall-GraphModulesFromGallery -InstalledModules $installedGraphModules -Force:$Force
        }

        # Then remove any remaining module directories
        if ($allGraphModules.Count -gt 0) {
            Write-ColorOutput "`n[-] Cleaning up remaining module directories..." -ForegroundColor Yellow
            Remove-ModuleDirectories -Modules $allGraphModules
        }

        # Force garbage collection to release any locks
        [System.GC]::Collect()
        [System.GC]::WaitForPendingFinalizers()

        Start-Sleep -Seconds 2

        $iteration++

        if ($iteration -gt $maxIterations) {
            Write-Warning "Reached maximum iterations ($maxIterations). Some modules may still remain."
            $remainingModules = Get-GraphModules
            if ($remainingModules.Count -gt 0) {
                Write-Host "`nRemaining modules:" -ForegroundColor Red
                $remainingModules | ForEach-Object { Write-Host " - $($_.Name) ($($_.Version)) at $($_.ModuleBase)" -ForegroundColor Red }
                Write-Host "`nYou may need to manually remove these modules or restart your PowerShell session." -ForegroundColor Yellow
            }
            break
        }

    } while ($true)

    Write-Host "`n=== Cleanup Summary ===" -ForegroundColor Magenta

    # Final check
    $finalGraphModules = Get-GraphModules -IncludeGraph:$(!$Entra) -IncludeEntra:($Entra -or $All)
    $finalInstalledModules = Get-InstalledGraphModules -IncludeGraph:$(!$Entra) -IncludeEntra:($Entra -or $All)

    if ($finalGraphModules.Count -eq 0 -and $finalInstalledModules.Count -eq 0) {
        if ($All) {
            Write-ColorOutput "[*] All Microsoft Graph and Entra PowerShell modules have been successfully removed!" -ForegroundColor Green
            Write-ColorOutput "[*] Your system is now clean of Microsoft Graph and Entra PowerShell modules." -ForegroundColor Green
        } elseif ($Entra) {
            Write-ColorOutput "[*] All Microsoft Entra PowerShell modules have been successfully removed!" -ForegroundColor Green
            Write-ColorOutput "[*] Your system is now clean of Microsoft Entra PowerShell modules." -ForegroundColor Green
        } else {
            Write-ColorOutput "[*] All Microsoft Graph PowerShell modules have been successfully removed!" -ForegroundColor Green
            Write-ColorOutput "[*] Your system is now clean of Microsoft Graph PowerShell modules." -ForegroundColor Green
        }
        Write-ColorOutput "[>] We recommend closing this window and starting a new PowerShell session." -ForegroundColor Green
    }
    else {
        Write-ColorOutput "[!] Some modules may still remain:" -ForegroundColor Yellow
        if ($finalGraphModules.Count -gt 0) {
            Write-Host " - $($finalGraphModules.Count) modules found in module paths" -ForegroundColor Red
        }
        if ($finalInstalledModules.Count -gt 0) {
            Write-Host " - $($finalInstalledModules.Count) installed modules from PowerShell Gallery" -ForegroundColor Red
        }
        Write-Host " You may need to restart PowerShell and run this script again." -ForegroundColor Yellow
    }
}