Public/Invoke-NSPPwsh.ps1

function Invoke-NSPPwsh {
    <#
    .SYNOPSIS
        Relaunches a script or a command in PowerShell 7 (pwsh) when running in Windows PowerShell
        5.1, installing PowerShell 7 first if needed; -Elevated also makes sure it runs elevated.
        Returns $true when it relaunched (the caller should exit), $false when the session is
        already where it should be (the caller should carry on).

    .DESCRIPTION
        The PowerShell 7 counterpart of Invoke-NSPElevated, for tools that should not stay on 5.1
        (Microsoft Graph misbehaves there, and Microsoft is retiring 5.1 for Graph). Elevation and
        edition are separate questions, so this is its own function: Invoke-NSPElevated keeps its
        "same edition" behavior.

          - Already in PowerShell 7 (and elevated, with -Elevated): returns $false.
          - In PowerShell 7, not elevated, with -Elevated: hands over to Invoke-NSPElevated.
          - In 5.1: finds pwsh.exe (Get-NSPPwshPath), installs it when missing (Install-NSPPwsh;
            -NoInstall throws instead), and relaunches into it. With -Elevated and not yet
            elevated, the relaunch asks for elevation (UAC); an elevated session stays elevated
            without a second prompt.

        Same shapes as Invoke-NSPElevated: -ScriptPath (with -ArgumentList, each element quoted)
        or -Command (passed via -EncodedCommand). NSP_NO_ELEVATE=1 keeps everything in the current
        session and returns $false, as it does for Invoke-NSPElevated.

    .PARAMETER ScriptPath
        The .ps1 to relaunch. Usually $PSCommandPath.

    .PARAMETER ArgumentList
        Extra arguments for the relaunched script (ScriptPath form only).

    .PARAMETER Command
        PowerShell command text to run in pwsh (Command form).

    .PARAMETER Elevated
        Also make sure the relaunched session is elevated.

    .PARAMETER NoInstall
        Throw instead of installing PowerShell 7 when it is missing.

    .PARAMETER NoExit
        Keep the new window open after the script/command finishes.

    .PARAMETER Wait
        Block until the new process exits.

    .EXAMPLE
        if (Invoke-NSPPwsh -ScriptPath $PSCommandPath) { exit }

    .EXAMPLE
        if (Invoke-NSPPwsh -Command 'Import-Module NSP.M365.ConditionalAccess; Start-NSPConditionalAccess' -Elevated) { return }
    #>

    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Script')]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory, ParameterSetName = 'Script')][string]$ScriptPath,
        [Parameter(ParameterSetName = 'Script')][string[]]$ArgumentList = @(),
        [Parameter(Mandatory, ParameterSetName = 'Command')][string]$Command,
        [switch]$Elevated,
        [switch]$NoInstall,
        [switch]$NoExit,
        [switch]$Wait
    )

    if ($env:NSP_NO_ELEVATE -eq '1') {
        Write-Verbose 'Invoke-NSPPwsh: NSP_NO_ELEVATE=1 - staying in this session.'
        return $false
    }
    $isAdmin = Test-NSPIsAdmin
    if ((Get-NSPPowerShellEdition) -eq 'Core') {
        if (-not $Elevated -or $isAdmin) { return $false }
        $handOver = @{ NoExit = $NoExit; Wait = $Wait }
        if ($PSCmdlet.ParameterSetName -eq 'Script') { $handOver.ScriptPath = $ScriptPath; $handOver.ArgumentList = $ArgumentList } else { $handOver.Command = $Command }
        return (Invoke-NSPElevated @handOver -WhatIf:$WhatIfPreference)
    }

    $pwsh = Get-NSPPwshPath
    if (-not $pwsh) {
        if ($NoInstall) { throw 'PowerShell 7 is not installed. Install it (Install-NSPPwsh, or https://aka.ms/powershell-release?tag=stable) and run this again.' }
        $pwsh = Install-NSPPwsh
        if (-not $pwsh) {
            # Install-NSPPwsh under -WhatIf installs nothing; report the relaunch that would follow.
            if ($WhatIfPreference) { return $true }
            throw 'PowerShell 7 could not be installed.'
        }
    }

    $psArgs = New-NSPRelaunchArgument -ScriptPath $ScriptPath -ArgumentList $ArgumentList -Command $Command -NoExit:$NoExit
    $how = if ($Elevated -and -not $isAdmin) { 'Relaunch in PowerShell 7, elevated' } else { 'Relaunch in PowerShell 7' }
    if ($PSCmdlet.ShouldProcess($pwsh, "$($how): $($psArgs -join ' ')")) {
        $startArgs = @{ FilePath = $pwsh; ArgumentList = $psArgs }
        if ($Elevated -and -not $isAdmin) { $startArgs['Verb'] = 'RunAs' }
        if ($Wait) { $startArgs['Wait'] = $true }
        Start-Process @startArgs
    }
    return $true
}