Script — PowerShell Prep for Azure & Graph

This script preps your PowerShell environment with the latest Microsoft Graph API and Az modules. It cleans up conflicting legacy modules, handles version management, and installs everything you need to get going.

Note: The ActiveDirectory module comes from RSAT (Remote Server Administration Tools) and isn't installed by this script.

# Clear output
Clear-Host

# ── Helper Functions ──────────────────────────────────────────────
function formatInfo    { param($msg) Write-Host "[INFO] $msg" -ForegroundColor Cyan }
function formatSuccess { param($msg) Write-Host "[OK]   $msg" -ForegroundColor Green }
function formatWarning { param($msg) Write-Host "[WARN] $msg" -ForegroundColor Yellow }
function formatError   { param($msg) Write-Host "[ERR]  $msg" -ForegroundColor Red }

# ── Check Admin Context ───────────────────────────────────────────
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
    formatError "This script must be run as Administrator."
    exit 1
}
formatSuccess "Running as Administrator."

# ── Execution Policy ──────────────────────────────────────────────
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
formatSuccess "Execution policy set to RemoteSigned."

# ── NuGet Provider ────────────────────────────────────────────────
if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) {
    formatInfo "Installing NuGet package provider..."
    Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force | Out-Null
    formatSuccess "NuGet provider installed."
} else {
    formatSuccess "NuGet provider already installed."
}

# ── PSGallery Trust ───────────────────────────────────────────────
if ((Get-PSRepository -Name PSGallery).InstallationPolicy -ne 'Trusted') {
    Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
    formatSuccess "PSGallery set to Trusted."
} else {
    formatSuccess "PSGallery already Trusted."
}

# ── RSAT Check ────────────────────────────────────────────────────
$rsat = Get-WindowsCapability -Online | Where-Object { $_.Name -like 'Rsat.ActiveDirectory*' -and $_.State -eq 'Installed' }
if ($rsat) {
    formatSuccess "RSAT ActiveDirectory tools installed."
} else {
    formatWarning "RSAT ActiveDirectory tools not found. Install via Settings > Optional Features if needed."
}

# ── Remove Conflicting System-Level Modules ───────────────────────
$systemModulePath = "C:\Program Files\WindowsPowerShell\Modules"
$conflicting = @('AzFilesHybrid', 'AzureAD', 'AzureADPreview')
foreach ($mod in $conflicting) {
    $modPath = Join-Path $systemModulePath $mod
    if (Test-Path $modPath) {
        formatWarning "Removing conflicting system module: $mod"
        Remove-Item -Path $modPath -Recurse -Force
        formatSuccess "Removed $mod from system modules."
    }
}

# ── Remove Old User-Level Conflicting Modules ─────────────────────
foreach ($mod in $conflicting) {
    $installed = Get-InstalledModule -Name $mod -ErrorAction SilentlyContinue
    if ($installed) {
        formatWarning "Uninstalling user module: $mod"
        Uninstall-Module -Name $mod -AllVersions -Force -ErrorAction SilentlyContinue
        formatSuccess "Uninstalled $mod."
    }
}

# ── Microsoft Graph Module ────────────────────────────────────────
# The top-level Microsoft.Graph module includes all sub-modules
# (Authentication, Users, Groups, Identity.DirectoryManagement, etc.)
$graphInstalled = Get-InstalledModule -Name Microsoft.Graph -ErrorAction SilentlyContinue
$graphLatest = Find-Module -Name Microsoft.Graph -Repository PSGallery

if ($graphInstalled) {
    if ($graphInstalled.Version -lt $graphLatest.Version) {
        formatInfo "Updating Microsoft.Graph from $($graphInstalled.Version) to $($graphLatest.Version)..."
        # Remove old versions first
        $allVersions = Get-InstalledModule -Name Microsoft.Graph -AllVersions
        foreach ($v in $allVersions) {
            if ($v.Version -ne $graphLatest.Version) {
                formatInfo "Removing old Graph version: $($v.Version)"
                Uninstall-Module -Name Microsoft.Graph -RequiredVersion $v.Version -Force -ErrorAction SilentlyContinue
            }
        }
        Install-Module -Name Microsoft.Graph -Force -AllowClobber
        formatSuccess "Microsoft.Graph updated to $($graphLatest.Version)."
    } else {
        formatSuccess "Microsoft.Graph is up to date ($($graphInstalled.Version))."
    }
} else {
    formatInfo "Installing Microsoft.Graph $($graphLatest.Version)..."
    Install-Module -Name Microsoft.Graph -Force -AllowClobber
    formatSuccess "Microsoft.Graph installed."
}

# ── Az Modules ────────────────────────────────────────────────────
$azInstalled = Get-InstalledModule -Name Az -ErrorAction SilentlyContinue
$azLatest = Find-Module -Name Az -Repository PSGallery

if ($azInstalled) {
    if ($azInstalled.Version -lt $azLatest.Version) {
        formatInfo "Updating Az from $($azInstalled.Version) to $($azLatest.Version)..."
        $allAzVersions = Get-InstalledModule -Name Az -AllVersions
        foreach ($v in $allAzVersions) {
            if ($v.Version -ne $azLatest.Version) {
                formatInfo "Removing old Az version: $($v.Version)"
                Uninstall-Module -Name Az -RequiredVersion $v.Version -Force -ErrorAction SilentlyContinue
            }
        }
        Install-Module -Name Az -Force -AllowClobber
        formatSuccess "Az updated to $($azLatest.Version)."
    } else {
        formatSuccess "Az is up to date ($($azInstalled.Version))."
    }
} else {
    formatInfo "Installing Az $($azLatest.Version)..."
    Install-Module -Name Az -Force -AllowClobber
    formatSuccess "Az installed."
}

# ── Az Config ─────────────────────────────────────────────────────
Update-AzConfig -DisplayBreakingChangeWarning $false -ErrorAction SilentlyContinue
formatSuccess "Az breaking change warnings disabled."

formatSuccess "`nEnvironment preparation complete."