Installed Visual Studio 2026 But Your Azure Pipeline Skips Every SDK-Style Project? Check Which MSBuild Is Actually Running.

September 25, 2026
Installed Visual Studio 2026 But Your Azure Pipeline Skips Every SDK-Style Project? Check Which MSBuild Is Actually Running.

I was setting up an Azure Pipelines build for a client on a self-hosted agent. The solution is a mix of old-style .NET Framework projects and newer SDK-style projects that want the .NET 10 SDK, and it uses one of the new .slnx solution files. All of that needs Visual Studio 2026. So Visual Studio 2026 went on the agent, I queued the build, and the restore step spat out a wall of these:

warning NU1503: Skipping restore for project 'C:\agent\_work\1\s\Something\Something.csproj'. The project file may be invalid or missing targets required for restore.

One for every SDK-style project in the solution. And then the build carried on without them, because NU1503 is a warning, not an error. The old-style projects built. The new ones just...weren't there.

The Short Version

  • NU1503: Skipping restore for project on SDK-style projects is a warning, so the build keeps going without those projects. Don't miss it.
  • The VSBuild@1 task with vsVersion: latest runs vswhere -version [17.0,18.0). That range means "newest Visual Studio 2022." VS 2026 is 18.x and never gets considered.
  • VS 2022's MSBuild can't load the .NET 10 SDK, so every project that needs it gets skipped.
  • Fix: locate MSBuild yourself with vswhere.exe in a PowerShell step and call it directly. Print msbuild -version so the log shows which one ran.
  • This recurs at every Visual Studio major release. Owning the lookup is the durable fix.

What NU1503 Actually Means Here

The message says "the project file may be invalid or missing targets required for restore." The project files were fine. What it really meant was "the MSBuild that's running can't load the SDK these projects ask for, so I'm pretending they don't exist."

The build was running under Visual Studio 2022's MSBuild. Visual Studio 2022 (17.x) can't load the .NET 10 SDK. VS 2026 was right there on the box, but nobody was using it.

Why the VSBuild Task Picked VS 2022

The pipeline used the standard VSBuild@1 task with vsVersion: latest. "Latest" sounds like it means "the newest one you can find." Look at what the task actually ran, though. It's right there in the log:

vswhere.exe -version [17.0,18.0) -latest -format json

That's a version range. [17.0,18.0) means "17.0 or higher, but less than 18.0." In other words, "the newest Visual Studio 2022." Visual Studio 2026 is 18.x, so it's outside the range and the task never considers it. "Latest" has a ceiling and the ceiling is whatever the task knew about when it shipped.

This isn't a bug so much as lag. The build tasks have to be updated to know about each new Visual Studio major, and if you're on Azure DevOps Server (on-prem) you get task updates when the server gets patched, not when Microsoft publishes them. So there's a window after every new Visual Studio release where the tasks are behind. Right now we're in that window for VS 2026.

(For what it's worth, the MSBuild@1 task uses the same helper library, so switching tasks doesn't help.)

The Fix: Find MSBuild Yourself

Stop depending on the task to locate MSBuild. Visual Studio ships a tool called vswhere.exe that's built for exactly this and it's always at the same path. Two PowerShell steps replace the VSBuild task:

- task: PowerShell@2
  displayName: Find MSBuild (VS 2026)
  inputs:
    targetType: inline
    pwsh: true
    script: |
      $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
      $msbuild = & $vswhere -latest -prerelease -products * -version '[18.0,19.0)' `                   -requires Microsoft.Component.MSBuild -find 'MSBuild\**\Bin\MSBuild.exe' |
                 Select-Object -First 1
      if (-not $msbuild) { throw "No Visual Studio 2026 (18.x) with MSBuild found on this agent" }
      "Using $msbuild"
      & $msbuild -version
      Write-Host "##vso[task.setvariable variable=msbuildPath]$msbuild"

- task: PowerShell@2
  displayName: Build
  inputs:
    targetType: inline
    pwsh: true
    script: |
      & "$(msbuildPath)" MySolution.slnx -restore -p:RestorePackagesConfig=true `          -p:Configuration=Release "-p:Platform=Any CPU" -m -nologo
      if ($LASTEXITCODE -ne 0) { throw "msbuild exited with $LASTEXITCODE" }

A few notes on that:

  • -version '[18.0,19.0)' pins it to VS 2026. When VS 2027 (or whatever they call it) comes out, you'll change that one string. If you'd rather it always take the newest, drop the -version argument entirely.
  • -products * makes it look at Community, Professional, Enterprise and Build Tools. Without it, Build Tools installs get skipped.
  • -prerelease lets it find a Preview install. Take it out if you only want release builds of Visual Studio.
  • The first step prints msbuild -version, so the log tells you which one ran. That's the line I wish I'd had on the first run.
  • -restore plus -p:RestorePackagesConfig=true restores both PackageReference and old packages.config projects in one go, which matters if you've got a mixed solution like I did. dotnet build can't do the packages.config half.

Once that was in, all the SDK-style projects restored and built. Same agent, same solution, same code. The only thing that changed was which MSBuild got called.

How to Tell This Is Your Problem

If you're seeing NU1503 on SDK-style projects and you're not sure this is it:

  1. Find the vswhere.exe line in the build log and look at the -version range.
  2. Find the msbuild.exe line right after it and look at the path. If it says \2022\ and you were expecting 2026, that's it.
  3. On the agent, run "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -all -products * -property installationPath to see every Visual Studio the box actually has.

Summary

  1. Installing Visual Studio 2026 on your build agent isn't enough. The VSBuild@1 task (and MSBuild@1) searches a hard-coded version range of [17.0,18.0) and will keep picking Visual Studio 2022 until the task is updated.
  2. When VS 2022's MSBuild meets SDK-style projects that need the .NET 10 SDK, you get NU1503: Skipping restore warnings, not errors, and those projects silently drop out of the build.
  3. Locate MSBuild yourself with vswhere.exe in a PowerShell step, then call it directly. Print msbuild -version so the log shows which one ran.
  4. This will happen again at the next Visual Studio major. Owning the MSBuild lookup is the durable fix.

I hope this helps.

-Ben

If you're trying to get an old codebase building on a modern pipeline, that's the kind of work I do. Let's talk.

Categories: devops