From a63973c39ccedbd1d73e21170d96813abde18ba9 Mon Sep 17 00:00:00 2001 From: Marc Paine Date: Fri, 14 Nov 2025 10:27:34 -0800 Subject: [PATCH 1/5] Refactor vsRequirements assignment logic in tools.ps1 Because 17.14 went stable, we needed a way to run vswhere, find the VS node, and enable preview SDKs. Noah found a way to do this but he had to modify tools.ps1 because the SDK repo didn't have a VS node in our global.json https://github.com/dotnet/sdk/pull/51558/files#diff-72b8f8e899b94872c6ead31fd06ec109da15bcb9ad2af6e78103d6763a31c637 Porting his change here to see if folks want this centrally. Alternatively, I'm trying adding the vs node to global.json to see if it unblocks us. --- eng/common/tools.ps1 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 9b3ad8840fd..b4cc83b46e3 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -547,19 +547,26 @@ function LocateVisualStudio([object]$vsRequirements = $null){ }) } - if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs } + if (!$vsRequirements) { + if (Get-Member -InputObject $GlobalJson.tools -Name 'vs' -ErrorAction SilentlyContinue) { + $vsRequirements = $GlobalJson.tools.vs + } else { + $vsRequirements = $null + } + } + $args = @('-latest', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*') if (!$excludePrereleaseVS) { $args += '-prerelease' } - if (Get-Member -InputObject $vsRequirements -Name 'version') { + if ($vsRequirements -and (Get-Member -InputObject $vsRequirements -Name 'version' -ErrorAction SilentlyContinue)) { $args += '-version' $args += $vsRequirements.version } - if (Get-Member -InputObject $vsRequirements -Name 'components') { + if ($vsRequirements -and (Get-Member -InputObject $vsRequirements -Name 'components' -ErrorAction SilentlyContinue)) { foreach ($component in $vsRequirements.components) { $args += '-requires' $args += $component From 26b0a9017d5ace880dcd8974a25e47179231a583 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:29:33 -0800 Subject: [PATCH 2/5] [release/9.0] Update dependencies from dotnet/xharness (#16382) Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e5e57280efd..7fee65dbda3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -42,9 +42,9 @@ https://github.com/dotnet/arcade-services f4c27758a26b32a48a1bc480856fd771b0d8b3f0 - + https://github.com/dotnet/xharness - 3e74b96870050adc82beed3934abf93d40716012 + 6f1b3efbfb1dcb66d10e3872842bf2d87dd6a64e https://github.com/dotnet/roslyn diff --git a/eng/Versions.props b/eng/Versions.props index eb56c376195..537c1014577 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -86,6 +86,6 @@ 17.5.0 - 9.0.0-prerelease.25570.2 + 9.0.0-prerelease.25601.1 From 92e45d251889042fd956e18b28d489020298d864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Mon, 8 Dec 2025 20:41:53 +0100 Subject: [PATCH 3/5] [release/9.0] Only run source index for main builds (#16379) --- eng/common/core-templates/job/source-index-stage1.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/common/core-templates/job/source-index-stage1.yml b/eng/common/core-templates/job/source-index-stage1.yml index 662b9fcce15..ddf8c2e00d8 100644 --- a/eng/common/core-templates/job/source-index-stage1.yml +++ b/eng/common/core-templates/job/source-index-stage1.yml @@ -6,7 +6,7 @@ parameters: sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] binlogPath: artifacts/log/Debug/Build.binlog - condition: '' + condition: eq(variables['Build.SourceBranch'], 'refs/heads/main') dependsOn: '' pool: '' is1ESPipeline: '' From 5dba308d00fabb7f13bb730bff7112b7ab5068c3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 17:10:04 +0100 Subject: [PATCH 4/5] [release/9.0] Update dependencies from dotnet/arcade (#16387) Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ global.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7fee65dbda3..2f8b257ea58 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,13 +26,13 @@ https://github.com/dotnet/templating e07a90b4df2f1b41a83064cfa3164611756c3746 - + https://github.com/dotnet/arcade - c28c6307d0600513219bcd9ab028c0fedbe591ec + 92e45d251889042fd956e18b28d489020298d864 - + https://github.com/dotnet/arcade - c28c6307d0600513219bcd9ab028c0fedbe591ec + 92e45d251889042fd956e18b28d489020298d864 https://github.com/dotnet/arcade-services @@ -124,9 +124,9 @@ ef4c24166691977558e5312758df4313ab310dc0 - + https://github.com/dotnet/arcade - c28c6307d0600513219bcd9ab028c0fedbe591ec + 92e45d251889042fd956e18b28d489020298d864 diff --git a/global.json b/global.json index f67b43a494f..1ed0f53cfa1 100644 --- a/global.json +++ b/global.json @@ -7,8 +7,8 @@ "dotnet": "9.0.112" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24421.7", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24421.7", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25608.5", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25608.5", "Microsoft.Build.NoTargets": "3.7.0" } } From 79824ceb55ca3c989469eb64fb67b8fedfa9c5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Thu, 11 Dec 2025 12:17:12 +0100 Subject: [PATCH 5/5] [release/9.0] Always pass -UseBasicParsing for Invoke-WebRequest calls in powershell (#16398) --- .github/workflows/scripts/read-configuration.ps1 | 2 +- Documentation/Policy/PowershellBestPractices.md | 4 ++++ eng/common/internal-feed-operations.ps1 | 2 +- eng/common/post-build/nuget-verification.ps1 | 2 +- eng/common/tools.ps1 | 6 +++--- eng/xcopy-msbuild/install-visualstudiobuildtools.ps1 | 4 ++-- scripts/add-build-variables.ps1 | 6 +++--- scripts/cqb-utilities.ps1 | 2 +- scripts/duplicate-feed.ps1 | 6 +++--- scripts/launch-mirrors.ps1 | 2 +- scripts/list-dotnet-install-versions.ps1 | 2 +- scripts/pause-all-pipelines.ps1 | 6 +++--- 12 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.github/workflows/scripts/read-configuration.ps1 b/.github/workflows/scripts/read-configuration.ps1 index 1aeae31238e..8fd99968fda 100644 --- a/.github/workflows/scripts/read-configuration.ps1 +++ b/.github/workflows/scripts/read-configuration.ps1 @@ -53,7 +53,7 @@ function GetConfiguration { Write-Host "Fetching configuration file from $urlToConfigurationFile" try{ - $response = Invoke-WebRequest -Method GET -MaximumRetryCount 3 -Headers $headers ` + $response = Invoke-WebRequest -UseBasicParsing -Method GET -MaximumRetryCount 3 -Headers $headers ` $urlToConfigurationFile $mergeFlowConfig = ConvertFrom-Json -InputObject $response.Content -AsHashTable diff --git a/Documentation/Policy/PowershellBestPractices.md b/Documentation/Policy/PowershellBestPractices.md index ff25d5a91ec..27a9c9abe05 100644 --- a/Documentation/Policy/PowershellBestPractices.md +++ b/Documentation/Policy/PowershellBestPractices.md @@ -169,3 +169,7 @@ will force this behavior. Was this helpful? [![Yes](https://helix.dot.net/f/ip/5?p=Documentation%5CPolicy%5CPowershellBestPractices.md)](https://helix.dot.net/f/p/5?p=Documentation%5CPolicy%5CPowershellBestPractices.md) [![No](https://helix.dot.net/f/in)](https://helix.dot.net/f/n/5?p=Documentation%5CPolicy%5CPowershellBestPractices.md) + +## Always pass -UseBasicParsing to Invoke-WebRequest + +To prevent blocking execution on older versions of PowerShell after the [KB5074596](https://support.microsoft.com/help/5074596) security update. diff --git a/eng/common/internal-feed-operations.ps1 b/eng/common/internal-feed-operations.ps1 index 92b77347d99..c282d3ae403 100644 --- a/eng/common/internal-feed-operations.ps1 +++ b/eng/common/internal-feed-operations.ps1 @@ -26,7 +26,7 @@ function SetupCredProvider { $url = 'https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1' Write-Host "Writing the contents of 'installcredprovider.ps1' locally..." - Invoke-WebRequest $url -OutFile installcredprovider.ps1 + Invoke-WebRequest $url -UseBasicParsing -OutFile installcredprovider.ps1 Write-Host 'Installing plugin...' .\installcredprovider.ps1 -Force diff --git a/eng/common/post-build/nuget-verification.ps1 b/eng/common/post-build/nuget-verification.ps1 index ac5c69ffcac..eea88e653c9 100644 --- a/eng/common/post-build/nuget-verification.ps1 +++ b/eng/common/post-build/nuget-verification.ps1 @@ -65,7 +65,7 @@ if ($NuGetExePath) { Write-Host "Downloading nuget.exe from $nugetExeUrl..." $ProgressPreference = 'SilentlyContinue' try { - Invoke-WebRequest $nugetExeUrl -OutFile $downloadedNuGetExe + Invoke-WebRequest $nugetExeUrl -UseBasicParsing -OutFile $downloadedNuGetExe $ProgressPreference = 'Continue' } catch { $ProgressPreference = 'Continue' diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 9b3ad8840fd..2c6d2cef9f6 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -266,7 +266,7 @@ function GetDotNetInstallScript([string] $dotnetRoot) { Retry({ Write-Host "GET $uri" - Invoke-WebRequest $uri -OutFile $installScript + Invoke-WebRequest $uri -UseBasicParsing -OutFile $installScript }) } @@ -499,7 +499,7 @@ function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) { Write-Host "Downloading $packageName $packageVersion" $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit Retry({ - Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath + Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -UseBasicParsing -OutFile $packagePath }) if (!(Test-Path $packagePath)) { @@ -543,7 +543,7 @@ function LocateVisualStudio([object]$vsRequirements = $null){ Create-Directory $vsWhereDir Write-Host 'Downloading vswhere' Retry({ - Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe + Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -UseBasicParsing -OutFile $vswhereExe }) } diff --git a/eng/xcopy-msbuild/install-visualstudiobuildtools.ps1 b/eng/xcopy-msbuild/install-visualstudiobuildtools.ps1 index 91bc94cf866..766b683ed42 100644 --- a/eng/xcopy-msbuild/install-visualstudiobuildtools.ps1 +++ b/eng/xcopy-msbuild/install-visualstudiobuildtools.ps1 @@ -21,14 +21,14 @@ if(-Not (Test-Path $destinationDir)) New-Item -ItemType 'Directory' -Path "$destinationDir" -Force | Out-Null } # Query the page to get the download link -$response = Invoke-WebRequest $downloadUrl +$response = Invoke-WebRequest $downloadUrl -UseBasicParsing $regex = "downloadUrl: '(?[^']+)'" $response.Content -Match $regex | Out-Null $downloadLink = $Matches['downloadUrl'] Write-Host "download link: $downloadLink" -$response = Invoke-WebRequest $downloadLink -OutFile "$installerPath" +$response = Invoke-WebRequest $downloadLink -UseBasicParsing -OutFile "$installerPath" if(-Not (Test-Path $outputDirectory)) { diff --git a/scripts/add-build-variables.ps1 b/scripts/add-build-variables.ps1 index cb0137303b0..de1fcf2084a 100644 --- a/scripts/add-build-variables.ps1 +++ b/scripts/add-build-variables.ps1 @@ -47,7 +47,7 @@ param ( function UpdatePipeline($id, $authHeaders) { $pipelineUri = "https://dev.azure.com/$Org/$Project/_apis/build/definitions/$($id)?api-version=6.1-preview.7" - $existingPipeline = Invoke-WebRequest -Headers $authHeaders -Method Get -Uri $pipelineUri -ContentType 'application/json' | ConvertFrom-Json + $existingPipeline = Invoke-WebRequest -UseBasicParsing -Headers $authHeaders -Method Get -Uri $pipelineUri -ContentType 'application/json' | ConvertFrom-Json Write-Host "Updating pipeline $Org/$Project/$($existingPipeline.name) (pipeline id: $id)" # Update the variables with the new one if not already done. If variable value is null, remove @@ -72,7 +72,7 @@ function UpdatePipeline($id, $authHeaders) # Attempt the update $bodyJson = $existingPipeline | ConvertTo-Json -Depth 10 - $updatedPipelineJson = Invoke-WebRequest -Headers $azdoAuthHeader -Method Put $pipelineUri -Body $bodyJson -ContentType 'application/json' | ConvertFrom-Json + $updatedPipelineJson = Invoke-WebRequest -UseBasicParsing -Headers $azdoAuthHeader -Method Put $pipelineUri -Body $bodyJson -ContentType 'application/json' | ConvertFrom-Json } $base64authinfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$AzDoPAT")) @@ -81,7 +81,7 @@ $azdoAuthHeader = @{"Authorization"="Basic $base64authinfo"} if ($PipelineId) { UpdatePipeline $PipelineId $azdoAuthHeader } else { - $allPipelines = Invoke-WebRequest -ContentType 'application/json' -Method Get -Headers $azdoAuthHeader -Uri "https://dev.azure.com/$Org/$Project/_apis/build/definitions?api-version=6.1-preview.7" | ConvertFrom-Json + $allPipelines = Invoke-WebRequest -UseBasicParsing -ContentType 'application/json' -Method Get -Headers $azdoAuthHeader -Uri "https://dev.azure.com/$Org/$Project/_apis/build/definitions?api-version=6.1-preview.7" | ConvertFrom-Json Write-Host "Updating $($allPipelines.count) pipelines" foreach ($pipeline in $allPipelines.value) { UpdatePipeline $pipeline.Id $azdoAuthHeader diff --git a/scripts/cqb-utilities.ps1 b/scripts/cqb-utilities.ps1 index a792c7271bc..c3e4ad35b96 100644 --- a/scripts/cqb-utilities.ps1 +++ b/scripts/cqb-utilities.ps1 @@ -48,7 +48,7 @@ Function Gen-Internal-Merge-PR } try { - $resp = Invoke-WebRequest -Method Post -Body $($prBody | ConvertTo-Json) -Headers $header -Uri "https://dev.azure.com/$Org/$Project/_apis/git/repositories/$RepoName/pullrequests?api-version=7.0" -ContentType application/json + $resp = Invoke-WebRequest -UseBasicParsing -Method Post -Body $($prBody | ConvertTo-Json) -Headers $header -Uri "https://dev.azure.com/$Org/$Project/_apis/git/repositories/$RepoName/pullrequests?api-version=7.0" -ContentType application/json $result = $resp | ConvertFrom-Json Write-Host https://dev.azure.com/$Org/$Project/_git/$RepoName/pullrequest/$($result.pullRequestId) } catch { diff --git a/scripts/duplicate-feed.ps1 b/scripts/duplicate-feed.ps1 index 7a27caa6b7c..fa67529d6ec 100644 --- a/scripts/duplicate-feed.ps1 +++ b/scripts/duplicate-feed.ps1 @@ -48,11 +48,11 @@ function Get-Package-List($vstsAuthHeader, $account, $visibility, $feed) { try { $packageListUri = "https://feeds.dev.azure.com/$account/${visibility}_apis/packaging/Feeds/$feed/packages?api-version=5.1-preview.1" Write-Host "Looking up packages on feed at: $packageListUri" - $result = Invoke-WebRequest -Headers $vstsAuthHeader $packageListUri + $result = Invoke-WebRequest -UseBasicParsing -Headers $vstsAuthHeader $packageListUri $resultJson = $result | ConvertFrom-Json Write-Host "Feed $SourceFeedUri has $($resultJson.count) packages" foreach ($package in $resultJson.value) { - $versionsResult = Invoke-WebRequest -Headers $vstsAuthHeader $package._links.versions.href + $versionsResult = Invoke-WebRequest -UseBasicParsing -Headers $vstsAuthHeader $package._links.versions.href $versionsResultJson = $versionsResult | ConvertFrom-Json foreach ($version in $versionsResultJson.value) { if (-not $version.isDeleted) { @@ -118,7 +118,7 @@ foreach ($packageToCopy in $listOfSourcePackages) { $packageContentUrl = "https://pkgs.dev.azure.com/$($sourceFeedInfo.account)/$($sourceFeedInfo.visibility)_apis/packaging/feeds/$($sourceFeedInfo.feed)/nuget/packages/$($packageToCopy.name)/versions/$($packageToCopy.version)/content"; Write-Host "Downloading package $($packageToCopy.name) @ $($packageToCopy.version) from $packageContentUrl" $localPackagePath = Join-Path -Path $downloadRoot -ChildPath "$($packageToCopy.name).$($packageToCopy.version).nupkg" - Invoke-WebRequest -Headers $vstsAuthHeader $packageContentUrl -OutFile $localPackagePath + Invoke-WebRequest -UseBasicParsing -Headers $vstsAuthHeader $packageContentUrl -OutFile $localPackagePath & $NugetPath push -Source $TargetFeedUri -ApiKey AzureDevOps $localPackagePath -SkipDuplicate } catch { Write-Error $_ diff --git a/scripts/launch-mirrors.ps1 b/scripts/launch-mirrors.ps1 index 71c4ea59d8e..4bc09eb66fd 100644 --- a/scripts/launch-mirrors.ps1 +++ b/scripts/launch-mirrors.ps1 @@ -59,7 +59,7 @@ function LaunchMirrorBuild { $bodyStr = ConvertTo-Json $body $uri = "${AzDOInstance}/_apis/build/builds?api-version=5.1" Write-Host "Launching $mirrorType build for $repo @ $branch" - $queueResponse = Invoke-WebRequest -Method Post -ContentType "application/json" -Headers $AzDOAuthHeader -Uri "${AzDOInstance}/_apis/build/builds?api-version=5.1" -Body $bodyStr | ConvertFrom-Json + $queueResponse = Invoke-WebRequest -UseBasicParsing -Method Post -ContentType "application/json" -Headers $AzDOAuthHeader -Uri "${AzDOInstance}/_apis/build/builds?api-version=5.1" -Body $bodyStr | ConvertFrom-Json $buildId = $queueResponse.id Write-Host "Launched $AzDOInstance/_build/results?buildId=$buildId" } diff --git a/scripts/list-dotnet-install-versions.ps1 b/scripts/list-dotnet-install-versions.ps1 index b12ce62e100..ea15a791e92 100644 --- a/scripts/list-dotnet-install-versions.ps1 +++ b/scripts/list-dotnet-install-versions.ps1 @@ -62,7 +62,7 @@ $productVersions += $queries | ForEach-Object -Parallel { } try { - $response = Invoke-WebRequest $versionStringUrl + $response = Invoke-WebRequest $versionStringUrl -UseBasicParsing # It's difficult to tell whether the aka.ms link 404s or not, since it redirects in case of # a not found. diff --git a/scripts/pause-all-pipelines.ps1 b/scripts/pause-all-pipelines.ps1 index e109d06e079..47c0de52c6a 100644 --- a/scripts/pause-all-pipelines.ps1 +++ b/scripts/pause-all-pipelines.ps1 @@ -26,7 +26,7 @@ param ( $base64authinfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$AzDOPat")) $AzDOAuthHeader = @{"Authorization"="Basic $base64authinfo"} -$allPipelines = Invoke-WebRequest -Uri "https://dev.azure.com/$Organization/$Project/_apis/build/definitions?api-version=6.0" -Headers $AzDOAuthHeader | ConvertFrom-Json +$allPipelines = Invoke-WebRequest -UseBasicParsing -Uri "https://dev.azure.com/$Organization/$Project/_apis/build/definitions?api-version=6.0" -Headers $AzDOAuthHeader | ConvertFrom-Json $queueStatusString = $null $uxString = $null @@ -48,13 +48,13 @@ foreach ($pipeline in $allPipelines.value) { Write-Host -NoNewLine " $uxString '$($pipeline.name)' (id: $pipelineId)..." $pipelineUri = "https://dev.azure.com/$Organization/$Project/_apis/build/definitions/$($pipelineId)?api-version=6.0" - $pipelineInfo = Invoke-WebRequest -Uri $pipelineUri -Headers $AzDOAuthHeader | ConvertFrom-Json + $pipelineInfo = Invoke-WebRequest -UseBasicParsing -Uri $pipelineUri -Headers $AzDOAuthHeader | ConvertFrom-Json # Update the pipeline $pipelineInfo.queueStatus = $queueStatusString #update the definition - $result = Invoke-WebRequest -Uri $pipelineUri -Headers $AzDOAuthHeader -Method Put -Body (ConvertTo-Json $pipelineInfo -Depth 100) -ContentType "application/json" + $result = Invoke-WebRequest -UseBasicParsing -Uri $pipelineUri -Headers $AzDOAuthHeader -Method Put -Body (ConvertTo-Json $pipelineInfo -Depth 100) -ContentType "application/json" if ($result.StatusCode -eq 200) { Write-Host "done"