From 4c935c7bca384bf4834a37e9cb16c41be89e54a2 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 6 Oct 2025 17:08:06 -0700 Subject: [PATCH 01/40] Fix CodeQL configuration (#1886) --- .config/tsaoptions.json | 2 +- .pipelines/PSResourceGet-Official.yml | 29 +++++++++------------------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json index 692eaec1f..f1c0afb59 100644 --- a/.config/tsaoptions.json +++ b/.config/tsaoptions.json @@ -1,7 +1,7 @@ { "instanceUrl": "https://msazure.visualstudio.com", "projectName": "One", - "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell\\PowerShell Core", + "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell\\PowerShell Core\\PSResourceGet", "notificationAliases": [ "adityap@microsoft.com", "americks@microsoft.com", diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index cc51e2e78..9dacd1a5e 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -1,14 +1,5 @@ -################################################################################# -# OneBranch Pipelines # -# This pipeline was created by EasyStart from a sample located at: # -# https://aka.ms/obpipelines/easystart/samples # -# Documentation: https://aka.ms/obpipelines # -# Yaml Schema: https://aka.ms/obpipelines/yaml/schema # -# Retail Tasks: https://aka.ms/obpipelines/tasks # -# Support: https://aka.ms/onebranchsup # -################################################################################# name: PSResourceGet-Release-$(Build.BuildId) -trigger: none # https://aka.ms/obpipelines/triggers +trigger: none pr: branches: include: @@ -36,7 +27,7 @@ resources: ref: refs/heads/main extends: - template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates # https://aka.ms/obpipelines/templates + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: featureFlags: WindowsHostVersion: '1ESWindows2022' @@ -49,18 +40,16 @@ extends: enabled: true packageName: Microsoft.PowerShell.PSResourceGet codeql: + tsaEnabled: true compiled: enabled: true - asyncSdl: # https://aka.ms/obpipelines/asyncsdl + credscan: enabled: true - forStages: [stagebuild] - credscan: - enabled: true - scanFolder: $(Build.SourcesDirectory)\PSResourceGet - binskim: - enabled: true - apiscan: - enabled: false + scanFolder: $(Build.SourcesDirectory)\PSResourceGet + binskim: + enabled: true + apiscan: + enabled: false stages: - stage: stagebuild From 71b35b088016cede5af84e3e81c12ff3b06680ea Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:04:25 -0700 Subject: [PATCH 02/40] Add cmdlet aliases: gres, usres, and svres (#1888) --- src/Microsoft.PowerShell.PSResourceGet.psd1 | 5 ++++- src/code/GetInstalledPSResource.cs | 2 +- src/code/SavePSResource.cs | 1 + src/code/UninstallPSResource.cs | 1 + test/GetInstalledPSResource/GetInstalledPSResource.Tests.ps1 | 4 ++++ test/SavePSResourceTests/SavePSResourceLocal.Tests.ps1 | 4 ++++ test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 | 4 ++++ 7 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index fad665d1c..023b0dcc8 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -41,9 +41,12 @@ AliasesToExport = @( 'Get-PSResource', 'fdres', + 'gres', 'isres', 'pbres', - 'udres') + 'svres', + 'udres', + 'usres') PrivateData = @{ PSData = @{ Prerelease = 'preview3' diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index 90cc9f20d..9dfe1a670 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -15,7 +15,7 @@ namespace Microsoft.PowerShell.PSResourceGet.Cmdlets /// Returns a single resource or multiple resource. /// [Cmdlet(VerbsCommon.Get, "InstalledPSResource")] - [Alias("Get-PSResource")] + [Alias("Get-PSResource", "gres")] [OutputType(typeof(PSResourceInfo))] public sealed class GetInstalledPSResourceCommand : PSCmdlet { diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 26d481fce..de5a70808 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -17,6 +17,7 @@ namespace Microsoft.PowerShell.PSResourceGet.Cmdlets /// It returns nothing. /// [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "IncludeXmlParameterSet", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low)] + [Alias("svres")] public sealed class SavePSResource : PSCmdlet { #region Members diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 4cd0a4d19..c9a63adfd 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -17,6 +17,7 @@ namespace Microsoft.PowerShell.PSResourceGet.Cmdlets /// Uninstall-PSResource uninstalls a package found in a module or script installation path. /// [Cmdlet(VerbsLifecycle.Uninstall, "PSResource", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true)] + [Alias("usres")] public sealed class UninstallPSResource : PSCmdlet { #region Parameters diff --git a/test/GetInstalledPSResource/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource/GetInstalledPSResource.Tests.ps1 index 5ddbf816a..21887bea3 100644 --- a/test/GetInstalledPSResource/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource/GetInstalledPSResource.Tests.ps1 @@ -153,6 +153,10 @@ Describe 'Test Get-InstalledPSResource for Module' -tags 'CI' { (Get-Alias Get-PSResource).Definition | Should -BeExactly 'Get-InstalledPSResource' } + It "Get definition for alias 'gres'" { + (Get-Alias gres).Definition | Should -BeExactly 'Get-InstalledPSResource' + } + It "Should not throw on ErrorAction ignore when no subdirectories are found" { { Get-InstalledPSResource -Path $TestEmptyDirectoryPath -ErrorAction 'Ignore' } | Should -Not -Throw } diff --git a/test/SavePSResourceTests/SavePSResourceLocal.Tests.ps1 b/test/SavePSResourceTests/SavePSResourceLocal.Tests.ps1 index 5b090e739..b25a6c53b 100644 --- a/test/SavePSResourceTests/SavePSResourceLocal.Tests.ps1 +++ b/test/SavePSResourceTests/SavePSResourceLocal.Tests.ps1 @@ -205,4 +205,8 @@ Describe 'Test Save-PSResource for local repositories' -tags 'CI' { $res.Name | Should -Be $moduleName $res.Version | Should -Be "1.0.0" } + + It "Get definition for alias 'svres'" { + (Get-Alias svres).Definition | Should -BeExactly 'Save-PSResource' + } } diff --git a/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 b/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 index 0a1fa10fc..f4723f612 100644 --- a/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 @@ -340,4 +340,8 @@ Describe 'Test Uninstall-PSResource for Modules' -tags 'CI' { $pkg.Name | Should -Be $testModuleName $pkg.Path.ToString().Contains("Documents") | Should -Be $true } + + It "Get definition for alias 'usres'" { + (Get-Alias usres).Definition | Should -BeExactly 'Uninstall-PSResource' + } } From 5b12325588d1f3956fd8dc6eabee00b1e14b2c5b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:15:48 -0700 Subject: [PATCH 03/40] Add warning when AuthenticodeCheck is used on non-Windows platforms (#1891) --- src/code/Utils.cs | 1 + .../InstallPSResourceV2Server.Tests.ps1 | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 61b9e6b04..ae540f9e4 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -2160,6 +2160,7 @@ internal static bool CheckAuthenticodeSignature( // Because authenticode and catalog verifications are only applicable on Windows, we allow all packages by default to be installed on unix systems. if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + cmdletPassedIn.WriteWarning("Authenticode check cannot be performed on Linux or MacOS."); return true; } diff --git a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 index 6023355b7..eea47eb71 100644 --- a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 @@ -554,6 +554,14 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { $err[0].FullyQualifiedErrorId | Should -BeExactly "GetAuthenticodeSignatureError,Microsoft.PowerShell.PSResourceGet.Cmdlets.InstallPSResource" } + # Test that AuthenticodeCheck parameter displays warning on non-Windows + It "Install with AuthenticodeCheck on non-Windows should display warning" -Skip:(Get-IsWindows) { + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -AuthenticodeCheck -WarningVariable warn -WarningAction SilentlyContinue + $warn[0] | Should -Contain "Authenticode check cannot be performed on Linux or MacOS" + $res = Get-InstalledPSResource $testModuleName + $res.Name | Should -Be $testModuleName + } + # Unix test for installing scripts It "Install script resource - Unix only" -Skip:(Get-IsWindows) { # previously installing pester on Unix was throwing an error due to how the environment PATH variable was being gotten. From fd1fe394568cba493fb13eb78e72da716ab350ce Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Oct 2025 14:58:35 -0700 Subject: [PATCH 04/40] Fix Compress-PSResource ignoring .gitkeep and other dotfiles (#1889) --- src/code/PublishHelper.cs | 3 +- .../CompressPSResource.Tests.ps1 | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/code/PublishHelper.cs b/src/code/PublishHelper.cs index 619c1da56..4b813362f 100644 --- a/src/code/PublishHelper.cs +++ b/src/code/PublishHelper.cs @@ -605,7 +605,8 @@ private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFil Path = nuspecFile, Exclude = System.Array.Empty(), Symbols = false, - Logger = NullLogger.Instance + Logger = NullLogger.Instance, + NoDefaultExcludes = true }, MSBuildProjectFactory.ProjectCreator, builder); diff --git a/test/PublishPSResourceTests/CompressPSResource.Tests.ps1 b/test/PublishPSResourceTests/CompressPSResource.Tests.ps1 index 75205069e..5dfb6e3d9 100644 --- a/test/PublishPSResourceTests/CompressPSResource.Tests.ps1 +++ b/test/PublishPSResourceTests/CompressPSResource.Tests.ps1 @@ -396,6 +396,36 @@ Describe "Test Compress-PSResource" -tags 'CI' { } } + It "Compress-PSResource includes .gitkeep files (empty and non-empty)" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + # Create 'hidden' directory with .gitkeep files + $hiddenDir = Join-Path -Path $script:PublishModuleBase -ChildPath "hidden" + New-Item -Path $hiddenDir -ItemType Directory -Force + + # Create empty .gitkeep file in 'hidden' directory + $hiddenGitkeep = Join-Path -Path $hiddenDir -ChildPath ".gitkeep" + New-Item -Path $hiddenGitkeep -ItemType File -Force + + Compress-PSResource -Path $script:PublishModuleBase -DestinationPath $script:repositoryPath + + # Extract and verify files are included + $nupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + $zipPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.zip" + Rename-Item -Path $nupkgPath -NewName $zipPath + $unzippedPath = Join-Path -Path $TestDrive -ChildPath "$script:PublishModuleName-gitkeep-test" + New-Item $unzippedPath -ItemType directory -Force + Expand-Archive -Path $zipPath -DestinationPath $unzippedPath + + # Verify both .gitkeep files exist + $extractedHiddenkeep = Join-Path -Path $unzippedPath -ChildPath "hidden" | Join-Path -ChildPath ".gitkeep" + + Test-Path -Path $extractedHiddenkeep | Should -Be $True + + $null = Remove-Item $unzippedPath -Force -Recurse + } + <# Test for Signing the nupkg. Signing doesn't work It "Compressed Module is able to be signed with a certificate" { $version = "1.0.0" From b85a9a891971d099497584f2274383f93879e92a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 16 Oct 2025 13:06:34 -0400 Subject: [PATCH 05/40] Add CodeQL suppression for ContainerRegistryServerAPICalls (#1897) --- src/code/ContainerRegistryServerAPICalls.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index 2c39f536d..d828c543d 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -1014,6 +1014,7 @@ internal JObject GetHttpResponseJObjectUsingContentHeaders(string url, HttpMetho return null; } + // codeql[cs/sensitive-data-transmission] This is expected PSResourceGet behavior to create the content of the request which is only transmitted to the server, not the user. This information is also not exposed back to the user via error or verbose messaging. request.Content = new StringContent(content); request.Content.Headers.Clear(); if (contentHeaders != null) From daeeb70fc8f8a49112f11a32c5560427913a521e Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 24 Oct 2025 14:48:06 -0400 Subject: [PATCH 06/40] Fix broken Install-PSResource test with warning condition incorrect (#1899) Co-authored-by: anamnavi --- test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 index eea47eb71..4285e0479 100644 --- a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 @@ -557,7 +557,7 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { # Test that AuthenticodeCheck parameter displays warning on non-Windows It "Install with AuthenticodeCheck on non-Windows should display warning" -Skip:(Get-IsWindows) { Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -AuthenticodeCheck -WarningVariable warn -WarningAction SilentlyContinue - $warn[0] | Should -Contain "Authenticode check cannot be performed on Linux or MacOS" + $warn[0] | Should -Match "Authenticode check cannot be performed on Linux or MacOS" $res = Get-InstalledPSResource $testModuleName $res.Name | Should -Be $testModuleName } From eb00082bbc4c7323af2696da3d6a698fa531c422 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 4 Nov 2025 14:44:51 -0500 Subject: [PATCH 07/40] Uninstall-PSResource should not fail silently when resource was not found or prerelease criteria not met (#1898) * initial error message * add warnings * add tests * clean up comment --------- Co-authored-by: Anam Navied --- src/code/UninstallPSResource.cs | 16 ++++++ .../UninstallPSResource.Tests.ps1 | 55 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index c9a63adfd..3183900fd 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -182,6 +182,8 @@ private bool UninstallPkgHelper(out List errRecords) WriteDebug("In UninstallPSResource::UninstallPkgHelper"); var successfullyUninstalled = false; GetHelper getHelper = new GetHelper(this); + + HashSet requestedPackageNames = new HashSet(Name, StringComparer.InvariantCultureIgnoreCase); List dirsToDelete = getHelper.FilterPkgPathsByName(Name, _pathsToSearch); int totalDirs = dirsToDelete.Count; errRecords = new List(); @@ -257,6 +259,20 @@ private bool UninstallPkgHelper(out List errRecords) return successfullyUninstalled; } + + requestedPackageNames.Remove(pkgName); + } + + // the package requested for uninstallation was found by name, but not satisfied by version criteria (i.e version didn't exist or match prerelease criteria) so write error + if (requestedPackageNames.Count > 0) + { + string[] pkgsFailedToUninstall = requestedPackageNames.ToArray(); + string prereleaseMessage = Prerelease ? "prerelease " : String.Empty; + string versionMessage = Version != null ? $"matching '{Version} '" : String.Empty; + + string warningMessage = $"Cannot uninstall {prereleaseMessage}version(s) {versionMessage}of resource '{String.Join(", ", pkgsFailedToUninstall)}' because it does not exist."; + + WriteWarning(warningMessage); } return successfullyUninstalled; diff --git a/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 b/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 index f4723f612..45b9310a1 100644 --- a/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResourceTests/UninstallPSResource.Tests.ps1 @@ -110,6 +110,32 @@ Describe 'Test Uninstall-PSResource for Modules' -tags 'CI' { $pkgs.Version | Should -Not -Contain "1.0.0" } + It "Do not uninstall existing module when requested version does not exist and write warning instead" { + Uninstall-PSResource -Name $testModuleName -Version "9.9.9" -SkipDependencyCheck -WarningVariable warn -WarningAction SilentlyContinue + + # Module should still be present since no prerelease versions were found + $res = Get-InstalledPSResource -Name $testModuleName + $res | Should -Not -BeNullOrEmpty + $res.Name | Should -Be $testModuleName + + # Warning should have been written + $warn.Count | Should -Be 1 + $warn[0] | Should -Match "Cannot uninstall version" + } + + It "Do not uninstall existing module when requested version range does not exist and write warning instead" { + Uninstall-PSResource -Name $testModuleName -Version "[9.9.9, 10.0.0]" -SkipDependencyCheck -WarningVariable warn -WarningAction SilentlyContinue + + # Module should still be present since no prerelease versions were found + $res = Get-InstalledPSResource -Name $testModuleName + $res | Should -Not -BeNullOrEmpty + $res.Name | Should -Be $testModuleName + + # Warning should have been written + $warn.Count | Should -Be 1 + $warn[0] | Should -Match "Cannot uninstall version" + } + $testCases = @{Version="[1.0.0.0]"; ExpectedVersion="1.0.0.0"; Reason="validate version, exact match"}, @{Version="1.0.0.0"; ExpectedVersion="1.0.0.0"; Reason="validate version, exact match without bracket syntax"}, @{Version="[1.0.0.0, 5.0.0.0]"; ExpectedVersion="5.0.0.0"; Reason="validate version, exact range inclusive"}, @@ -235,6 +261,35 @@ Describe 'Test Uninstall-PSResource for Modules' -tags 'CI' { $stableVersionPkgs.Count | Should -Be 2 } + It "Write warning when using -Prerelease flag with only stable versions installed" { + # $testModuleName (test_module2) only has stable versions installed + $pkg = Get-InstalledPSResource $testModuleName + $pkg | Should -Not -BeNullOrEmpty + + # Try to uninstall with -Prerelease flag, should show warning + Uninstall-PSResource -Name $testModuleName -Prerelease -SkipDependencyCheck -WarningVariable warn -WarningAction SilentlyContinue + + # Module should still be present since no prerelease versions were found + $res = Get-InstalledPSResource -Name $testModuleName + $res | Should -Not -BeNullOrEmpty + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be $pkg.Version + + # Warning should have been written + $warn.Count | Should -Be 1 + $warn[0] | Should -Match "Cannot uninstall prerelease version" + } + + It "Write warning when multiple modules are requested to be uninstalled but one does not exist" { + Uninstall-PSResource $testModuleName, "nonExistantModule" -SkipDependencyCheck -WarningVariable warn -WarningAction SilentlyContinue + $res = Get-InstalledPSResource -Name $testModuleName + $res | Should -BeNullOrEmpty + + # Warning should have been written + $warn.Count | Should -Be 1 + $warn[0] | Should -Match "Cannot uninstall version" + } + It "Uninstall module using -WhatIf, should not uninstall the module" { Start-Transcript .\testUninstallWhatIf.txt Uninstall-PSResource -Name $testModuleName -WhatIf -SkipDependencyCheck From d616e44555229d1c8530ae03cec1459cc28a2e64 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 4 Nov 2025 15:01:24 -0500 Subject: [PATCH 08/40] Bugfix: Uninstall-PSResource should delete subdirectories without Access Denied error on OneDrive (#1860) --- src/code/Utils.cs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ae540f9e4..c9c970506 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1658,6 +1658,16 @@ public static void DeleteDirectoryWithRestore(string dirPath) } } + private static void SetAttributesHelper(DirectoryInfo directory) + { + foreach (var subDirectory in directory.GetDirectories()) + { + subDirectory.Attributes = FileAttributes.Normal; + SetAttributesHelper(subDirectory); + } + + directory.Attributes = FileAttributes.Normal; + } /// /// Deletes a directory and its contents /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell @@ -1672,13 +1682,17 @@ public static void DeleteDirectory(string dirPath) } // Remove read only file attributes first - foreach (var dirFilePath in Directory.GetFiles(dirPath,"*",SearchOption.AllDirectories)) + foreach (var dirFilePath in Directory.GetFiles(dirPath, "*", SearchOption.AllDirectories)) { if (File.GetAttributes(dirFilePath).HasFlag(FileAttributes.ReadOnly)) { File.SetAttributes(dirFilePath, File.GetAttributes(dirFilePath) & ~FileAttributes.ReadOnly); } } + + DirectoryInfo rootDir = new DirectoryInfo(dirPath); + SetAttributesHelper(rootDir); + // Delete directory recursive, try multiple times before throwing ( #1662 ) int maxAttempts = 5; int msDelay = 5; @@ -1686,7 +1700,7 @@ public static void DeleteDirectory(string dirPath) { try { - Directory.Delete(dirPath,true); + Directory.Delete(dirPath, true); return; } catch (Exception ex) @@ -1695,6 +1709,17 @@ public static void DeleteDirectory(string dirPath) { Thread.Sleep(msDelay); } + else if (ex is System.IO.IOException) + { + string psVersion = System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Version.ToString(); + if (ex.Message.Contains("The directory is not empty") && psVersion.StartsWith("5")) + { + // there is a known bug with WindowsPowerShell and OneDrive based module paths, where .NET Directory.Delete() will throw a 'The directory is not empty.' error. + throw new Exception(string.Format("Cannot uninstall module with OneDrive based path on Windows PowerShell due to .NET issue. Try installing and uninstalling using PowerShell 7+ if using OneDrive."), ex); + } + + throw new Exception(string.Format("Access denied to path while deleting path {0}", dirPath), ex); + } else { throw; From 05f79284eb9c0097882dd9a480e6f0f5171ef071 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 6 Nov 2025 16:16:55 -0800 Subject: [PATCH 09/40] Add @shammu1 as a CODEOWNER (#1904) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1b53fe53a..ff70521d0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,4 @@ # the repo. Unless a later match takes precedence, # the following owners will be requested for # review when someone opens a pull request. -* @anamnavi @alerickson @adityapatwardhan @SydneyhSmith +* @anamnavi @alerickson @adityapatwardhan @SydneyhSmith @shammu1 From 6c2076ca06d742033eaf426c46557c7fa519b9ed Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 6 Nov 2025 16:18:07 -0800 Subject: [PATCH 10/40] Update change for release v1.2.0-preview4 (#1903) --- CHANGELOG/preview.md | 17 +++++++++++++++++ global.json | 2 +- src/Microsoft.PowerShell.PSResourceGet.psd1 | 19 ++++++++++++++++++- .../Microsoft.PowerShell.PSResourceGet.csproj | 4 ++-- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index a436c10bb..3ba5f8ee8 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,22 @@ # Preview Changelog +## [1.2.0-preview4](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview3..v1.2.0-preview4) - 2025-11-04 + +## Bug fix + +- Fix typos in numerous files (#1875 Thanks @SamErde!) +- MAR fails to parse RequiredVersion for dependencies (#1876 Thanks @o-l-a-v!) +- Get-InstalledPSResource -Path don't throw if no subdirectories were found (#1877 Thanks @o-l-a-v!) +- Handle boolean correctly in RequiredResourceFile for prerelease key (#1843 Thanks @o-l-a-v!) +- Fix CodeQL configuration (#1886) +- Add cmdlet aliases: gres, usres, and svres (#1888) +- Add warning when AuthenticodeCheck is used on non-Windows platforms (#1891) +- Fix Compress-PSResource ignoring .gitkeep and other dotfiles (#1889) +- Add CodeQL suppression for ContainerRegistryServerAPICalls (#1897) +- Fix broken Install-PSResource test with warning condition incorrect (#1899) +- Uninstall-PSResource should not fail silently when resource was not found or prerelease criteria not met (#1898) +- Uninstall-PSResource should delete subdirectories without Access Denied error on OneDrive (#1860) + ## [1.2.0-preview3](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview2..v1.2.0-preview3) - 2025-09-12 ### New Features diff --git a/global.json b/global.json index 100631a86..bb0a2659e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.414" + "version": "8.0.415" } } diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 023b0dcc8..617f0cb33 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -49,7 +49,7 @@ 'usres') PrivateData = @{ PSData = @{ - Prerelease = 'preview3' + Prerelease = 'preview4' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -59,6 +59,23 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 1.2.0-preview4 + +## Bug fix + +- Fix typos in numerous files (#1875 Thanks @SamErde!) +- MAR fails to parse RequiredVersion for dependencies (#1876 Thanks @o-l-a-v!) +- Get-InstalledPSResource -Path don't throw if no subdirectories were found (#1877 Thanks @o-l-a-v!) +- Handle boolean correctly in RequiredResourceFile for prerelease key (#1843 Thanks @o-l-a-v!) +- Fix CodeQL configuration (#1886) +- Add cmdlet aliases: gres, usres, and svres (#1888) +- Add warning when AuthenticodeCheck is used on non-Windows platforms (#1891) +- Fix Compress-PSResource ignoring .gitkeep and other dotfiles (#1889) +- Add CodeQL suppression for ContainerRegistryServerAPICalls (#1897) +- Fix broken Install-PSResource test with warning condition incorrect (#1899) +- Uninstall-PSResource should not fail silently when resource was not found or prerelease criteria not met (#1898) +- Uninstall-PSResource should delete subdirectories without Access Denied error on OneDrive (#1860) + ## 1.2.0-preview3 ### New Features diff --git a/src/code/Microsoft.PowerShell.PSResourceGet.csproj b/src/code/Microsoft.PowerShell.PSResourceGet.csproj index 715e420d4..daeaff8e1 100644 --- a/src/code/Microsoft.PowerShell.PSResourceGet.csproj +++ b/src/code/Microsoft.PowerShell.PSResourceGet.csproj @@ -22,9 +22,9 @@ - + - + From 60b96d97a0c79099e6752bafea81b1bf3f26bcd2 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 12:55:07 -0800 Subject: [PATCH 11/40] Fix PSModuleInfo property deserialization in ValidateModuleManifest (#1909) --- src/code/Utils.cs | 44 +++++++++---------- .../PublishPSResource.Tests.ps1 | 15 +++++++ 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index c9c970506..cc6f0fa14 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1375,7 +1375,7 @@ private static bool TryReadPSDataFile( public static bool ValidateModuleManifest(string moduleManifestPath, out string errorMsg) { errorMsg = string.Empty; - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) + using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)) { // use PowerShell cmdlet Test-ModuleManifest // TODO: Test-ModuleManifest will throw an error if RequiredModules specifies a module that does not exist @@ -1400,32 +1400,32 @@ public static bool ValidateModuleManifest(string moduleManifestPath, out string } } - if (pwsh.HadErrors) + // Validate the result object directly + if (results.Any()) { - if (results.Any()) + PSModuleInfo psModuleInfoObj = results[0].BaseObject as PSModuleInfo; + if (string.IsNullOrWhiteSpace(psModuleInfoObj.Author)) { - PSModuleInfo psModuleInfoObj = results[0].BaseObject as PSModuleInfo; - if (string.IsNullOrWhiteSpace(psModuleInfoObj.Author)) - { - errorMsg = "No author was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; - } - else if (string.IsNullOrWhiteSpace(psModuleInfoObj.Description)) - { - errorMsg = "No description was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; - } - else if (psModuleInfoObj.Version == null) - { - errorMsg = "No version or an incorrectly formatted version was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; - } + errorMsg = "No author was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + return false; } - - if (string.IsNullOrEmpty(errorMsg)) + else if (string.IsNullOrWhiteSpace(psModuleInfoObj.Description)) { - // Surface any inner error messages - var innerErrorMsg = (pwsh.Streams.Error.Count > 0) ? pwsh.Streams.Error[0].ToString() : string.Empty; - errorMsg = $"Module manifest file validation failed with error: {innerErrorMsg}. Run 'Test-ModuleManifest' to validate the module manifest."; + errorMsg = "No description was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + return false; } - + else if (psModuleInfoObj.Version == null) + { + errorMsg = "No version or an incorrectly formatted version was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + return false; + } + } + + // Check for any errors from Test-ModuleManifest + if (pwsh.HadErrors) + { + var innerErrorMsg = (pwsh.Streams.Error.Count > 0) ? pwsh.Streams.Error[0].ToString() : string.Empty; + errorMsg = $"Module manifest file validation failed with error: {innerErrorMsg}. Run 'Test-ModuleManifest' to validate the module manifest."; return false; } } diff --git a/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 b/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 index e97f64407..ed0adf1b8 100644 --- a/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 @@ -131,6 +131,21 @@ Describe "Test Publish-PSResource" -tags 'CI' { } } + It "Publish a module with valid Author field without -SkipModuleManifestValidate" { + # This test verifies that the fix for runspace deserialization issue works correctly. + # Previously, PSModuleInfo.Author would return empty string when called via PowerShell.Create(), + # causing false positive "No author was provided" errors. + $version = "1.0.0" + $author = "TestAuthor" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -Author $author + + # This should succeed without needing -SkipModuleManifestValidate + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } + It "Publish a module with -Path to the highest priority repo" { $version = "1.0.0" New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" From 895cc6f4cca399e0bbb728c6789d4aea500e0db9 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Nov 2025 10:31:10 -0800 Subject: [PATCH 12/40] Respect TrustRepository parameter in RequiredResource hashtable (#1910) --- src/code/InstallPSResource.cs | 28 +++++++---- src/code/InstallPkgParams.cs | 50 ++++++++++++------- .../InstallPSResourceV2Server.Tests.ps1 | 13 +++++ .../InstallPSResourceV3Server.Tests.ps1 | 13 +++++ 4 files changed, 76 insertions(+), 28 deletions(-) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 83943eef9..feca62d50 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -487,9 +487,9 @@ private void RequiredResourceHelper(Hashtable reqResourceHash) } } - if (pkgParams.Scope == ScopeType.AllUsers) + if (pkgParams.Scope.HasValue && pkgParams.Scope.Value == ScopeType.AllUsers) { - _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, pkgParams.Scope); + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, pkgParams.Scope.Value); } pkgVersion = pkgInstallInfo["version"] == null ? String.Empty : pkgInstallInfo["version"].ToString(); @@ -565,6 +565,16 @@ private void ProcessInstallHelper(string[] pkgNames, string pkgVersion, bool pkg this)); } + // When reqResourceParams is provided (via -RequiredResource), use its properties + // instead of the cmdlet-level parameters. Only use the property if it was explicitly set (not null). + bool acceptLicense = reqResourceParams?.AcceptLicense ?? AcceptLicense; + bool quiet = reqResourceParams?.Quiet ?? Quiet; + bool reinstall = reqResourceParams?.Reinstall ?? Reinstall; + bool trustRepository = reqResourceParams?.TrustRepository ?? TrustRepository; + bool noClobber = reqResourceParams?.NoClobber ?? NoClobber; + bool skipDependencyCheck = reqResourceParams?.SkipDependencyCheck ?? SkipDependencyCheck; + ScopeType scope = reqResourceParams?.Scope ?? Scope; + IEnumerable installedPkgs = _installHelper.BeginInstallPackages( names: pkgNames, versionRange: versionRange, @@ -573,19 +583,19 @@ private void ProcessInstallHelper(string[] pkgNames, string pkgVersion, bool pkg versionString: Version, prerelease: pkgPrerelease, repository: pkgRepository, - acceptLicense: AcceptLicense, - quiet: Quiet, - reinstall: Reinstall, + acceptLicense: acceptLicense, + quiet: quiet, + reinstall: reinstall, force: false, - trustRepository: TrustRepository, - noClobber: NoClobber, + trustRepository: trustRepository, + noClobber: noClobber, asNupkg: false, includeXml: true, - skipDependencyCheck: SkipDependencyCheck, + skipDependencyCheck: skipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: false, pathsToInstallPkg: _pathsToInstallPkg, - scope: Scope, + scope: scope, tmpPath: _tmpPath, pkgsInstalled: _packagesOnMachine); diff --git a/src/code/InstallPkgParams.cs b/src/code/InstallPkgParams.cs index 7a1b8e986..19cdd076b 100644 --- a/src/code/InstallPkgParams.cs +++ b/src/code/InstallPkgParams.cs @@ -11,15 +11,15 @@ public class InstallPkgParams public string Name { get; set; } public VersionRange Version { get; set; } public string Repository { get; set; } - public bool AcceptLicense { get; set; } + public bool? AcceptLicense { get; set; } public bool Prerelease { get; set; } - public ScopeType Scope { get; set; } - public bool Quiet { get; set; } - public bool Reinstall { get; set; } + public ScopeType? Scope { get; set; } + public bool? Quiet { get; set; } + public bool? Reinstall { get; set; } public bool Force { get; set; } - public bool TrustRepository { get; set; } - public bool NoClobber { get; set; } - public bool SkipDependencyCheck { get; set; } + public bool? TrustRepository { get; set; } + public bool? NoClobber { get; set; } + public bool? SkipDependencyCheck { get; set; } @@ -67,8 +67,10 @@ public void SetProperty(string propertyName, string propertyValue, out ErrorReco break; case "acceptlicense": - bool.TryParse(propertyValue, out bool acceptLicenseTmp); - AcceptLicense = acceptLicenseTmp; + if (!string.IsNullOrWhiteSpace(propertyValue) && bool.TryParse(propertyValue, out bool acceptLicenseTmp)) + { + AcceptLicense = acceptLicenseTmp; + } break; case "prerelease": @@ -82,28 +84,38 @@ public void SetProperty(string propertyName, string propertyValue, out ErrorReco break; case "quiet": - bool.TryParse(propertyValue, out bool quietTmp); - Quiet = quietTmp; + if (!string.IsNullOrWhiteSpace(propertyValue) && bool.TryParse(propertyValue, out bool quietTmp)) + { + Quiet = quietTmp; + } break; case "reinstall": - bool.TryParse(propertyValue, out bool reinstallTmp); - Reinstall = reinstallTmp; + if (!string.IsNullOrWhiteSpace(propertyValue) && bool.TryParse(propertyValue, out bool reinstallTmp)) + { + Reinstall = reinstallTmp; + } break; case "trustrepository": - bool.TryParse(propertyValue, out bool trustRepositoryTmp); - TrustRepository = trustRepositoryTmp; + if (!string.IsNullOrWhiteSpace(propertyValue) && bool.TryParse(propertyValue, out bool trustRepositoryTmp)) + { + TrustRepository = trustRepositoryTmp; + } break; case "noclobber": - bool.TryParse(propertyValue, out bool noClobberTmp); - NoClobber = noClobberTmp; + if (!string.IsNullOrWhiteSpace(propertyValue) && bool.TryParse(propertyValue, out bool noClobberTmp)) + { + NoClobber = noClobberTmp; + } break; case "skipdependencycheck": - bool.TryParse(propertyValue, out bool skipDependencyCheckTmp); - SkipDependencyCheck = skipDependencyCheckTmp; + if (!string.IsNullOrWhiteSpace(propertyValue) && bool.TryParse(propertyValue, out bool skipDependencyCheckTmp)) + { + SkipDependencyCheck = skipDependencyCheckTmp; + } break; default: diff --git a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 index 4285e0479..e269b2628 100644 --- a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 @@ -429,6 +429,19 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { (Get-InstalledPSResource -Name 'TestModule99').'Prerelease' | Should -Be 'beta2' } + It "Install module using -RequiredResource with TrustRepository in hashtable" { + # This test verifies that TrustRepository specified in -RequiredResource hashtable is respected + Install-PSResource -RequiredResource @{ + 'TestModule99' = @{ + 'repository' = 'PSGallery' + 'trustrepository' = 'true' + } + } + $res = Get-InstalledPSResource -Name 'TestModule99' + $res.Name | Should -Be 'TestModule99' + $res.Version | Should -Be '0.0.93' + } + It "Install modules using -RequiredResource with JSON string" { $rrJSON = "{ 'test_module': { diff --git a/test/InstallPSResourceTests/InstallPSResourceV3Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceV3Server.Tests.ps1 index e18b9272d..835e0c0c6 100644 --- a/test/InstallPSResourceTests/InstallPSResourceV3Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceV3Server.Tests.ps1 @@ -310,6 +310,19 @@ Describe 'Test Install-PSResource for V3Server scenarios' -tags 'CI' { $res3.Version | Should -Be '0.0.93' } + It 'Install module using -RequiredResource with TrustRepository in hashtable' { + # This test verifies that TrustRepository specified in -RequiredResource hashtable is respected + Install-PSResource -RequiredResource @{ + 'TestModule99' = @{ + 'repository' = $NuGetGalleryName + 'trustrepository' = 'true' + } + } + $res = Get-InstalledPSResource -Name 'TestModule99' + $res.Name | Should -Be 'TestModule99' + $res.Version | Should -Be '0.0.93' + } + It 'Install modules using -RequiredResource with JSON string' { $rrJSON = "{ 'test_module': { From 6b9ddf4e4f3afd066b3e0fb6894cde1c6f4ceb7e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:11:37 -0800 Subject: [PATCH 13/40] Prevent users from setting ApiVersion to 'Unknown' in Set-PSResourceRepository and Register-PSResourceRepository (#1892) --- src/code/RegisterPSResourceRepository.cs | 1 + src/code/SetPSResourceRepository.cs | 1 + .../RegisterPSResourceRepository.Tests.ps1 | 8 ++++++++ .../SetPSResourceRepository.Tests.ps1 | 9 +++++---- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 8d86face3..ddf5cad24 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -91,6 +91,7 @@ class RegisterPSResourceRepository : PSCmdlet, IDynamicParameters /// Specifies the Api version of the repository to be set. /// [Parameter(ParameterSetName = NameParameterSet)] + [ValidateSet("V2", "V3", "Local", "NugetServer", "ContainerRegistry")] public PSRepositoryInfo.APIVersion ApiVersion { get; set; } /// diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index d46c5ba48..8dc17fe21 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -88,6 +88,7 @@ public SwitchParameter Trusted /// Specifies the Api version of the repository to be set. /// [Parameter(ParameterSetName = NameParameterSet)] + [ValidateSet("V2", "V3", "Local", "NugetServer", "ContainerRegistry")] public PSRepositoryInfo.APIVersion ApiVersion { get; set; } /// diff --git a/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 b/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 index 93df34b22..783457d55 100644 --- a/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 +++ b/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 @@ -404,6 +404,14 @@ Describe "Test Register-PSResourceRepository" -tags 'CI' { $res.ApiVersion | Should -Be 'v2' } + It "should throw error when trying to register repository with ApiVersion unknown" { + {Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -ApiVersion "unknown" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PSResourceGet.Cmdlets.RegisterPSResourceRepository" + + # Verify the repository was not created + $repo = Get-PSResourceRepository $TestRepoName1 -ErrorAction SilentlyContinue + $repo | Should -BeNullOrEmpty + } + It "should register container registry repository with correct ApiVersion" { $ContainerRegistryName = "ACRRepo" $ContainerRegistryUri = "https://psresourcegettest.azurecr.io/" diff --git a/test/ResourceRepositoryTests/SetPSResourceRepository.Tests.ps1 b/test/ResourceRepositoryTests/SetPSResourceRepository.Tests.ps1 index fa9120dfe..3a4d4f10c 100644 --- a/test/ResourceRepositoryTests/SetPSResourceRepository.Tests.ps1 +++ b/test/ResourceRepositoryTests/SetPSResourceRepository.Tests.ps1 @@ -345,15 +345,16 @@ Describe "Test Set-PSResourceRepository" -tags 'CI' { $repo.Priority | Should -Be 25 } - It "should not change ApiVersion of repository if -ApiVersion parameter was not used" { + It "should throw error when trying to set ApiVersion to unknown" { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $repo = Get-PSResourceRepository $TestRepoName1 $repoApiVersion = $repo.ApiVersion $repoApiVersion | Should -Be "local" - Set-PSResourceRepository -Name $TestRepoName1 -ApiVersion "unknown" -ErrorVariable err -ErrorAction SilentlyContinue + {Set-PSResourceRepository -Name $TestRepoName1 -ApiVersion "unknown" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PSResourceGet.Cmdlets.SetPSResourceRepository" + + # Verify the repository ApiVersion was not changed $repo = Get-PSResourceRepository $TestRepoName1 - $repo.ApiVersion | Should -Be "unknown" - $err.Count | Should -Be 0 + $repo.ApiVersion | Should -Be "local" } } From d2789d199fbe6f2014e1ff89bcc3d4bcb7aa919f Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 1 Dec 2025 14:06:31 -0500 Subject: [PATCH 14/40] Add CodeQL suppression for DefaultAzureCredentialUse (#1917) --- src/code/Utils.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index cc6f0fa14..ee228de1a 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -662,6 +662,7 @@ public static string GetAzAccessToken(PSCmdlet cmdletPassedIn) ExcludeInteractiveBrowserCredential = false }; + // codeql[cs/security/identity/default-azure-credential-use] DefaultAzureCredential is not being used to create a credential in a production environment (i.e hosted server). It is created locally for a PSResourceGet command invocation, intended to be short-lived, and supports multiple authentication mechanisms which cannot be predicted and isolated for the invocation beforehand. var dCred = new DefaultAzureCredential(credOptions); var tokenRequestContext = new TokenRequestContext(new string[] { "https://management.azure.com/.default" }); From 30c54d9fe63d4dae2b2289e02f8602dfe6e34252 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 3 Dec 2025 10:51:36 -0800 Subject: [PATCH 15/40] Improve performance of ContainerRegistry repositories by caching token (#1920) --- src/code/ContainerRegistryServerAPICalls.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index d828c543d..ff3445ac3 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -54,6 +54,8 @@ internal class ContainerRegistryServerAPICalls : ServerApiCall const string containerRegistryRepositoryListTemplate = "https://{0}/v2/_catalog"; // 0 - registry + private string _cachedContainterRegistryToken = null; + #endregion #region Constructor @@ -68,6 +70,8 @@ public ContainerRegistryServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmd Credentials = networkCredential }; + _cachedContainterRegistryToken = null; + _sessionClient = new HttpClient(handler); _sessionClient.Timeout = TimeSpan.FromMinutes(10); _sessionClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", userAgentString); @@ -384,6 +388,12 @@ internal string GetContainerRegistryAccessToken(bool needCatalogAccess, out Erro string tenantID = string.Empty; errRecord = null; + if (!string.IsNullOrEmpty(_cachedContainterRegistryToken)) + { + _cmdletPassedIn.WriteVerbose("Using cached container registry access token."); + return _cachedContainterRegistryToken; + } + var repositoryCredentialInfo = Repository.CredentialInfo; if (repositoryCredentialInfo != null) { @@ -445,6 +455,9 @@ internal string GetContainerRegistryAccessToken(bool needCatalogAccess, out Erro return null; } + _cmdletPassedIn.WriteVerbose("Container registry access token retrieved."); + _cachedContainterRegistryToken = containerRegistryAccessToken; + return containerRegistryAccessToken; } @@ -739,7 +752,7 @@ internal Hashtable GetContainerRegistryMetadata(string packageName, string exact { using (JsonDocument metadataJSONDoc = JsonDocument.Parse(serverPkgInfo.Metadata)) { - string pkgVersionString = String.Empty; + string pkgVersionString = String.Empty; JsonElement rootDom = metadataJSONDoc.RootElement; if (rootDom.TryGetProperty("ModuleVersion", out JsonElement pkgVersionElement)) From ab4fac1b18993d0862fa1555e9e360452c6e419d Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 4 Dec 2025 11:56:51 -0500 Subject: [PATCH 16/40] Fix Update-PSResource re-installing dependency packages which already meet dependency criteria (#1919) --- src/code/InstallHelper.cs | 10 ++++++++++ src/code/UpdatePSResource.cs | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 83900e413..fef419a4f 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -587,6 +587,16 @@ private List InstallPackages( } } + string depPkgNameVersion = $"{depPkg.Name}{depPkg.Version.ToString()}"; + if (_packagesOnMachine.Contains(depPkgNameVersion) && !depPkg.IsPrerelease) + { + // if a dependency package is already installed, do not install it again. + // to determine if the package version is already installed, _packagesOnMachine is used but it only contains name, version info, not version with prerelease info + // if the dependency package is found to be prerelease, it is safer to install it (and worse case it reinstalls) + _cmdletPassedIn.WriteVerbose($"Dependency '{depPkg.Name}' with version '{depPkg.Version}' is already installed."); + continue; + } + packagesHash = BeginPackageInstall( searchVersionType: VersionType.SpecificVersion, specificVersion: depVersion, diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 86e2cf1ae..6cfc4fbbe 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -25,6 +25,7 @@ public sealed class UpdatePSResource : PSCmdlet { #region Members private List _pathsToInstallPkg; + private HashSet _packagesOnMachine; private CancellationTokenSource _cancellationTokenSource; private FindHelper _findHelper; private InstallHelper _installHelper; @@ -157,6 +158,8 @@ protected override void BeginProcessing() RepositorySettings.CheckRepositoryStore(); _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); + List pathsToSearch = Utils.GetAllResourcePaths(this, Scope); + _packagesOnMachine = Utils.GetInstalledPackages(pathsToSearch, this); _cancellationTokenSource = new CancellationTokenSource(); var networkCred = Credential != null ? new NetworkCredential(Credential.UserName, Credential.Password) : null; @@ -216,7 +219,7 @@ protected override void ProcessRecord() pathsToInstallPkg: _pathsToInstallPkg, scope: Scope, tmpPath: _tmpPath, - pkgsInstalled: new HashSet(StringComparer.InvariantCultureIgnoreCase)); + pkgsInstalled: _packagesOnMachine); if (PassThru) { From 79404f323af33fdf24703937c959c6c4a8fb2dc8 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:18:35 -0800 Subject: [PATCH 17/40] Remove unused _networkCredential field and fix parameter shadowing in PublishHelper (#1914) --- src/code/PublishHelper.cs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/code/PublishHelper.cs b/src/code/PublishHelper.cs index 4b813362f..abdced37b 100644 --- a/src/code/PublishHelper.cs +++ b/src/code/PublishHelper.cs @@ -50,7 +50,6 @@ internal enum CallerCmdlet private string pathToModuleDirToPublish = string.Empty; private string pathToNupkgToPublish = string.Empty; private ResourceType resourceType = ResourceType.None; - private NetworkCredential _networkCredential; string userAgentString = UserAgentInfo.UserAgentString(); private bool _isNupkgPathSpecified = false; private Hashtable dependencies; @@ -381,7 +380,7 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe } // Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement. - _networkCredential = repository.SetNetworkCredentials(_networkCredential, _cmdletPassedIn); + var networkCredential = repository.SetNetworkCredentials(_networkCredential, _cmdletPassedIn); // Check if dependencies already exist within the repo if: // 1) the resource to publish has dependencies and @@ -389,7 +388,7 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe if (dependencies != null && !SkipDependenciesCheck) { // If error gets thrown, exit process record - if (!CheckDependenciesExist(dependencies, repository.Name)) + if (!CheckDependenciesExist(dependencies, repository.Name, networkCredential)) { return; } @@ -440,7 +439,7 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe if (repository.ApiVersion == PSRepositoryInfo.APIVersion.ContainerRegistry) { - ContainerRegistryServerAPICalls containerRegistryServer = new ContainerRegistryServerAPICalls(repository, _cmdletPassedIn, _networkCredential, userAgentString); + ContainerRegistryServerAPICalls containerRegistryServer = new ContainerRegistryServerAPICalls(repository, _cmdletPassedIn, networkCredential, userAgentString); if (_isNupkgPathSpecified) { @@ -475,7 +474,7 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe } // This call does not throw any exceptions, but it will write unsuccessful responses to the console - if (!PushNupkg(outputNupkgDir, repository.Name, repository.Uri.ToString(), out ErrorRecord pushNupkgError)) + if (!PushNupkg(outputNupkgDir, repository.Name, repository.Uri.ToString(), networkCredential, out ErrorRecord pushNupkgError)) { _cmdletPassedIn.WriteError(pushNupkgError); // exit out of processing @@ -648,7 +647,7 @@ private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFil return true; } - private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, out ErrorRecord error) + private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, NetworkCredential networkCredential, out ErrorRecord error) { _cmdletPassedIn.WriteDebug("In PublishPSResource::PushNupkg()"); @@ -674,9 +673,9 @@ private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, o var success = false; var sourceProvider = new PackageSourceProvider(settings); - if (Credential != null || _networkCredential != null) + if (Credential != null || networkCredential != null) { - InjectCredentialsToSettings(settings, sourceProvider, publishLocation); + InjectCredentialsToSettings(settings, sourceProvider, publishLocation, networkCredential); } @@ -833,10 +832,10 @@ private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, o return success; } - private void InjectCredentialsToSettings(ISettings settings, IPackageSourceProvider sourceProvider, string source) + private void InjectCredentialsToSettings(ISettings settings, IPackageSourceProvider sourceProvider, string source, NetworkCredential networkCredential) { _cmdletPassedIn.WriteDebug("In PublishPSResource::InjectCredentialsToSettings()"); - if (Credential == null && _networkCredential == null) + if (Credential == null && networkCredential == null) { return; } @@ -851,7 +850,7 @@ private void InjectCredentialsToSettings(ISettings settings, IPackageSourceProvi } - var networkCred = Credential == null ? _networkCredential : Credential.GetNetworkCredential(); + var networkCred = Credential == null ? networkCredential : Credential.GetNetworkCredential(); string key; if (packageSource == null) @@ -1246,7 +1245,7 @@ private Hashtable ParseRequiredModules(Hashtable parsedMetadataHash) return dependenciesHash; } - private bool CheckDependenciesExist(Hashtable dependencies, string repositoryName) + private bool CheckDependenciesExist(Hashtable dependencies, string repositoryName, NetworkCredential networkCredential) { _cmdletPassedIn.WriteDebug("In PublishHelper::CheckDependenciesExist()"); @@ -1276,7 +1275,7 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam } // Search for and return the dependency if it's in the repository. - FindHelper findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn, _networkCredential); + FindHelper findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn, networkCredential); var repository = new[] { repositoryName }; // Note: we set prerelease argument for FindByResourceName() to true because if no version is specified we want latest version (including prerelease). From 06b4384f8066d84f64cf703547e7e621a3d02457 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 4 Dec 2025 14:19:27 -0500 Subject: [PATCH 18/40] Filter out path separators in package names (#1916) --- src/code/Utils.cs | 7 ++++++- test/SavePSResourceTests/SavePSResourceV2.Tests.ps1 | 6 ++++++ test/SavePSResourceTests/SavePSResourceV3.Tests.ps1 | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ee228de1a..26d3ab25e 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -189,13 +189,18 @@ public static string[] ProcessNameWildcards( if (name.Contains("?") || name.Contains("[")) { - errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); + errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: '{0}' will be discarded.", name)); continue; } isContainWildcard = true; namesWithSupportedWildcards.Add(name); } + else if(name.StartsWith("/") || name.StartsWith("\\")) + { + errorMsgsList.Add(String.Format("-Name starting with path separator '/' or '\\' is not supported for this cmdlet so Name entry: '{0}' will be discarded.", name)); + continue; + } else { namesWithSupportedWildcards.Add(name); diff --git a/test/SavePSResourceTests/SavePSResourceV2.Tests.ps1 b/test/SavePSResourceTests/SavePSResourceV2.Tests.ps1 index 609c73e3d..4b0269d82 100644 --- a/test/SavePSResourceTests/SavePSResourceV2.Tests.ps1 +++ b/test/SavePSResourceTests/SavePSResourceV2.Tests.ps1 @@ -208,4 +208,10 @@ Describe 'Test HTTP Save-PSResource for V2 Server Protocol' -tags 'CI' { $pkg.Name | Should -Be $testModuleNameWithLicense $pkg.Version | Should -Be "2.0" } + + It "Not save module that has path separator in name" { + Save-PSResource -Name "/$testModuleName" -Repository $PSGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue -TrustRepository + $err.Count | Should -BeGreaterThan 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly 'ErrorFilteringNamesForUnsupportedWildcards,Microsoft.PowerShell.PSResourceGet.Cmdlets.SavePSResource' + } } diff --git a/test/SavePSResourceTests/SavePSResourceV3.Tests.ps1 b/test/SavePSResourceTests/SavePSResourceV3.Tests.ps1 index 037ed1674..f4118d265 100644 --- a/test/SavePSResourceTests/SavePSResourceV3.Tests.ps1 +++ b/test/SavePSResourceTests/SavePSResourceV3.Tests.ps1 @@ -159,4 +159,10 @@ Describe 'Test HTTP Save-PSResource for V3 Server Protocol' -tags 'CI' { $res = Save-PSResource 'TestModuleWithDependencyE' -Repository $NuGetGalleryName -TrustRepository -PassThru $res.Length | Should -Be 4 } + + It "Not save module that has path separator in name" { + Save-PSResource -Name "/$testModuleName" -Repository $NuGetGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue -TrustRepository + $err.Count | Should -BeGreaterThan 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly 'ErrorFilteringNamesForUnsupportedWildcards,Microsoft.PowerShell.PSResourceGet.Cmdlets.SavePSResource' + } } From 5da84faf488e34809e643761a05952514a5ffe2c Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 5 Dec 2025 15:43:10 -0500 Subject: [PATCH 19/40] For Publish operation to ACR, non-anonymous access token should be retrieved (#1918) --- src/code/ContainerRegistryServerAPICalls.cs | 15 +++++++++------ ...SResourceContainerRegistryServer.Tests.ps1 | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index ff3445ac3..9c17c0db0 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -332,7 +332,7 @@ private Stream InstallVersion( return null; } - string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, out errRecord); + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, isPushOperation: false, out errRecord); if (errRecord != null) { return null; @@ -380,7 +380,7 @@ private Stream InstallVersion( /// If no credential provided at registration then, check if the ACR endpoint can be accessed without a token. If not, try using Azure.Identity to get the az access token, then ACR refresh token and then ACR access token. /// Note: Access token can be empty if the repository is unauthenticated /// - internal string GetContainerRegistryAccessToken(bool needCatalogAccess, out ErrorRecord errRecord) + internal string GetContainerRegistryAccessToken(bool needCatalogAccess, bool isPushOperation, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::GetContainerRegistryAccessToken()"); string accessToken = string.Empty; @@ -408,7 +408,10 @@ internal string GetContainerRegistryAccessToken(bool needCatalogAccess, out Erro } else { - bool isRepositoryUnauthenticated = IsContainerRegistryUnauthenticated(Repository.Uri.ToString(), needCatalogAccess, out errRecord, out accessToken); + // A container registry repository is determined to be unauthenticated if it allows anonymous pull access. However, push operations always require authentication. + bool isRepositoryUnauthenticated = isPushOperation ? false : IsContainerRegistryUnauthenticated(Repository.Uri.ToString(), needCatalogAccess, out errRecord, out accessToken); + _cmdletPassedIn.WriteInformation($"Value of isRepositoryUnauthenticated: {isRepositoryUnauthenticated}", new string[] { "PSRGContainerRegistryUnauthenticatedCheck" }); + _cmdletPassedIn.WriteDebug($"Is repository unauthenticated: {isRepositoryUnauthenticated}"); if (errRecord != null) @@ -1330,7 +1333,7 @@ internal bool PushNupkgContainerRegistry( // Get access token (includes refresh tokens) _cmdletPassedIn.WriteVerbose($"Get access token for container registry server."); - var containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, out errRecord); + var containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, isPushOperation: true, out errRecord); if (errRecord != null) { return false; @@ -1795,7 +1798,7 @@ private Hashtable[] FindPackagesWithVersionHelper(string packageName, VersionTyp string packageNameLowercase = packageName.ToLower(); string packageNameForFind = PrependMARPrefix(packageNameLowercase); - string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, out errRecord); + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, isPushOperation: false,out errRecord); if (errRecord != null) { return emptyHashResponses; @@ -1907,7 +1910,7 @@ private FindResults FindPackages(string packageName, bool includePrerelease, out { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindPackages()"); errRecord = null; - string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: true, out errRecord); + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: true, isPushOperation: false, out errRecord); if (errRecord != null) { return emptyResponseResults; diff --git a/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 b/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 index 9714a627c..bd59d69d0 100644 --- a/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 +++ b/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 @@ -346,6 +346,25 @@ Describe "Test Publish-PSResource" -tags 'CI' { $results[0].Version | Should -Be $correctVersion } + It "Publish a package should always require authentication" { + $version = "15.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository $ACRRepoName -InformationVariable RegistryUnauthenticated + + $results = Find-PSResource -Name $script:PublishModuleName -Repository $ACRRepoName + $results | Should -Not -BeNullOrEmpty + $results[0].Name | Should -Be $script:PublishModuleName + $results[0].Version | Should -Be $version + + if ($usingAzAuth) + { + $RegistryUnauthenticated | Should -Not -BeNullOrEmpty + $RegistryUnauthenticated[0].Tags | Should -Be "PSRGContainerRegistryUnauthenticatedCheck" + $RegistryUnauthenticated[0].MessageData | Should -Be "Value of isRepositoryUnauthenticated: False" + } + } + It "Publish a script"{ $scriptVersion = "1.0.0" $params = @{ From e2bf4ee1f3a03dcd1c92599cdf0a04e03a8ebc33 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:52:16 -0800 Subject: [PATCH 20/40] Add Reset-PSResourceRepository cmdlet to recover from corrupted repository store (#1895) --- src/Microsoft.PowerShell.PSResourceGet.psd1 | 1 + src/code/RepositorySettings.cs | 112 ++++++++++++- src/code/ResetPSResourceRepository.cs | 70 ++++++++ .../ResetPSResourceRepository.Tests.ps1 | 149 ++++++++++++++++++ 4 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 src/code/ResetPSResourceRepository.cs create mode 100644 test/ResourceRepositoryTests/ResetPSResourceRepository.Tests.ps1 diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 617f0cb33..92c49df12 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -23,6 +23,7 @@ 'Get-PSScriptFileInfo', 'Install-PSResource', 'Register-PSResourceRepository', + 'Reset-PSResourceRepository', 'Save-PSResource', 'Set-PSResourceRepository', 'New-PSScriptFileInfo', diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 39f129006..7cf4f9261 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -72,7 +72,7 @@ public static void CheckRepositoryStore() } catch (Exception e) { - throw new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Repository store may be corrupted, file reading failed with error: {0}.", e.Message)); + throw new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Repository store may be corrupted, file reading failed with error: {0}. Try running 'Reset-PSResourceRepository' to reset the repository store.", e.Message)); } } @@ -845,6 +845,116 @@ public static List Read(string[] repoNames, out string[] error return reposToReturn.ToList(); } + /// + /// Reset the repository store by creating a new PSRepositories.xml file with PSGallery registered. + /// This creates a temporary new file first, and only replaces the old file if creation succeeds. + /// If creation fails, the old file is restored. + /// Returns: PSRepositoryInfo for the PSGallery repository + /// + public static PSRepositoryInfo Reset(out string errorMsg) + { + errorMsg = string.Empty; + string tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".xml"); + string backupFilePath = string.Empty; + + try + { + // Ensure the repository directory exists + if (!Directory.Exists(RepositoryPath)) + { + Directory.CreateDirectory(RepositoryPath); + } + + // Create new repository XML in a temporary location + XDocument newRepoXML = new XDocument( + new XElement("configuration")); + newRepoXML.Save(tempFilePath); + + // Validate that the temporary file can be loaded + try + { + LoadXDocument(tempFilePath); + } + catch (Exception loadEx) + { + // Clean up temp file on validation failure + if (File.Exists(tempFilePath)) + { + try + { + File.Delete(tempFilePath); + } + catch (Exception cleanupEx) + { + errorMsg = string.Format(CultureInfo.InvariantCulture, "Failed to validate newly created repository store file with error: {0}. Additionally, cleanup of temporary file failed with error: {1}", loadEx.Message, cleanupEx.Message); + return null; + } + } + errorMsg = string.Format(CultureInfo.InvariantCulture, "Failed to validate newly created repository store file with error: {0}.", loadEx.Message); + return null; + } + + // Back up the existing file if it exists + if (File.Exists(FullRepositoryPath)) + { + backupFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + "_backup.xml"); + Utils.MoveFiles(FullRepositoryPath, backupFilePath, overwrite: true); + } + + // Move the temporary file to the actual location + Utils.MoveFiles(tempFilePath, FullRepositoryPath, overwrite: true); + + // Add PSGallery to the newly created store + Uri psGalleryUri = new Uri(PSGalleryRepoUri); + PSRepositoryInfo psGalleryRepo = Add(PSGalleryRepoName, psGalleryUri, DefaultPriority, DefaultTrusted, repoCredentialInfo: null, repoCredentialProvider: CredentialProviderType.None, APIVersion.V2, force: false); + + // Clean up backup file on success + if (!string.IsNullOrEmpty(backupFilePath) && File.Exists(backupFilePath)) + { + File.Delete(backupFilePath); + } + + return psGalleryRepo; + } + catch (Exception e) + { + // Restore the backup file if it exists + if (!string.IsNullOrEmpty(backupFilePath) && File.Exists(backupFilePath)) + { + try + { + if (File.Exists(FullRepositoryPath)) + { + File.Delete(FullRepositoryPath); + } + Utils.MoveFiles(backupFilePath, FullRepositoryPath, overwrite: true); + } + catch (Exception restoreEx) + { + errorMsg = string.Format(CultureInfo.InvariantCulture, "Repository store reset failed with error: {0}. An attempt to restore the old repository store also failed with error: {1}", e.Message, restoreEx.Message); + return null; + } + } + + // Clean up temporary file + if (File.Exists(tempFilePath)) + { + try + { + File.Delete(tempFilePath); + } + catch (Exception cleanupEx) + { + errorMsg = string.Format(CultureInfo.InvariantCulture, "Repository store reset failed with error: {0}. Additionally, cleanup of temporary file failed with error: {1}", e.Message, cleanupEx.Message); + return null; + } + } + + errorMsg = string.Format(CultureInfo.InvariantCulture, "Repository store reset failed with error: {0}.", e.Message); + return null; + } + } + #endregion #region Private methods diff --git a/src/code/ResetPSResourceRepository.cs b/src/code/ResetPSResourceRepository.cs new file mode 100644 index 000000000..2c217aab3 --- /dev/null +++ b/src/code/ResetPSResourceRepository.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PSResourceGet.UtilClasses; +using System; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PSResourceGet.Cmdlets +{ + /// + /// The Reset-PSResourceRepository cmdlet resets the repository store by creating a new PSRepositories.xml file. + /// This is useful when the repository store becomes corrupted. + /// It will create a new repository store with only the PSGallery repository registered. + /// + [Cmdlet(VerbsCommon.Reset, + "PSResourceRepository", + SupportsShouldProcess = true, + ConfirmImpact = ConfirmImpact.High)] + [OutputType(typeof(PSRepositoryInfo))] + public sealed class ResetPSResourceRepository : PSCmdlet + { + #region Parameters + + /// + /// When specified, displays the PSGallery repository that was registered after reset + /// + [Parameter] + public SwitchParameter PassThru { get; set; } + + #endregion + + #region Methods + + protected override void ProcessRecord() + { + string repositoryStorePath = System.IO.Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "PSResourceGet", + "PSResourceRepository.xml"); + + WriteVerbose($"Resetting repository store at: {repositoryStorePath}"); + + if (!ShouldProcess(repositoryStorePath, "Reset repository store and create new PSRepositories.xml file with PSGallery registered")) + { + return; + } + + PSRepositoryInfo psGalleryRepo = RepositorySettings.Reset(out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorResettingRepositoryStore", + ErrorCategory.InvalidOperation, + this)); + return; + } + + WriteVerbose("Repository store reset successfully. PSGallery has been registered."); + + if (PassThru) + { + WriteObject(psGalleryRepo); + } + } + + #endregion + } +} diff --git a/test/ResourceRepositoryTests/ResetPSResourceRepository.Tests.ps1 b/test/ResourceRepositoryTests/ResetPSResourceRepository.Tests.ps1 new file mode 100644 index 000000000..f49570229 --- /dev/null +++ b/test/ResourceRepositoryTests/ResetPSResourceRepository.Tests.ps1 @@ -0,0 +1,149 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$modPath = "$psscriptroot/../PSGetTestUtils.psm1" +Write-Verbose -Verbose -Message "PSGetTestUtils path: $modPath" +Import-Module $modPath -Force -Verbose + +Describe "Test Reset-PSResourceRepository" -tags 'CI' { + BeforeEach { + $PSGalleryName = Get-PSGalleryName + $PSGalleryUri = Get-PSGalleryLocation + Get-NewPSResourceRepositoryFile + } + + AfterEach { + Get-RevertPSResourceRepositoryFile + } + + It "Reset repository store without PassThru parameter" { + # Arrange: Add a test repository + $TestRepoName = "testRepository" + $tmpDirPath = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + New-Item -ItemType Directory -Path $tmpDirPath -Force | Out-Null + Register-PSResourceRepository -Name $TestRepoName -Uri $tmpDirPath + + # Verify repository was added + $repos = Get-PSResourceRepository + $repos.Count | Should -BeGreaterThan 1 + + # Act: Reset repository store + Reset-PSResourceRepository -Confirm:$false + + # Assert: Only PSGallery should exist + $repos = Get-PSResourceRepository + $repos.Count | Should -Be 1 + $repos.Name | Should -Be $PSGalleryName + $repos.Uri | Should -Be $PSGalleryUri + } + + It "Reset repository store with PassThru parameter returns PSGallery" { + # Arrange: Add a test repository + $TestRepoName = "testRepository" + $tmpDirPath = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + New-Item -ItemType Directory -Path $tmpDirPath -Force | Out-Null + Register-PSResourceRepository -Name $TestRepoName -Uri $tmpDirPath + + # Act: Reset repository store with PassThru + $result = Reset-PSResourceRepository -Confirm:$false -PassThru + + # Assert: Result should be PSGallery repository info + $result | Should -Not -BeNullOrEmpty + $result.Name | Should -Be $PSGalleryName + $result.Uri | Should -Be $PSGalleryUri + $result.Trusted | Should -Be $false + $result.Priority | Should -Be 50 + + # Verify only PSGallery exists + $repos = Get-PSResourceRepository + $repos.Count | Should -Be 1 + } + + It "Reset repository store should support -WhatIf" { + # Arrange: Add a test repository + $TestRepoName = "testRepository" + $tmpDirPath = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + New-Item -ItemType Directory -Path $tmpDirPath -Force | Out-Null + Register-PSResourceRepository -Name $TestRepoName -Uri $tmpDirPath + + # Capture repository count before WhatIf + $reposBefore = Get-PSResourceRepository + $countBefore = $reposBefore.Count + + # Act: Run with WhatIf + Reset-PSResourceRepository -WhatIf + + # Assert: Repositories should not have changed + $reposAfter = Get-PSResourceRepository + $reposAfter.Count | Should -Be $countBefore + } + + It "Reset repository store when corrupted should succeed" { + # Arrange: Corrupt the repository file + $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PSResourceGet" + $repoFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" + + # Write invalid XML to corrupt the file + "This is not valid XML" | Set-Content -Path $repoFilePath -Force + + # Act: Reset the repository store + $result = Reset-PSResourceRepository -Confirm:$false -PassThru + + # Assert: Should successfully reset and return PSGallery + $result | Should -Not -BeNullOrEmpty + $result.Name | Should -Be $PSGalleryName + + # Verify we can now read repositories + $repos = Get-PSResourceRepository + $repos.Count | Should -Be 1 + $repos.Name | Should -Be $PSGalleryName + } + + It "Reset repository store when file doesn't exist should succeed" { + # Arrange: Delete the repository file + $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PSResourceGet" + $repoFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" + + if (Test-Path -Path $repoFilePath) { + Remove-Item -Path $repoFilePath -Force + } + + # Act: Reset the repository store + $result = Reset-PSResourceRepository -Confirm:$false -PassThru + + # Assert: Should successfully reset and return PSGallery + $result | Should -Not -BeNullOrEmpty + $result.Name | Should -Be $PSGalleryName + + # Verify PSGallery is registered + $repos = Get-PSResourceRepository + $repos.Count | Should -Be 1 + $repos.Name | Should -Be $PSGalleryName + } + + It "Reset repository store with multiple repositories should only keep PSGallery" { + # Arrange: Register multiple repositories + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + New-Item -ItemType Directory -Path $tmpDir1Path -Force | Out-Null + New-Item -ItemType Directory -Path $tmpDir2Path -Force | Out-Null + New-Item -ItemType Directory -Path $tmpDir3Path -Force | Out-Null + + Register-PSResourceRepository -Name "testRepo1" -Uri $tmpDir1Path + Register-PSResourceRepository -Name "testRepo2" -Uri $tmpDir2Path + Register-PSResourceRepository -Name "testRepo3" -Uri $tmpDir3Path + + # Verify multiple repositories exist + $reposBefore = Get-PSResourceRepository + $reposBefore.Count | Should -BeGreaterThan 1 + + # Act: Reset repository store + Reset-PSResourceRepository -Confirm:$false + + # Assert: Only PSGallery should remain + $reposAfter = Get-PSResourceRepository + $reposAfter.Count | Should -Be 1 + $reposAfter.Name | Should -Be $PSGalleryName + } +} From 80d1ef055424230e9fbc0cdef1597e7812114a6a Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:46:04 -0800 Subject: [PATCH 21/40] Update version, changelog, release notes for 1.2.0-preview5 (#1921) --- CHANGELOG/preview.md | 14 ++++++++++++++ src/Microsoft.PowerShell.PSResourceGet.psd1 | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 3ba5f8ee8..81722e8c6 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,19 @@ # Preview Changelog +## [1.2.0-preview5](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview4..v1.2.0-preview5) - 2025-12-05 + +### New Features +- Add `Reset-PSResourceRepository` cmdlet to recover from corrupted repository store (#1895) +- Improve performance of `ContainerRegistry` repositories by caching token (#1920) + +## Bug fix +- Ensure `Update-PSResource` does not re-install dependency packages which already satisfy dependency criteria (#1919) +- Retrieve non-anonymous access token when publishing to ACR (#1918) +- Filter out path separators when passing in package names as a parameter for any cmdlet (#1916) +- Respect `TrustRepository` parameter when using `-RequiredResource` with `Install-PSResource` (#1910) +- Fix bug with 'PSModuleInfo' property deserialization when validating module manifest (#1909) +- Prevent users from setting ApiVersion to 'Unknown' in `Set-PSResourceRepository` and `Register-PSResourceRepository` (#1892) + ## [1.2.0-preview4](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview3..v1.2.0-preview4) - 2025-11-04 ## Bug fix diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 92c49df12..390155138 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -50,7 +50,7 @@ 'usres') PrivateData = @{ PSData = @{ - Prerelease = 'preview4' + Prerelease = 'preview5' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -60,6 +60,20 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 1.2.0-preview5 + +### New Features +- Add `Reset-PSResourceRepository` cmdlet to recover from corrupted repository store (#1895) +- Improve performance of `ContainerRegistry` repositories by caching token (#1920) + +## Bug fix +- Ensure `Update-PSResource` does not re-install dependency packages which already satisfy dependency criteria (#1919) +- Retrieve non-anonymous access token when publishing to ACR (#1918) +- Filter out path separators when passing in package names as a parameter for any cmdlet (#1916) +- Respect `TrustRepository` parameter when using `-RequiredResource` with `Install-PSResource` (#1910) +- Fix bug with 'PSModuleInfo' property deserialization when validating module manifest (#1909) +- Prevent users from setting ApiVersion to 'Unknown' in `Set-PSResourceRepository` and `Register-PSResourceRepository` (#1892) + ## 1.2.0-preview4 ## Bug fix From c012d389e1d5cdcd96dc83a3a3e65a19ff7d3277 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 14 Jan 2026 12:55:42 -0500 Subject: [PATCH 22/40] WhatIf parameter should respect provided value instead of simply checking presence (#1925) --- src/code/InstallHelper.cs | 4 ++-- src/code/RegisterPSResourceRepository.cs | 23 +++++++++++-------- ...allPSResourceRepositorySearching.Tests.ps1 | 8 +++++++ .../RegisterPSResourceRepository.Tests.ps1 | 6 +++++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index fef419a4f..0616cf040 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -342,7 +342,7 @@ private List ProcessRepositories( allPkgsInstalled.AddRange(installedPkgs); } - if (!_cmdletPassedIn.MyInvocation.BoundParameters.ContainsKey("WhatIf") && _pkgNamesToInstall.Count > 0) + if ((!_cmdletPassedIn.MyInvocation.BoundParameters.ContainsKey("WhatIf") || (SwitchParameter)_cmdletPassedIn.MyInvocation.BoundParameters["WhatIf"] == false) && _pkgNamesToInstall.Count > 0) { string repositoryWording = repositoryNamesToSearch.Count > 1 ? "registered repositories" : "repository"; _cmdletPassedIn.WriteError(new ErrorRecord( @@ -624,7 +624,7 @@ private List InstallPackages( } // If -WhatIf is passed in, early out. - if (_cmdletPassedIn.MyInvocation.BoundParameters.ContainsKey("WhatIf")) + if (_cmdletPassedIn.MyInvocation.BoundParameters.ContainsKey("WhatIf") && (SwitchParameter)_cmdletPassedIn.MyInvocation.BoundParameters["WhatIf"] == true) { return pkgsSuccessfullyInstalled; } diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index ddf5cad24..a4994df8a 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -186,17 +186,20 @@ protected override void ProcessRecord() break; case PSGalleryParameterSet: - try - { - items.Add(PSGalleryParameterSetHelper(Priority, Trusted)); - } - catch (Exception e) + if (PSGallery) { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException(e.Message), - "ErrorInPSGalleryParameterSet", - ErrorCategory.InvalidArgument, - this)); + try + { + items.Add(PSGalleryParameterSetHelper(Priority, Trusted)); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorInPSGalleryParameterSet", + ErrorCategory.InvalidArgument, + this)); + } } break; diff --git a/test/InstallPSResourceTests/InstallPSResourceRepositorySearching.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceRepositorySearching.Tests.ps1 index 46d4c54a6..eea4dae94 100644 --- a/test/InstallPSResourceTests/InstallPSResourceRepositorySearching.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceRepositorySearching.Tests.ps1 @@ -137,4 +137,12 @@ Describe 'Test Install-PSResource for searching and looping through repositories $err | Should -HaveCount 0 $warningVar | Should -Not -BeNullOrEmpty } + + It "install resources from repository should respect WhatIf value of false" { + # Package "test_module" exists in the following repositories (in this order): localRepo, PSGallery, NuGetGallery + $res = Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -SkipDependencyCheck -PassThru -WhatIf:$false + $res | Should -Not -BeNullOrEmpty + $res.Name | Should -Be $testModuleName + $res.Repository | Should -Be $PSGalleryName + } } diff --git a/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 b/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 index 783457d55..f9c350356 100644 --- a/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 +++ b/test/ResourceRepositoryTests/RegisterPSResourceRepository.Tests.ps1 @@ -85,6 +85,12 @@ Describe "Test Register-PSResourceRepository" -tags 'CI' { $res.Priority | Should -Be 50 } + It "register repository with PSGallery switch parameter value of false (PSGalleryParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + $res = Register-PSResourceRepository -PSGallery:$false -PassThru + $res | Should -BeNullOrEmpty + } + It "register repository with PSGallery, Trusted parameters (PSGalleryParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName $res = Register-PSResourceRepository -PSGallery -Trusted -PassThru From 9c0664011b76d2af14823083e36679a28bfb4dba Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 14 Jan 2026 15:01:30 -0500 Subject: [PATCH 23/40] Update version, changelog, release notes for 1.2.0-rc1 (#1927) --- CHANGELOG/preview.md | 5 +++++ src/Microsoft.PowerShell.PSResourceGet.psd1 | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 81722e8c6..f1d5ee63c 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,10 @@ # Preview Changelog +## [1.2.0-rc1](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview5..v1.2.0-rc1) - 2026-01-14 + +## Bug fix +- `WhatIf` parameter should respect provided value instead of simply checking presence (#1925) + ## [1.2.0-preview5](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview4..v1.2.0-preview5) - 2025-12-05 ### New Features diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 390155138..033434457 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -50,7 +50,7 @@ 'usres') PrivateData = @{ PSData = @{ - Prerelease = 'preview5' + Prerelease = 'rc1' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -60,6 +60,11 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 1.2.0-rc1 + +## Bug fix +- `WhatIf` parameter should respect provided value instead of simply checking presence (#1925) + ## 1.2.0-preview5 ### New Features From 097cfc26ab6f9e9ce694d75a7a6341909244843a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 14 Jan 2026 15:28:59 -0500 Subject: [PATCH 24/40] Update dotnet version (#1928) --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index bb0a2659e..9289a72a0 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.415" + "version": "8.0.417" } } From 10f06cdc83290e4a88cc22f6953e2509e5d1502d Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 5 Feb 2026 17:47:32 -0500 Subject: [PATCH 25/40] For packages with dependency on a specific version use specific version instead of version range (#1937) --- src/code/FindHelper.cs | 64 +++++++++++++++++++ src/code/FindPSResource.cs | 6 ++ .../FindPSResourceV2Server.Tests.ps1 | 11 ++++ .../InstallPSResourceV2Server.Tests.ps1 | 17 ++++- 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index d8287c689..024623503 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1171,6 +1171,70 @@ internal IEnumerable FindDependencyPackages( } } } + else if(dep.VersionRange.MaxVersion != null && dep.VersionRange.MinVersion != null && dep.VersionRange.MaxVersion.OriginalVersion.Equals(dep.VersionRange.MinVersion.OriginalVersion)) + { + string depPkgVersion = dep.VersionRange.MaxVersion.OriginalVersion; + FindResults responses = currentServer.FindVersion(dep.Name, version: dep.VersionRange.MaxVersion.OriginalVersion, _type, out ErrorRecord errRecord); + if (errRecord != null) + { + if (errRecord.Exception is ResourceNotFoundException) + { + _cmdletPassedIn.WriteVerbose(errRecord.Exception.Message); + } + else + { + _cmdletPassedIn.WriteError(errRecord); + } + yield return null; + continue; + } + + PSResourceResult currentResult = currentResponseUtil.ConvertToPSResourceResult(responses).FirstOrDefault(); + if (currentResult == null) + { + // This scenario may occur when the package version requested is unlisted. + _cmdletPassedIn.WriteError(new ErrorRecord( + new ResourceNotFoundException($"Dependency package with name '{dep.Name}' and version '{depPkgVersion}' could not be found in repository '{repository.Name}'"), + "DependencyPackageNotFound", + ErrorCategory.ObjectNotFound, + this)); + yield return null; + continue; + } + + if (currentResult.exception != null && !currentResult.exception.Message.Equals(string.Empty)) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new ResourceNotFoundException($"Dependency package with name '{dep.Name}' and version '{depPkgVersion}' could not be found in repository '{repository.Name}'", currentResult.exception), + "DependencyPackageNotFound", + ErrorCategory.ObjectNotFound, + this)); + yield return null; + continue; + } + + depPkg = currentResult.returnedObject; + + if (!_packagesFound.ContainsKey(depPkg.Name)) + { + foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository)) + { + yield return depRes; + } + } + else + { + List pkgVersions = _packagesFound[depPkg.Name] as List; + // _packagesFound has depPkg.name in it, but the version is not the same + if (!pkgVersions.Contains(FormatPkgVersionString(depPkg))) + { + foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository)) + { + yield return depRes; + } + } + } + } else { FindResults responses = currentServer.FindVersionGlobbing(dep.Name, dep.VersionRange, includePrerelease: true, ResourceType.None, getOnlyLatest: true, out ErrorRecord errRecord); diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 2709073e7..a0ef9f496 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -234,6 +234,12 @@ private void ProcessResourceNameParameterSet() return; } + + if (versionRange.MinVersion != null && versionRange.MaxVersion != null && versionRange.MinVersion.OriginalVersion.Equals(versionRange.MaxVersion.OriginalVersion)) + { + nugetVersion = versionRange.MaxVersion; + versionType = VersionType.SpecificVersion; + } } else { diff --git a/test/FindPSResourceTests/FindPSResourceV2Server.Tests.ps1 b/test/FindPSResourceTests/FindPSResourceV2Server.Tests.ps1 index 139e68ab0..911471f3b 100644 --- a/test/FindPSResourceTests/FindPSResourceV2Server.Tests.ps1 +++ b/test/FindPSResourceTests/FindPSResourceV2Server.Tests.ps1 @@ -446,6 +446,17 @@ Describe 'Test HTTP Find-PSResource for V2 Server Protocol' -tags 'CI' { $res.Name | Should -Contain 'test_unlisted' $res.Name | Should -Contain 'test_notunlisted' } + + It "Find resource that takes a dependency on package with specific version" { + $moduleName = 'test-nugetversion-parent' + $version = '4.0.0' + $depPkgName = 'test-nugetversion' + + $res = Find-PSResource -Name $moduleName -Version $version -Repository $PSGalleryName -IncludeDependencies + $res.Count | Should -Be 2 + $res.Name | Should -Contain $moduleName + $res.Name | Should -Contain $depPkgName + } } Describe 'Test HTTP Find-PSResource for V2 Server Protocol' -tags 'ManualValidationOnly' { diff --git a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 index e269b2628..852f5d3a3 100644 --- a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 @@ -32,7 +32,7 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { AfterEach { Uninstall-PSResource "test_module", "test_module2", "test_script", "TestModule99", "testModuleWithlicense", ` "TestFindModule", "ClobberTestModule1", "ClobberTestModule2", "PackageManagement", "TestTestScript", ` - "TestModuleWithDependency", "TestModuleWithPrereleaseDep", "PrereleaseModule" -SkipDependencyCheck -ErrorAction SilentlyContinue + "TestModuleWithDependency", "TestModuleWithPrereleaseDep", "PrereleaseModule", "test-nugetversion-parent", "test-nugetversion" -SkipDependencyCheck -ErrorAction SilentlyContinue } AfterAll { @@ -616,6 +616,21 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { $res | Should -Not -BeNullOrEmpty $res.Version | Should -Be $version } + + It "Install resource that takes a dependency on package with specific version" { + $moduleName = 'test-nugetversion-parent' + $version = '4.0.0' + $depPkgName = 'test-nugetversion' + $depPkgVer = '5.0.1' + + Install-PSResource -Name $moduleName -Version $version -Repository $PSGalleryName -TrustRepository + $res = Get-InstalledPSResource $moduleName + $res.Name | Should -Be $moduleName + $res.Version | Should -Be $version + $depRes = Get-InstalledPSResource $depPkgName + $depRes.Name | Should -Be $depPkgName + $depRes.Version | Should -Be $depPkgVer + } } Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'ManualValidationOnly' { From a3e272a4ad3c71f2e61e4e927a82df7a7ad2d14d Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 5 Feb 2026 18:08:12 -0500 Subject: [PATCH 26/40] Update version, changelog, release notes for 1.2.0-rc2 (#1938) --- CHANGELOG/preview.md | 5 +++++ src/Microsoft.PowerShell.PSResourceGet.psd1 | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index f1d5ee63c..c319dbbb6 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,10 @@ # Preview Changelog +## [1.2.0-rc2](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-rc1..v1.2.0-rc2) - 2026-02-05 + +## Bug fix +- For packages that depend on a specific version, use an exact version instead of a version range. (#1937) + ## [1.2.0-rc1](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-preview5..v1.2.0-rc1) - 2026-01-14 ## Bug fix diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 033434457..45cc07ddb 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -50,7 +50,7 @@ 'usres') PrivateData = @{ PSData = @{ - Prerelease = 'rc1' + Prerelease = 'rc2' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -60,6 +60,11 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 1.2.0-rc2 + +## Bug fix +- For packages with dependency on a specific version use specific version instead of version range (#1937) + ## 1.2.0-rc1 ## Bug fix From 1fca92239121657677863cfdcb54b52fe3ba8017 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 5 Feb 2026 19:30:09 -0500 Subject: [PATCH 27/40] Remove older versions in Changelog.md (#1939) --- src/Microsoft.PowerShell.PSResourceGet.psd1 | 158 -------------------- 1 file changed, 158 deletions(-) diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 45cc07ddb..e4737cb26 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -132,164 +132,6 @@ - Improvements in `ContainerRegistry` repositories in listing repository catalog (#1831) - Wildcard attribute added to `-Repository` parameter of `Install-PSResource` (#1808) -## 1.1.1 - -### Bug Fix -- Bugfix to retrieve all metadata properties when finding a PSResource from a ContainerRegistry repository (#1799) -- Update README.md (#1798) -- Use authentication challenge for unauthenticated ContainerRegistry repository (#1797) -- Bugfix for Install-PSResource with varying digit version against ContainerRegistry repository (#1796) -- Bugfix for updating ContainerRegistry dependency parsing logic to account for AzPreview package (#1792) -- Add wildcard support for MAR repository for FindAll and FindByName (#1786) -- Bugfix for nuspec dependency version range calculation for RequiredModules (#1784) - -## 1.1.0 - -### Bug Fix -- Bugfix for publishing .nupkg file to ContainerRegistry repository (#1763) -- Bugfix for PMPs like Artifactory needing modified filter query parameter to proxy upstream (#1761) -- Bugfix for ContainerRegistry repository to parse out dependencies from metadata (#1766) -- Bugfix for Install-PSResource Null pointer occurring when package is present only in upstream feed in ADO (#1760) -- Bugfix for local repository casing issue on Linux (#1750) -- Update README.md (#1759) -- Bug fix for case sensitive License.txt when RequireLicense is specified (#1757) -- Bug fix for broken -Quiet parameter for Save-PSResource (#1745) - -## 1.1.0-rc3 - -### Bug Fix -- Include missing commits - -## 1.1.0-RC2 - -### New Features -- Full Microsoft Artifact Registry integration (#1741) - -### Bug Fixes - -- Update to use OCI v2 APIs for Container Registry (#1737) -- Bug fixes for finding and installing from local repositories on Linux machines (#1738) -- Bug fix for finding package name with 4 part version from local repositories (#1739) - -## 1.1.0-RC1 - -### New Features - -- Group Policy configurations for enabling or disabling PSResource repositories (#1730) - -### Bug Fixes - -- Fix packaging name matching when searching in local repositories (#1731) -- `Compress-PSResource` `-PassThru` now passes `FileInfo` instead of string (#1720) -- Fix for `Compress-PSResource` not properly compressing scripts (#1719) -- Add `AcceptLicense` to Save-PSResource (#1718 Thanks @o-l-a-v!) -- Better support for NuGet v2 feeds (#1713 Thanks @o-l-a-v!) -- Better handling of `-WhatIf` support in `Install-PSResource` (#1531 Thanks @o-l-a-v!) -- Fix for some nupkgs failing to extract due to empty directories (#1707 Thanks @o-l-a-v!) -- Fix for searching for `-Name *` in `Find-PSResource` (#1706 Thanks @o-l-a-v!) - -## 1.1.0-preview2 - -### New Features - -- New cmdlet `Compress-PSResource` which packs a package into a .nupkg and saves it to the file system (#1682, #1702) -- New `-Nupkg` parameter for `Publish-PSResource` which pushes pushes a .nupkg to a repository (#1682) -- New `-ModulePrefix` parameter for `Publish-PSResource` which adds a prefix to a module name for container registry repositories to add a module prefix.This is only used for publishing and is not part of metadata. MAR will drop the prefix when syndicating from ACR to MAR (#1694) - -### Bug Fixes - -- Add prerelease string when NormalizedVersion doesn't exist, but prerelease string does (#1681 Thanks @sean-r-williams) -- Add retry logic when deleting files (#1667 Thanks @o-l-a-v!) -- Fix broken PAT token use (#1672) -- Updated error messaging for authenticode signature failures (#1701) - -## 1.1.0-preview1 - -### New Features - -- Support for Azure Container Registries (#1495, #1497-#1499, #1501, #1502, #1505, #1522, #1545, #1548, #1550, #1554, #1560, #1567, -#1573, #1576, #1587, #1588, #1589, #1594, #1598, #1600, #1602, #1604, #1615) - -### Bug Fixes - -- Fix incorrect request URL when installing resources from ADO (#1597 Thanks @anytonyoni!) -- Fix for swallowed exceptions (#1569) -- Fix for PSResourceGet not working in Constrained Language Mode (#1564) - -## 1.0.6 - -- Bump System.Text.Json to 8.0.5 - -## [1.0.5](https://github.com/PowerShell/PSResourceGet/compare/v1.0.4.1...v1.0.5) - 2024-05-13 - -### Bug Fixes -- Update `nuget.config` to use PowerShell packages feed (#1649) -- Refactor V2ServerAPICalls and NuGetServerAPICalls to use object-oriented query/filter builder (#1645 Thanks @sean-r-williams!) -- Fix unnecessary `and` for version globbing in V2ServerAPICalls (#1644 Thanks again @sean-r-williams!) -- Fix requiring `tags` in server response (#1627 Thanks @evelyn-bi!) -- Add 10 minute timeout to HTTPClient (#1626) -- Fix save script without `-IncludeXml` (#1609, #1614 Thanks @o-l-a-v!) -- PAT token fix to translate into HttpClient 'Basic Authorization'(#1599 Thanks @gerryleys!) -- Fix incorrect request url when installing from ADO (#1597 Thanks @antonyoni!) -- Improved exception handling (#1569) -- Ensure that .NET methods are not called in order to enable use in Constrained Language Mode (#1564) -- PSResourceGet packaging update - -## [1.0.4.1](https://github.com/PowerShell/PSResourceGet/compare/v1.0.4...v1.0.4.1) - 2024-04-05 - -- PSResourceGet packaging update - -## [1.0.4](https://github.com/PowerShell/PSResourceGet/compare/v1.0.3...v1.0.4) - 2024-04-05 - -### Patch - -- Dependency package updates - -## 1.0.3 - -### Bug Fixes -- Bug fix for null package version in `Install-PSResource` - -## 1.0.2 - -### Bug Fixes - -- Bug fix for `Update-PSResource` not updating from correct repository (#1549) -- Bug fix for creating temp home directory on Unix (#1544) -- Bug fix for creating `InstalledScriptInfos` directory when it does not exist (#1542) -- Bug fix for `Update-ModuleManifest` throwing null pointer exception (#1538) -- Bug fix for `name` property not populating in `PSResourceInfo` object when using `Find-PSResource` with JFrog Artifactory (#1535) -- Bug fix for incorrect configuration of requests to JFrog Artifactory v2 endpoints (#1533 Thanks @sean-r-williams!) -- Bug fix for determining JFrog Artifactory repositories (#1532 Thanks @sean-r-williams!) -- Bug fix for v2 server repositories incorrectly adding script endpoint (1526) -- Bug fixes for null references (#1525) -- Typo fixes in message prompts in `Install-PSResource` (#1510 Thanks @NextGData!) -- Bug fix to add `NormalizedVersion` property to `AdditionalMetadata` only when it exists (#1503 Thanks @sean-r-williams!) -- Bug fix to verify whether `Uri` is a UNC path and set respective `ApiVersion` (#1479 Thanks @kborowinski!) - -## 1.0.1 - -### Bug Fixes - -- Bugfix to update Unix local user installation paths to be compatible with .NET 7 and .NET 8 (#1464) -- Bugfix for Import-PSGetRepository in Windows PowerShell (#1460) -- Bugfix for `Test-PSScriptFileInfo`` to be less sensitive to whitespace (#1457) -- Bugfix to overwrite rels/rels directory on net472 when extracting nupkg to directory (#1456) -- Bugfix to add pipeline by property name support for Name and Repository properties for Find-PSResource (#1451 Thanks @ThomasNieto!) - -## 1.0.0 - -### New Features -- Add `ApiVersion` parameter for `Register-PSResourceRepository` (#1431) - -### Bug Fixes -- Automatically set the ApiVersion to v2 for repositories imported from PowerShellGet (#1430) -- Bug fix ADO v2 feed installation failures (#1429) -- Bug fix Artifactory v2 endpoint failures (#1428) -- Bug fix Artifactory v3 endpoint failures (#1427) -- Bug fix `-RequiredResource` silent failures (#1426) -- Bug fix for v2 repository returning extra packages for `-Tag` based search with `-Prerelease` (#1405) - See change log (CHANGELOG) at https://github.com/PowerShell/PSResourceGet '@ } From 0206a85ae1a5a5b1829d4e6035708583ca741dcf Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 6 Feb 2026 15:29:40 -0500 Subject: [PATCH 28/40] Package that depend on a specific version should search for dependency with NormalizedVersion (#1941) --- src/code/FindHelper.cs | 2 +- src/code/V2ServerAPICalls.cs | 14 +++++++++++++- .../InstallPSResourceV2Server.Tests.ps1 | 18 +++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 024623503..388be9090 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1174,7 +1174,7 @@ internal IEnumerable FindDependencyPackages( else if(dep.VersionRange.MaxVersion != null && dep.VersionRange.MinVersion != null && dep.VersionRange.MaxVersion.OriginalVersion.Equals(dep.VersionRange.MinVersion.OriginalVersion)) { string depPkgVersion = dep.VersionRange.MaxVersion.OriginalVersion; - FindResults responses = currentServer.FindVersion(dep.Name, version: dep.VersionRange.MaxVersion.OriginalVersion, _type, out ErrorRecord errRecord); + FindResults responses = currentServer.FindVersion(dep.Name, version: dep.VersionRange.MaxVersion.ToNormalizedString(), _type, out ErrorRecord errRecord); if (errRecord != null) { if (errRecord.Exception is ResourceNotFoundException) diff --git a/src/code/V2ServerAPICalls.cs b/src/code/V2ServerAPICalls.cs index 94d0b3a0b..ec3551f79 100644 --- a/src/code/V2ServerAPICalls.cs +++ b/src/code/V2ServerAPICalls.cs @@ -638,6 +638,17 @@ public override FindResults FindVersion(string packageName, string version, Reso // Quotations around package name and version do not matter, same metadata gets returned. // We need to explicitly add 'Id eq ' whenever $filter is used, otherwise arbitrary results are returned. + // version passed in must be a valid NuGet version + if (!NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) + { + errRecord = new ErrorRecord( + new ArgumentException($"Version '{version}' cannot be converted to a valid NuGet version."), + "InvalidVersionFormat", + ErrorCategory.InvalidArgument, + this); + return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); + } + var queryBuilder = new NuGetV2QueryBuilder(new Dictionary{ { "$inlinecount", "allpages" }, { "id", $"'{packageName}'" }, @@ -650,7 +661,8 @@ public override FindResults FindVersion(string packageName, string version, Reso filterBuilder.AddCriterion($"Id eq '{packageName}'"); } - filterBuilder.AddCriterion($"NormalizedVersion eq '{version}'"); + // a NormalizedVersion is required for the query filter + filterBuilder.AddCriterion($"NormalizedVersion eq '{nugetVersion.ToNormalizedString()}'"); if (type != ResourceType.None) { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } diff --git a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 index 852f5d3a3..ee35c3396 100644 --- a/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 @@ -32,7 +32,7 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { AfterEach { Uninstall-PSResource "test_module", "test_module2", "test_script", "TestModule99", "testModuleWithlicense", ` "TestFindModule", "ClobberTestModule1", "ClobberTestModule2", "PackageManagement", "TestTestScript", ` - "TestModuleWithDependency", "TestModuleWithPrereleaseDep", "PrereleaseModule", "test-nugetversion-parent", "test-nugetversion" -SkipDependencyCheck -ErrorAction SilentlyContinue + "TestModuleWithDependency", "TestModuleWithPrereleaseDep", "PrereleaseModule", "test-nugetversion-parent", "test-nugetversion", "test-pkg-normalized-dependency" -SkipDependencyCheck -ErrorAction SilentlyContinue } AfterAll { @@ -631,6 +631,22 @@ Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'CI' { $depRes.Name | Should -Be $depPkgName $depRes.Version | Should -Be $depPkgVer } + + It "Install resource that takes a dependency on package with specific version with differing normalized and semver versions" { + $moduleName = 'test-pkg-normalized-dependency' + $version = '3.9.2' + $depPkgName1 = "PowerShellGet" + $depPkgName2 = "PackageManagement" + + Install-PSResource -Name $moduleName -Prerelease -Repository $PSGalleryName -TrustRepository + $res = Get-InstalledPSResource $moduleName + $res.Name | Should -Be $moduleName + $res.Version | Should -Be $version + + $depRes = Get-InstalledPSResource $depPkgName1, $depPkgName2 + $depRes.Name | Should -Contain $depPkgName1 + $depRes.Name | Should -Contain $depPkgName2 + } } Describe 'Test Install-PSResource for V2 Server scenarios' -tags 'ManualValidationOnly' { From c2a8e18f118a8820b27834d76b08a935176b71ae Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 6 Feb 2026 15:38:21 -0500 Subject: [PATCH 29/40] Update version, changelog, release notes for 1.2.0-rc3 (#1942) --- CHANGELOG/preview.md | 5 +++++ src/Microsoft.PowerShell.PSResourceGet.psd1 | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index c319dbbb6..22d2e5e8e 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,10 @@ # Preview Changelog +## [1.2.0-rc3](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-rc2..v1.2.0-rc3) - 2026-02-06 + +## Bug fix +- Packages that depend on a specific version should search for the dependency with NormalizedVersion (#1941) + ## [1.2.0-rc2](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-rc1..v1.2.0-rc2) - 2026-02-05 ## Bug fix diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index e4737cb26..efacb8a3e 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -50,7 +50,7 @@ 'usres') PrivateData = @{ PSData = @{ - Prerelease = 'rc2' + Prerelease = 'rc3' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -60,6 +60,11 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 1.2.0-rc3 + +## Bug fix +- Packages that depend on a specific version should search for the dependency with NormalizedVersion (#1941) + ## 1.2.0-rc2 ## Bug fix From 73b90e3c8fffdaa13f641cb5a9ce8093330a1ee2 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Feb 2026 13:37:38 -0500 Subject: [PATCH 30/40] CodeQL: Ensure CodeQL scan is published to database (#1936) --- .pipelines/PSResourceGet-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 9dacd1a5e..a44d53651 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -111,7 +111,7 @@ extends: ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. inputs: Enabled: true - AnalyzeInPipeline: true + AnalyzeInPipeline: false Language: csharp # this is installing .NET From f4bd328a57397909bee459d36e0cb86ba4535463 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Mar 2026 17:07:20 -0400 Subject: [PATCH 31/40] Update changelog, release notes, version for v1.2.0 release (#1957) --- CHANGELOG/1.2.md | 4 ++++ global.json | 2 +- src/Microsoft.PowerShell.PSResourceGet.psd1 | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG/1.2.md diff --git a/CHANGELOG/1.2.md b/CHANGELOG/1.2.md new file mode 100644 index 000000000..35912468c --- /dev/null +++ b/CHANGELOG/1.2.md @@ -0,0 +1,4 @@ +# 1.2 Changelog + +## [1.2.0](https://github.com/PowerShell/PSResourceGet/compare/v1.2.0-rc3...v1.2.0) - 2026-03-10 + diff --git a/global.json b/global.json index 9289a72a0..40cb45844 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.417" + "version": "8.0.419" } } diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index efacb8a3e..17c341571 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -50,7 +50,7 @@ 'usres') PrivateData = @{ PSData = @{ - Prerelease = 'rc3' + # Prerelease = '' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -60,6 +60,8 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 1.2.0 + ## 1.2.0-rc3 ## Bug fix From 70957639a04358f4cda1cabbc530ad01db4e7281 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Mar 2026 22:28:16 +0000 Subject: [PATCH 32/40] Merged PR 38899: Fix signing for .nupkg Fix signing for .nupkg, defining ADO variable ---- #### AI description (iteration 1) #### PR Classification Bug fix to resolve issues with signing .nupkg packages in the pipeline. #### PR Summary This pull request adjusts the pipeline steps to ensure the correct directory path is used for signing the .nupkg, while adding debugging steps to verify the directory contents before and after signing. - `/pipelines/PSResourceGet-Official.yml`: Introduces a `publishPath` variable using `Join-Path` to reliably point to the `PublishedNupkg` directory. - `/pipelines/PSResourceGet-Official.yml`: Updates registration, signing, and directory navigation steps to use `publishPath` instead of hardcoded paths, and adds commands to output folder contents for debugging. --- .pipelines/PSResourceGet-Official.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index a44d53651..9728e5b8a 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -234,25 +234,34 @@ extends: Import-Module -Name Microsoft.PowerShell.PSResourceGet -Force Set-Location "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" - $null = New-Item -ItemType Directory -Path "$(signOutPath)\PublishedNupkg" -Force + $publishPath = Join-Path $(signOutPath) -ChildPath 'PublishedNupkg' - Register-PSResourceRepository -Name 'localRepo' -Uri "$(signOutPath)\PublishedNupkg" + $null = New-Item -ItemType Directory -Path $publishPath -Force + + Register-PSResourceRepository -Name 'localRepo' -Uri $publishPath Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose + Write-Output "##vso[task.setvariable variable=publishPath;isOutput=true]$publishPath" displayName: Create nupkg for publishing + - pwsh: | + Set-Location '$(publishPath)' + Write-Host "Contents of signOutPath:" + Get-ChildItem '$(publishPath)' -Recurse + displayName: Find Nupkg Pre Signing + - task: onebranch.pipeline.signing@1 displayName: Sign nupkg inputs: command: 'sign' signing_profile: external_distribution files_to_sign: '**\*.nupkg' - search_root: "$(signOutPath)\PublishedNupkg" + search_root: '$(publishPath)' - pwsh: | - Set-Location "$(signOutPath)\PublishedNupkg" + Set-Location '$(publishPath)' Write-Host "Contents of signOutPath:" - Get-ChildItem "$(signOutPath)" -Recurse - displayName: Find Nupkg + Get-ChildItem '$(publishPath)' -Recurse + displayName: Find Nupkg Post Signing - task: CopyFiles@2 displayName: "Copy nupkg to ob_outputDirectory - '$(ob_outputDirectory)'" From 63b258a9e162c6b45977500ec4cbf4563dd67e8b Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Mar 2026 23:02:24 +0000 Subject: [PATCH 33/40] Merged PR 38901: Remove isOutput on variable being set and update publishPath var reference Remove isOutput on variable being set and update publishPath var reference ---- #### AI description (iteration 1) #### PR Classification This pull request is a pipeline fix and code cleanup, adjusting variable setting and reference for improved consistency. #### PR Summary The changes remove the "isOutput=true" flag when setting the "publishPath" variable and update the file copy step to correctly reference the "publishPath". - `/.pipelines/PSResourceGet-Official.yml`: Removed the "isOutput=true" from the variable setting command. - `/.pipelines/PSResourceGet-Official.yml`: Updated the file copy task to use `publishPath` instead of `signOutPath` for selecting the published package. --- .pipelines/PSResourceGet-Official.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 9728e5b8a..8558e7d9a 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -240,7 +240,7 @@ extends: Register-PSResourceRepository -Name 'localRepo' -Uri $publishPath Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose - Write-Output "##vso[task.setvariable variable=publishPath;isOutput=true]$publishPath" + Write-Output "##vso[task.setvariable variable=publishPath]$publishPath" displayName: Create nupkg for publishing - pwsh: | @@ -266,7 +266,7 @@ extends: - task: CopyFiles@2 displayName: "Copy nupkg to ob_outputDirectory - '$(ob_outputDirectory)'" inputs: - Contents: $(signOutPath)\PublishedNupkg\Microsoft.PowerShell.PSResourceGet.*.nupkg + Contents: $(publishPath)\Microsoft.PowerShell.PSResourceGet.*.nupkg TargetFolder: $(ob_outputDirectory) - pwsh: | From 9289da13a78a05b08c53756194816cf79d4584c6 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 11 Mar 2026 17:47:11 +0000 Subject: [PATCH 34/40] Merged PR 38916: Add ob_restore_phase to steps in packaging job Add ob_restore_phase to steps in packaging job --- .pipelines/PSResourceGet-Official.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 8558e7d9a..e4ea3ba1e 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -209,6 +209,8 @@ extends: type: windows steps: - checkout: self + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | if (-not (Test-Path $(repoRoot)/.config/tsaoptions.json)) { @@ -216,18 +218,24 @@ extends: throw "tsaoptions.json does not exist under $(repoRoot)/.config" } displayName: Test if tsaoptions.json exists + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - task: DownloadPipelineArtifact@2 displayName: 'Download build files' inputs: targetPath: $(signOutPath) artifact: drop_stagebuild_jobbuild + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | Set-Location "$(signOutPath)" Write-Host "Contents of signOutPath:" Get-ChildItem $(signOutPath) -Recurse displayName: Capture artifacts directory structure + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | # This need to be done before set-location so the module from PSHome is loaded @@ -242,12 +250,16 @@ extends: Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose Write-Output "##vso[task.setvariable variable=publishPath]$publishPath" displayName: Create nupkg for publishing + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | Set-Location '$(publishPath)' Write-Host "Contents of signOutPath:" Get-ChildItem '$(publishPath)' -Recurse displayName: Find Nupkg Pre Signing + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - task: onebranch.pipeline.signing@1 displayName: Sign nupkg From c8904281051651e27a827079fce9483b8fea3d76 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Mar 2026 22:28:16 +0000 Subject: [PATCH 35/40] Merged PR 38899: Fix signing for .nupkg Fix signing for .nupkg, defining ADO variable ---- #### AI description (iteration 1) #### PR Classification Bug fix to resolve issues with signing .nupkg packages in the pipeline. #### PR Summary This pull request adjusts the pipeline steps to ensure the correct directory path is used for signing the .nupkg, while adding debugging steps to verify the directory contents before and after signing. - `/pipelines/PSResourceGet-Official.yml`: Introduces a `publishPath` variable using `Join-Path` to reliably point to the `PublishedNupkg` directory. - `/pipelines/PSResourceGet-Official.yml`: Updates registration, signing, and directory navigation steps to use `publishPath` instead of hardcoded paths, and adds commands to output folder contents for debugging. --- .pipelines/PSResourceGet-Official.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index a44d53651..9728e5b8a 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -234,25 +234,34 @@ extends: Import-Module -Name Microsoft.PowerShell.PSResourceGet -Force Set-Location "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" - $null = New-Item -ItemType Directory -Path "$(signOutPath)\PublishedNupkg" -Force + $publishPath = Join-Path $(signOutPath) -ChildPath 'PublishedNupkg' - Register-PSResourceRepository -Name 'localRepo' -Uri "$(signOutPath)\PublishedNupkg" + $null = New-Item -ItemType Directory -Path $publishPath -Force + + Register-PSResourceRepository -Name 'localRepo' -Uri $publishPath Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose + Write-Output "##vso[task.setvariable variable=publishPath;isOutput=true]$publishPath" displayName: Create nupkg for publishing + - pwsh: | + Set-Location '$(publishPath)' + Write-Host "Contents of signOutPath:" + Get-ChildItem '$(publishPath)' -Recurse + displayName: Find Nupkg Pre Signing + - task: onebranch.pipeline.signing@1 displayName: Sign nupkg inputs: command: 'sign' signing_profile: external_distribution files_to_sign: '**\*.nupkg' - search_root: "$(signOutPath)\PublishedNupkg" + search_root: '$(publishPath)' - pwsh: | - Set-Location "$(signOutPath)\PublishedNupkg" + Set-Location '$(publishPath)' Write-Host "Contents of signOutPath:" - Get-ChildItem "$(signOutPath)" -Recurse - displayName: Find Nupkg + Get-ChildItem '$(publishPath)' -Recurse + displayName: Find Nupkg Post Signing - task: CopyFiles@2 displayName: "Copy nupkg to ob_outputDirectory - '$(ob_outputDirectory)'" From be743d53997cf508af09a22f0c291c3f140389f7 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Mar 2026 23:02:24 +0000 Subject: [PATCH 36/40] Merged PR 38901: Remove isOutput on variable being set and update publishPath var reference Remove isOutput on variable being set and update publishPath var reference ---- #### AI description (iteration 1) #### PR Classification This pull request is a pipeline fix and code cleanup, adjusting variable setting and reference for improved consistency. #### PR Summary The changes remove the "isOutput=true" flag when setting the "publishPath" variable and update the file copy step to correctly reference the "publishPath". - `/.pipelines/PSResourceGet-Official.yml`: Removed the "isOutput=true" from the variable setting command. - `/.pipelines/PSResourceGet-Official.yml`: Updated the file copy task to use `publishPath` instead of `signOutPath` for selecting the published package. --- .pipelines/PSResourceGet-Official.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 9728e5b8a..8558e7d9a 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -240,7 +240,7 @@ extends: Register-PSResourceRepository -Name 'localRepo' -Uri $publishPath Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose - Write-Output "##vso[task.setvariable variable=publishPath;isOutput=true]$publishPath" + Write-Output "##vso[task.setvariable variable=publishPath]$publishPath" displayName: Create nupkg for publishing - pwsh: | @@ -266,7 +266,7 @@ extends: - task: CopyFiles@2 displayName: "Copy nupkg to ob_outputDirectory - '$(ob_outputDirectory)'" inputs: - Contents: $(signOutPath)\PublishedNupkg\Microsoft.PowerShell.PSResourceGet.*.nupkg + Contents: $(publishPath)\Microsoft.PowerShell.PSResourceGet.*.nupkg TargetFolder: $(ob_outputDirectory) - pwsh: | From 4558c310d0bb60d4ff8b79cabe06ef72b0354e69 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 11 Mar 2026 17:47:11 +0000 Subject: [PATCH 37/40] Merged PR 38916: Add ob_restore_phase to steps in packaging job Add ob_restore_phase to steps in packaging job --- .pipelines/PSResourceGet-Official.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 8558e7d9a..e4ea3ba1e 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -209,6 +209,8 @@ extends: type: windows steps: - checkout: self + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | if (-not (Test-Path $(repoRoot)/.config/tsaoptions.json)) { @@ -216,18 +218,24 @@ extends: throw "tsaoptions.json does not exist under $(repoRoot)/.config" } displayName: Test if tsaoptions.json exists + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - task: DownloadPipelineArtifact@2 displayName: 'Download build files' inputs: targetPath: $(signOutPath) artifact: drop_stagebuild_jobbuild + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | Set-Location "$(signOutPath)" Write-Host "Contents of signOutPath:" Get-ChildItem $(signOutPath) -Recurse displayName: Capture artifacts directory structure + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | # This need to be done before set-location so the module from PSHome is loaded @@ -242,12 +250,16 @@ extends: Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose Write-Output "##vso[task.setvariable variable=publishPath]$publishPath" displayName: Create nupkg for publishing + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | Set-Location '$(publishPath)' Write-Host "Contents of signOutPath:" Get-ChildItem '$(publishPath)' -Recurse displayName: Find Nupkg Pre Signing + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - task: onebranch.pipeline.signing@1 displayName: Sign nupkg From 7f7dff040ead7fc8019f0bdeab111c7be1e3c1a0 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 11 Mar 2026 16:13:03 -0400 Subject: [PATCH 38/40] Revert "Merged PR 38916: Add ob_restore_phase to steps in packaging job" This reverts commit 4558c310d0bb60d4ff8b79cabe06ef72b0354e69. --- .pipelines/PSResourceGet-Official.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index e4ea3ba1e..8558e7d9a 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -209,8 +209,6 @@ extends: type: windows steps: - checkout: self - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | if (-not (Test-Path $(repoRoot)/.config/tsaoptions.json)) { @@ -218,24 +216,18 @@ extends: throw "tsaoptions.json does not exist under $(repoRoot)/.config" } displayName: Test if tsaoptions.json exists - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - task: DownloadPipelineArtifact@2 displayName: 'Download build files' inputs: targetPath: $(signOutPath) artifact: drop_stagebuild_jobbuild - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | Set-Location "$(signOutPath)" Write-Host "Contents of signOutPath:" Get-ChildItem $(signOutPath) -Recurse displayName: Capture artifacts directory structure - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | # This need to be done before set-location so the module from PSHome is loaded @@ -250,16 +242,12 @@ extends: Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose Write-Output "##vso[task.setvariable variable=publishPath]$publishPath" displayName: Create nupkg for publishing - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - pwsh: | Set-Location '$(publishPath)' Write-Host "Contents of signOutPath:" Get-ChildItem '$(publishPath)' -Recurse displayName: Find Nupkg Pre Signing - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - task: onebranch.pipeline.signing@1 displayName: Sign nupkg From 63e27a7415cfe5f2db7f19566e87ac33e1cc641a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 11 Mar 2026 16:13:03 -0400 Subject: [PATCH 39/40] Revert "Merged PR 38901: Remove isOutput on variable being set and update publishPath var reference" This reverts commit be743d53997cf508af09a22f0c291c3f140389f7. --- .pipelines/PSResourceGet-Official.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 8558e7d9a..9728e5b8a 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -240,7 +240,7 @@ extends: Register-PSResourceRepository -Name 'localRepo' -Uri $publishPath Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose - Write-Output "##vso[task.setvariable variable=publishPath]$publishPath" + Write-Output "##vso[task.setvariable variable=publishPath;isOutput=true]$publishPath" displayName: Create nupkg for publishing - pwsh: | @@ -266,7 +266,7 @@ extends: - task: CopyFiles@2 displayName: "Copy nupkg to ob_outputDirectory - '$(ob_outputDirectory)'" inputs: - Contents: $(publishPath)\Microsoft.PowerShell.PSResourceGet.*.nupkg + Contents: $(signOutPath)\PublishedNupkg\Microsoft.PowerShell.PSResourceGet.*.nupkg TargetFolder: $(ob_outputDirectory) - pwsh: | From 75dc87267270565e04a9b7a7aa98426f010e2ae3 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 11 Mar 2026 16:13:03 -0400 Subject: [PATCH 40/40] Revert "Merged PR 38899: Fix signing for .nupkg" This reverts commit c8904281051651e27a827079fce9483b8fea3d76. --- .pipelines/PSResourceGet-Official.yml | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/.pipelines/PSResourceGet-Official.yml b/.pipelines/PSResourceGet-Official.yml index 9728e5b8a..a44d53651 100644 --- a/.pipelines/PSResourceGet-Official.yml +++ b/.pipelines/PSResourceGet-Official.yml @@ -234,34 +234,25 @@ extends: Import-Module -Name Microsoft.PowerShell.PSResourceGet -Force Set-Location "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" - $publishPath = Join-Path $(signOutPath) -ChildPath 'PublishedNupkg' + $null = New-Item -ItemType Directory -Path "$(signOutPath)\PublishedNupkg" -Force - $null = New-Item -ItemType Directory -Path $publishPath -Force - - Register-PSResourceRepository -Name 'localRepo' -Uri $publishPath + Register-PSResourceRepository -Name 'localRepo' -Uri "$(signOutPath)\PublishedNupkg" Publish-PSResource -Path "$(signOutPath)\Microsoft.PowerShell.PSResourceGet" -Repository 'localRepo' -Verbose - Write-Output "##vso[task.setvariable variable=publishPath;isOutput=true]$publishPath" displayName: Create nupkg for publishing - - pwsh: | - Set-Location '$(publishPath)' - Write-Host "Contents of signOutPath:" - Get-ChildItem '$(publishPath)' -Recurse - displayName: Find Nupkg Pre Signing - - task: onebranch.pipeline.signing@1 displayName: Sign nupkg inputs: command: 'sign' signing_profile: external_distribution files_to_sign: '**\*.nupkg' - search_root: '$(publishPath)' + search_root: "$(signOutPath)\PublishedNupkg" - pwsh: | - Set-Location '$(publishPath)' + Set-Location "$(signOutPath)\PublishedNupkg" Write-Host "Contents of signOutPath:" - Get-ChildItem '$(publishPath)' -Recurse - displayName: Find Nupkg Post Signing + Get-ChildItem "$(signOutPath)" -Recurse + displayName: Find Nupkg - task: CopyFiles@2 displayName: "Copy nupkg to ob_outputDirectory - '$(ob_outputDirectory)'"