functions/Confirm-UdeVs2022Installation.ps1


<#
    .SYNOPSIS
        Confirms the installation of Visual Studio 2022.
         
    .DESCRIPTION
        Checks if Visual Studio 2022 is installed on the machine and if the required components are present.
         
        Will prepare necessary files to assist in installing missing components.
         
    .PARAMETER Path
        The path to the directory where prerequisite files will be stored.
         
        Defaults to "C:\Temp\d365bap.tools\Vs2022-Ude-Prerequisites".
         
    .PARAMETER Latest
        Instructs the function to use the latest configuration files from the internet instead of the bundled ones.
         
    .EXAMPLE
        PS C:\> Confirm-UdeVs2022Installation
         
        This command checks for the installation of Visual Studio 2022 and prepares prerequisite files in the default path.
        Will use the bundled configuration files.
         
    .EXAMPLE
        PS C:\> Confirm-UdeVs2022Installation -Latest
         
        This command checks for the installation of Visual Studio 2022 and prepares prerequisite files in the default path.
        Will download the latest configuration files from the internet.
         
    .NOTES
        Author: Mötz Jensen (@Splaxi)
#>

function Confirm-UdeVs2022Installation {
    [CmdletBinding()]
    param (
        [string] $Path = 'C:\Temp\d365bap.tools\Vs2022-Ude-Prerequisites',

        [switch] $Latest
    )

    begin {
        # Safest way to detect VS 2022 installation is via WMI
        $wmiObj = Get-CimInstance -ClassName MSFT_VSInstance `
            -Namespace root/cimv2/vs | `
            Where-Object { $_.Name -like "Visual Studio*2022" }

        if ($null -eq $wmiObj) {
            $messageString = "Visual Studio 2022 Professional or Enterprise does not appear to be installed on this machine. Please install Visual Studio 2022 Professional or Enterprise with the required workloads and try again."
            Write-PSFMessage -Level Host -Message $messageString -Target Host
            Stop-PSFFunction -Message "Stopping because Visual Studio 2022 was NOT installed." -Exception $([System.Exception]::new($($messageString -replace '<[^>]+>', '')))
            return
        }
        
        # Path for VS_Installer.exe
        $pathVsInstaller = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe"

        # Sub paths for extensions
        $pathExtSuffix = "\Extensions\*\*.vsixmanifest"
        $pathCommonExtSuffix = "\CommonExtensions\Microsoft\*\*.vsixmanifest"

        # Paths to extensions
        $pathVs2022Ext = $wmiObj.ProductLocation.Replace("devenv.exe", $pathExtSuffix)
        $pathVs2022CommonExt = $wmiObj.ProductLocation.Replace("devenv.exe", $pathCommonExtSuffix)
        
        New-Item -Path $Path `
            -ItemType Directory `
            -Force `
            -WarningAction SilentlyContinue > $null

        if (-not [System.IO.Path]::Exists("$Path\Vs2022.Extensions.json")) {
            if (-not $Latest) {
                Copy-Item -Path "$script:ModuleRoot\internal\misc\Vs2022.Extensions.json" `
                    -Destination "$Path\Vs2022.Extensions.json" `
                    -Force
            }
            else {
                <# Action when all if and elseif conditions are false #>
            }
        }

        if (-not [System.IO.Path]::Exists("$Path\Full-Ude.vsconfig")) {
            if (-not $Latest) {
                Copy-Item -Path "$script:ModuleRoot\internal\misc\Full-Ude.vsconfig" `
                    -Destination "$Path\Full-Ude.vsconfig" `
                    -Force
            }
            else {
                <# Action when all if and elseif conditions are false #>
            }
        }
    }

    process {
        if (Test-PSFFunctionInterrupt) { return }

        Write-PSFMessage -Level Host -Message "Starting the <c='em'>Visual Studio Installer</c>:" -Target Host
        Write-PSFMessage -Level Host -Message " - You will need to click <c='em'>Modify</c> or <c='em'>Close</c> when prompted." -Target Host
        Write-PSFMessage -Level Host -Message " - When the installation is finished, you will need to <c='em'>Close</c> the <c='em'>Visual Studio Installer</c> window." -Target Host

        # We need to make sure VS 2022 has the basic workloads installed
        Start-Process -FilePath $pathVsInstaller `
            -ArgumentList "modify --config `"$Path\Full-Ude.vsconfig`" --installPath `"$($wmiObj.InstallLocation)`"" `
            -Wait

        # List of extensions to validate against
        $colExt = (Get-Content "$Path\Vs2022.Extensions.json") | ConvertFrom-Json

        $colManifests = @(Get-Item -Path $pathVs2022Ext | Select-Object -ExpandProperty FullName)
        $colManifests += @(Get-Item -Path $pathVs2022CommonExt | Select-Object -ExpandProperty FullName)

        # Create hashtable of installed extensions
        $hashExtInstalled = @{}
        foreach ($pathManifest in $colManifests) {
            [xml]$xmlMani = Get-Content -Path $pathManifest -Raw

            if ($null -eq $xmlMani.PackageManifest.Metadata.Identity.Id) { continue }

            $hashExtInstalled[$($xmlMani.PackageManifest.Metadata.Identity.Id)] = [ordered]@{
                Id      = $xmlMani.PackageManifest.Metadata.Identity.Id
                Name    = $xmlMani.PackageManifest.Metadata.DisplayName
                Version = $xmlMani.PackageManifest.Metadata.Identity.Version
            }
        }

        # Download missing extensions
        foreach ($ext in $colExt | Where-Object VsixUrl -ne $null) {
            if ($null -ne $hashExtInstalled[$ext.Id]) {
                continue
            }

            Write-PSFMessage -Level Host -Message "Extension: '<c='em'>$($ext.Name)</c>' is missing." -Target Host

            Write-PSFMessage -Level Host -Message " - <c='em'>Downloading</c>..." -Target Host
            
            $file = (Split-Path -Path $ext.Uri -Leaf).Split('.') | Select-Object -Last 1
            Invoke-WebRequest -Uri $ext.VsixUrl `
                -OutFile "$Path\$file.vsix" `
                -UseBasicParsing `
                -ErrorAction Stop > $null

            Write-PSFMessage -Level Host -Message " - <c='em'>Installing</c> - Please make sure to let the VSIX installer finish..." -Target Host

            Start-Process -FilePath "$Path\$file.vsix" `
                -Wait
        }
    }
}