How Do I Install Windows SDK Components in a Job?

Add the SDK component with the Visual Studio installer in a quiet step, or pick a Windows runner image that already ships the SDK build your project pins.

Two routes work. Run the Visual Studio installer inside a step with --add <component-id> --quiet --norestart, waiting for the process to exit, or point runs-on at a Windows runner image that already ships the SDK build your project targets so nothing is downloaded during the job. The choice matters because the images differ: GitHub's Windows Server 2022 image readme lists four installed Windows SDK builds and the Windows Server 2025 readme lists one, and WarpBuild Windows images carry the same tooling as the GitHub-hosted equivalents (preinstalled software, checked on 2026-08-13).

Answer

The Visual Studio installer sits at its standard location, C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe, and the instance it manages on the Windows images is Visual Studio Enterprise 2022 at C:\Program Files\Microsoft Visual Studio\2022\Enterprise (Windows Server 2022 image readme). Adding an SDK component means calling that installer in modify mode against that install path. Component and workload IDs are published by Microsoft in the Visual Studio component ID reference, and the argument list is documented in the command line parameters reference.

name: windows-native-build

on:
  pull_request:

jobs:
  build:
    runs-on: warp-windows-latest-x64-8x
    steps:
      - uses: actions/checkout@v4

      - name: Add the desktop C++ workload and the 26100 SDK
        shell: pwsh
        run: |
          $installer = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe"
          $arguments = @(
            "modify",
            "--installPath", "C:\Program Files\Microsoft Visual Studio\2022\Enterprise",
            "--add", "Microsoft.VisualStudio.Workload.NativeDesktop",
            "--add", "Microsoft.VisualStudio.Component.Windows11SDK.26100",
            "--quiet", "--norestart", "--nocache"
          )
          $process = Start-Process -FilePath $installer -ArgumentList $arguments -Wait -PassThru
          if ($process.ExitCode -notin @(0, 3010)) {
            throw "Visual Studio installer exited with $($process.ExitCode)"
          }

      - uses: microsoft/setup-msbuild@v2

      - name: Build
        run: msbuild App.sln /p:Configuration=Release /p:Platform=x64

Three details decide whether this step behaves in a workflow. --quiet suppresses the interface so the installer runs unattended. Start-Process -Wait holds the step open until the installer process exits, which matters because the installer returns control early otherwise and the next step starts against a half installed toolset; the installer also accepts a --wait argument for the same purpose. Exit code 3010 means the component installed and the machine wants a restart, so treat 0 and 3010 as success and fail the step on anything else (command line parameters reference). Teams that need the SDK without the Visual Studio instance can run Microsoft's standalone installer, winsdksetup.exe, with /features + /quiet /norestart from the Windows SDK download page.

Before writing any of that, check whether the build already has what it needs. The two current Windows images differ in exactly this dimension:

Runner labelImageInstalled Windows SDK buildsSource
warp-windows-latest-x64-<size>Windows Server 202210.0.17763.0, 10.0.19041.0, 10.0.22621.0, 10.0.26100.0Windows2022-Readme.md
warp-windows-2025-x64-<size>Windows Server 202510.0.26100.0Windows2025-Readme.md

A project that pins WindowsTargetPlatformVersion to 10.0.22621.0 builds on the Windows Server 2022 label with no install step and fails on the Windows Server 2025 label until the component is added. Compare the pinned value in your .vcxproj against the readme list first, then either move the pin to a build the image carries or install the one you want. The warp-windows-2025-vs2026-x64-<size> labels run the same Windows Server 2025 base with the Visual Studio 2026 toolset (Windows Visual Studio image reference), so probe that image with Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\Include" before you pin against it. Every label, shape, and rate is listed in the Windows runner catalog.

Detail

What the install step costs per job

An installer step bills like any other minute of runner time. The arithmetic is install minutes times jobs per month times the per minute rate for the shape, and the rates come from the WarpBuild pricing page, checked on 2026-08-13.

Windows labelPer minute3 install minutes across 1,000 jobs6 install minutes across 1,000 jobs
warp-windows-latest-x64-4x$0.016$48.00$96.00
warp-windows-latest-x64-8x$0.032$96.00$192.00
warp-windows-latest-x64-16x$0.064$192.00$384.00
warp-windows-latest-x64-32x$0.128$384.00$768.00

Read your own install duration off the step timing in a job log and substitute it. Selecting a label whose image already carries the component takes that column to zero, which is the whole argument for checking the readme before adding the step.

The custom image route

Teams that need the same components on every run, and cannot get them from a stock image, build the image once. On BYOC that is a custom VM image in your own cloud account, and custom VM images documents the Windows requirements: aria2 must be present and on the system PATH, an AWS instance must be sysprepped before the image is created, and jobs run as the runneradmin user, which is the same user GitHub's Windows runners use. There is no additional cost for using a custom VM image (pricing). The custom runner image guide covers the build and registration loop.

Snapshot runners, which boot a later job from a captured runner state, cover Linux x64 and Linux ARM64, so on Windows the custom image is the route that removes a repeated install from the job path.

Windows SDK, .NET SDK, and Windows App SDK are separate installs

The Windows SDK carries the Win32 headers, libraries, and tools that a native build links against, and it arrives through the Visual Studio installer or the standalone installer above. The .NET SDK is installed with actions/setup-dotnet and pinned in global.json. The Windows App SDK arrives as a NuGet package restored by the project, and the Visual Studio component group Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs is already listed on the Windows Server 2022 image. An MSB8036 error names a missing Windows SDK build specifically, so reach for the Visual Studio installer or a different label when you see it, and leave the other two installs alone.

Can I cache the Visual Studio installer download between jobs?

The installer pulls payloads from Microsoft and writes them into the Visual Studio instance, so actions/cache has no clean unit to restore. WarpBuild caches are not supported on Windows runners either, so the durable answer is a custom image or a label whose image already carries the component. Details are in the Windows runner catalog.

Which Visual Studio toolset ships on each Windows label?

The latest and 2025 labels carry Visual Studio Enterprise 2022 and the 2025-vs2026 labels carry Visual Studio 2026 on the same Windows Server 2025 base. The Windows Visual Studio image reference lists what each one installs.

Do I need the full workload or a single component?

A single component ID installs faster than a workload because a workload pulls its whole recommended set. Start with the component that names the SDK build, such as Microsoft.VisualStudio.Component.Windows11SDK.26100, and add Microsoft.VisualStudio.Workload.NativeDesktop only when the compiler and the C++ tooling are also missing. The Build Tools installation guide walks through both shapes.

What if the build needs a Windows SDK build older than 10.0.17763.0?

Those builds are not on either stock image, so they come from a modify call with the matching component ID or from a custom VM image. Check the ID against the Visual Studio component ID reference before you pin it.

WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.