[小ネタ] Windows Server 2022 EC2にWindows Terminalをインストールする (ついでにwingetも)

2021.09.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

小ネタです。

先月リリースされたWindows Server 2022はOSのビルドバージョンとしては10.0.20348でありWindows Terminalがインストール可能なビルドとなります。

というわけで誰もがWindows Server 2022にWindows Terminalをインストールしようと考えるに決まっており既に先駆者もいるわけです。
たとえば以下は元MVPで現Microsoft社員のThomas MaurerさんのブログでWindows Server 2022プレビュー時点から既に試されています。

まあ、OSのビルドバージョンさえクリアできていればインストール方法自体は非常にシンプルで、GitHubのリリースページからmsixbundleファイルをダウンロードしてやるだけです。

簡単なPowerShell関数を作りましたので以下のスクリプトを実行すれば最新のWindows Terminalをサクッとインストールできます。

2022年6月24日追記
現在最新のWindows Terminal 1.13以降ではインストーラーがWindows 10/Windows 11で分離したのに加え、Windows 10環境ではVC Runtimeの事前インストールが必要になっています。
Windows Server 2022ではWindows 10のインストール手順を行ってください。

2023年10月23日さらに追記
さらに新しいバージョンで Microsoft.UI.Xaml への依存関係が増えたためスクリプトの内容を再度見直しています。

#
# ※ブログ初回公開時と内容が異なります (2023年10月アップデート済み)
#
function Install-LatestWindowsTerminal ([switch]$SkipInstallVCLibs) {
    # Check OS version
    $buildVersion = [Version](Get-CimInstance -ClassName 'Win32_OperatingSystem' -Property Version | Select-Object -ExpandProperty Version)
    $isWin11 = if ($buildVersion -ge ([Version]"10.0.22000.0") ) { $true } else { $false }
    
    # Get the latest release information
    $latest = Invoke-RestMethod -Uri 'https://api.github.com/repos/microsoft/terminal/releases/latest'
    $installerUrl = $latest.assets | Where-Object { $_.browser_download_url -like '*.msixbundle_Windows10_PreinstallKit.zip' } | Select-Object -ExpandProperty browser_download_url -First 1
    if ([string]::IsNullOrEmpty($installerUrl)) {
        Write-Error 'Failed to get the installer url'
        return
    }

    # For Windows 10, Need to install VCLibs
    if ((-not $isWin11) -and (-not $SkipInstallVCLibs)) {
        $vcLibsUrl = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx'
        Write-Host -ForegroundColor Green "Download $vcLibsUrl"
        Add-AppxPackage -Path $vcLibsUrl
    }

    # Download zip and expand items
    Write-Host -ForegroundColor Green "Download $installerUrl"
    $zipPath = Join-Path -Path ([IO.Path]::GetTempPath()) ($installerUrl -split '/')[-1]
    try {
        $client = [System.Net.WebClient]::new() 
        $client.DownloadFile($installerUrl, $zipPath)
    } finally {
        $client.Dispose()
    }

    Add-Type -AssemblyName System.IO.Compression.FileSystem
    $xamlUIPath = ''
    $bundlePath = ''
    try {
        $archive = [System.IO.Compression.ZipFile]::OpenRead($zipPath)
        # Extract Microsoft.UI.Xaml appx 
        $archName = switch ($env:PROCESSOR_ARCHITECTURE) {
            'x86' { 'x86' }
            'AMD64' { 'x64' }
            'ARM64' { 'arm64' }
            Default { 'x64' }
        }
        $item = $archive.Entries | Where-Object { $_.FullName -like "Microsoft.UI.Xaml*_${archName}*.appx" } | Select-Object -First 1
        if ($item) {
            $xamlUIPath = Join-Path -Path ([IO.Path]::GetTempPath()) ($item.Name)
            Write-Host -ForegroundColor Green "Extract $($item.Name) to $xamlUIPath"
            [System.IO.Compression.ZipFileExtensions]::ExtractToFile($item, $xamlUIPath)
        }
        # Extract msixbundle
        $item = $archive.Entries | Where-Object { $_.FullName -like '*.msixbundle' } | Select-Object -First 1
        if ($item) {
            $bundlePath = Join-Path -Path ([IO.Path]::GetTempPath()) ($item.Name)
            Write-Host -ForegroundColor Green "Extract $($item.Name) to $bundlePath"
            [System.IO.Compression.ZipFileExtensions]::ExtractToFile($item, $bundlePath)
        }
    } finally {
        if ($archive) {
            $archive.Dispose()
        }
    }
    
    # Install Microsoft.UI.Xaml appx
    if (-not $isWin11) {
        Write-Host -ForegroundColor Green "Install $xamlUIPath"
        Add-AppxPackage -Path $xamlUIPath
    }

    # Install MSIX bundle
    Write-Host -ForegroundColor Green "Install $bundlePath"
    Add-AppxPackage -Path $bundlePath

    # Remove files
    ($bundlePath, $xamlUIPath, $zipPath) | ForEach-Object {
        if (Test-Path -LiteralPath $_) {
            Write-Host -ForegroundColor Green "Remove $_"
            Remove-Item -LiteralPath $_
        }
    }
    Write-Host -ForegroundColor Green "Installation complete!"
}
Install-LatestWindowsTerminal

これでよしなにWindows TerminalがインストールされWindows Server 2022で利用可能になります。

おまけ : Windows Package Manager Client (winget)をインストールする

2022年6月24日追記
現在Windows Server 2022上でのwingetの利用は試験的な機能扱いで非サポートなのでご注意ください。

  • 参考 : [FEATURE] Add support installation on Windows Server 2022
  • Windows Terminalと同様の理屈でWindows Package Manager Client (winget)もインストール可能です。

    wingetの場合はアプリケーションのmsixbunldeファイル以外にVCライブラリのインストールが必要となる点、ライセンスファイルも同時にインストールする必要があるためAdd-AppxProvisionedPackageを使う必要がある点が異なります。

    #
    # ※ブログ初回公開時と内容が異なります (2023年10月アップデート済み)
    #
    function Install-LatestWinGet ([switch]$SkipInstallVCLibs) {
        # Install prerequisites
        if (-not $SkipInstallVCLibs) {
            $vcLibsUrl = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx'
            Write-Host -ForegroundColor Green "Download $vcLibsUrl"
            Add-AppxPackage -Path $vcLibsUrl
        }
    
        # Find the latest assets url
        $latest = Invoke-RestMethod -Uri 'https://api.github.com/repos/microsoft/winget-cli/releases/latest'
        $msixUrl = $latest.assets | Where-Object { $_.browser_download_url -like '*.msixbundle' } | Select-Object -ExpandProperty browser_download_url
        $msixPath = Join-Path -Path ([IO.Path]::GetTempPath()) ($msixUrl -split '/')[-1]
        $licenseUrl = $latest.assets | Where-Object { $_.browser_download_url -like '*License1.xml' } | Select-Object -ExpandProperty browser_download_url
        $licensePath = Join-Path -Path ([IO.Path]::GetTempPath()) ($licenseUrl -split '/')[-1]
    
        # Download assets
        ( @{Url = $msixUrl ; LocalPath = $msixPath }, @{Url = $licenseUrl ; LocalPath = $licensePath } ) | ForEach-Object {
            Write-Host -ForegroundColor Green "Download $($_.Url)"
            try {
                $client = [System.Net.WebClient]::new() 
                $client.DownloadFile($_.Url, $_.LocalPath)
            } finally {
                $client.Dispose()
            }
        }
    
        # Install MSIX to provisioned package
        Write-Host -ForegroundColor Green "Install $msixPath"
        Write-Host -ForegroundColor Green "  : License $licensePath"
        Add-AppxProvisionedPackage -Online -PackagePath $msixPath -LicensePath $licensePath
        # Install Microsoft.UI.Xaml 2.7.3 (need fixed version)
        Write-Host -ForegroundColor Green "Install Microsoft.UI.Xaml 2.7.3"
        $archName = switch ($env:PROCESSOR_ARCHITECTURE) {
            'x86' { 'x86' }
            'AMD64' { 'x64' }
            'ARM64' { 'arm64' }
            Default { 'x64' }
        }
        Add-AppxPackage -Path "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.7.3/Microsoft.UI.Xaml.2.7.${archName}.appx"
        # Register MSIX 
        Write-Host -ForegroundColor Green "Registter Microsoft.DesktopAppInstaller"
        Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
    
        # Remove assets
        ($msixPath, $licensePath) | ForEach-Object {
            if (Test-Path -LiteralPath $_) {
                Write-Host -ForegroundColor Green "Remove $_"
                Remove-Item -LiteralPath $_
            }
        }
        Write-Host -ForegroundColor Green "Installation complete!"
    }
    Install-LatestWinGet

    これでwingetを使っていろいろなソフトウェアをインストールできます。
    なお、wingetインストール後はログインし直してください。

    (上図はVS Codeをインストールしてみた図)

    Gist

    一応私のGistにもコードを載せておきます。