From c07e93c215884582fba3a86c36bd395adc40cd4b Mon Sep 17 00:00:00 2001 From: "G.Reijn" <26114636+Gijsreyn@users.noreply.github.com> Date: Sat, 23 May 2026 12:25:13 +0200 Subject: [PATCH 1/4] fix(psresourcelist): Get operation filters out resources on installed version --- src/dsc/psresourceget.ps1 | 32 ++++++------- .../PSResourceGetDSCResource.Tests.ps1 | 46 +++++++++++++++++++ 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/dsc/psresourceget.ps1 b/src/dsc/psresourceget.ps1 index f6f9eb50d..f297fcccb 100644 --- a/src/dsc/psresourceget.ps1 +++ b/src/dsc/psresourceget.ps1 @@ -344,26 +344,20 @@ function GetPSResourceList { $resourcesExist = @() - foreach ($resource in $allPSResources) { - foreach ($inputResource in $inputResources) { - if ($resource.Name -eq $inputResource.Name) { - Write-Trace -message "Found matching resource for input: $($inputResource.Name). Checking version constraints. Input version: $($inputResource.Version), Resource version: $($resource.Version)" -level debug - if ($inputResource.Version) { - # Use the NuGet.Versioning package if available, otherwise do a simple comparison - try { - if (SatisfiesVersion -version $resource.Version -versionRange $inputResource.Version) { - $resourcesExist += $resource - } - } - catch { - Write-Trace -message "Error checking version constraints for resource: $($inputResource.Name). Error details: $($_.Exception.Message)" -level debug - # Fallback: simple string comparison (not full NuGet range support) - if ($resource.Version.ToString() -eq $inputResource.Version) { - $resourcesExist += $resource - } - } - } + foreach ($inputResource in $inputResources) { + $matchingResources = $allPSResources | Where-Object { $_.Name -eq $inputResource.Name } + + if ($matchingResources) { + # Prefer a version that satisfies the requested range; fall back to any installed version + $preferred = if ($inputResource.Version) { + $matchingResources | Where-Object { + try { SatisfiesVersion -version $_.Version -versionRange $inputResource.Version } catch { $false } + } | Select-Object -First 1 } + + $toAdd = if ($preferred) { $preferred } else { $matchingResources | Select-Object -First 1 } + Write-Trace -message "Found matching resource for input: $($inputResource.Name). Returning version: $($toAdd.Version)" -level debug + $resourcesExist += $toAdd } } diff --git a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 index ce320dc62..5b7477d5f 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -285,6 +285,52 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { $testResult = & $script:dscExe resource test --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $resourceInput -o json | ConvertFrom-Json $testResult.inDesiredState | Should -BeFalse } + + It 'Get returns actual installed version when installed version does not satisfy requested version' { + # Install 1.0.0 but request 5.0.0 - get should return the actual installed version (1.0.0) + Install-PSResource -Name $script:testModuleName -Version '1.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue + Uninstall-PSResource -Name $script:testModuleName -Version '5.0.0' -ErrorAction SilentlyContinue + + $psResourceListParams = @{ + repositoryName = $script:localRepo + resources = @( + @{ + name = $script:testModuleName + version = '5.0.0' + } + ) + } + + $resourceInput = $psResourceListParams | ConvertTo-Json -Depth 5 + $getResult = & $script:dscExe resource get --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $resourceInput -o json | ConvertFrom-Json + $getResult.actualState.resources.Count | Should -Be 1 + $getResult.actualState.resources[0].name | Should -BeExactly $script:testModuleName + $getResult.actualState.resources[0].version | Should -BeExactly '1.0.0' + $getResult.actualState.resources[0]._exist | Should -BeTrue + } + + It 'Get prefers installed version that satisfies requested version range when multiple versions are installed' { + # Install both 1.0.0 and 5.0.0 but request 5.0.0 - get should prefer the satisfying version (5.0.0) + Install-PSResource -Name $script:testModuleName -Version '1.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue + Install-PSResource -Name $script:testModuleName -Version '5.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue + + $psResourceListParams = @{ + repositoryName = $script:localRepo + resources = @( + @{ + name = $script:testModuleName + version = '5.0.0' + } + ) + } + + $resourceInput = $psResourceListParams | ConvertTo-Json -Depth 5 + $getResult = & $script:dscExe resource get --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $resourceInput -o json | ConvertFrom-Json + $getResult.actualState.resources.Count | Should -Be 1 + $getResult.actualState.resources[0].name | Should -BeExactly $script:testModuleName + $getResult.actualState.resources[0].version | Should -BeExactly '5.0.0' + $getResult.actualState.resources[0]._exist | Should -BeTrue + } } Describe 'E2E tests for Repository resource' -Tags 'CI' { From 55aeed7b9e9e9b94730eee56fbab5d2bf749ebc0 Mon Sep 17 00:00:00 2001 From: "G.Reijn" <26114636+Gijsreyn@users.noreply.github.com> Date: Sun, 24 May 2026 13:15:10 +0200 Subject: [PATCH 2/4] Return original code with other fix --- src/dsc/psresourceget.ps1 | 50 +++++++++++++------ .../PSResourceGetDSCResource.Tests.ps1 | 7 +-- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/dsc/psresourceget.ps1 b/src/dsc/psresourceget.ps1 index f297fcccb..c1225c647 100644 --- a/src/dsc/psresourceget.ps1 +++ b/src/dsc/psresourceget.ps1 @@ -342,27 +342,38 @@ function GetPSResourceList { ) } - $resourcesExist = @() + $resolvedResources = @() foreach ($inputResource in $inputResources) { $matchingResources = $allPSResources | Where-Object { $_.Name -eq $inputResource.Name } if ($matchingResources) { - # Prefer a version that satisfies the requested range; fall back to any installed version - $preferred = if ($inputResource.Version) { - $matchingResources | Where-Object { + $preferred = $null + if ($inputResource.Version) { + $preferred = $matchingResources | Where-Object { try { SatisfiesVersion -version $_.Version -versionRange $inputResource.Version } catch { $false } } | Select-Object -First 1 + } else { + $preferred = $matchingResources | Select-Object -First 1 } - $toAdd = if ($preferred) { $preferred } else { $matchingResources | Select-Object -First 1 } - Write-Trace -message "Found matching resource for input: $($inputResource.Name). Returning version: $($toAdd.Version)" -level debug - $resourcesExist += $toAdd + if ($preferred) { + Write-Trace -message "Resource '$($inputResource.Name)' version '$($preferred.Version)' satisfies requested range '$($inputResource.Version)'." -level debug + $resolvedResources += $preferred + } else { + # Installed but doesn't satisfy the version range - report actual installed version with _exist = false + $fallback = $matchingResources | Select-Object -First 1 + Write-Trace -message "Resource '$($inputResource.Name)' installed at '$($fallback.Version)' does not satisfy requested range '$($inputResource.Version)'. Reporting _exist = false." -level debug + $fallback._exist = $false + $resolvedResources += $fallback + } + } else { + Write-Trace -message "Resource '$($inputResource.Name)' is not installed. Reporting _exist = false." -level debug + $resolvedResources += [PSResource]::new($inputResource.Name) } } - ## For get operation we only need the first resource that exists, which is always the latest for currentUser - PopulatePSResourceListObjectByRepository -resourcesExist $resourcesExist -inputResources $inputResources -repositoryName $inputPSResourceList.RepositoryName -trustedRepository $inputPSResourceList.trustedRepository + PopulatePSResourceListObjectByRepository -resourcesExist $resolvedResources -inputResources $inputResources -repositoryName $inputPSResourceList.RepositoryName -trustedRepository $inputPSResourceList.trustedRepository } function GetOperation { @@ -753,13 +764,20 @@ function PopulatePSResourceListObjectByRepository { } else { $resources += $resourcesExist | ForEach-Object { - [PSResource]::new( - $_.Name, - $_.Version.PreRelease ? $_.Version.ToString() + "-" + $_.PreRelease : $_.Version.ToString(), - $_.Scope, - $_.RepositoryName, - $_.PreRelease ? $true : $false - ) + $srcExist = $_._exist + $r = if ($_.version) { + [PSResource]::new( + $_.Name, + $_.Version.ToString(), + $_.Scope, + $_.RepositoryName, + $_.PreRelease ? $true : $false + ) + } else { + [PSResource]::new($_.Name) + } + $r._exist = $srcExist + $r } } diff --git a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 index 5b7477d5f..cca77a799 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -286,8 +286,9 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { $testResult.inDesiredState | Should -BeFalse } - It 'Get returns actual installed version when installed version does not satisfy requested version' { - # Install 1.0.0 but request 5.0.0 - get should return the actual installed version (1.0.0) + It 'Get returns actual installed version with _exist false when installed version does not satisfy requested version' { + # Install 1.0.0 but request 5.0.0 - get should report _exist = false (requested version absent) + # but still surface the actually installed version (1.0.0) Install-PSResource -Name $script:testModuleName -Version '1.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue Uninstall-PSResource -Name $script:testModuleName -Version '5.0.0' -ErrorAction SilentlyContinue @@ -306,7 +307,7 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { $getResult.actualState.resources.Count | Should -Be 1 $getResult.actualState.resources[0].name | Should -BeExactly $script:testModuleName $getResult.actualState.resources[0].version | Should -BeExactly '1.0.0' - $getResult.actualState.resources[0]._exist | Should -BeTrue + $getResult.actualState.resources[0]._exist | Should -BeFalse } It 'Get prefers installed version that satisfies requested version range when multiple versions are installed' { From 5707c9e00c669ae863d1a1d741298c53644c2228 Mon Sep 17 00:00:00 2001 From: "G.Reijn" <26114636+Gijsreyn@users.noreply.github.com> Date: Sat, 12 Sep 2026 01:23:11 +0200 Subject: [PATCH 3/4] Fix test --- .../PSResourceGetDSCResource.Tests.ps1 | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 index cca77a799..74affbd8c 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -167,6 +167,16 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { SetupTestRepos } AfterAll { + # Remove test modules installed through DSC so they do not leak into later runs. + foreach ($moduleToRemove in @($script:testModuleName, $script:testModuleName2)) { + $cleanupInput = @{ + repositoryName = $script:localRepo + trustedRepository = $true + resources = @(@{ name = $moduleToRemove; _exist = $false }) + } | ConvertTo-Json -Depth 5 + $null = & $script:dscExe resource set --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $cleanupInput -o json 2>&1 + } + # Clean up the test repository Get-RevertPSResourceRepositoryFile } @@ -288,9 +298,19 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { It 'Get returns actual installed version with _exist false when installed version does not satisfy requested version' { # Install 1.0.0 but request 5.0.0 - get should report _exist = false (requested version absent) - # but still surface the actually installed version (1.0.0) - Install-PSResource -Name $script:testModuleName -Version '1.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue - Uninstall-PSResource -Name $script:testModuleName -Version '5.0.0' -ErrorAction SilentlyContinue + $removeAllInput = @{ + repositoryName = $script:localRepo + trustedRepository = $true + resources = @(@{ name = $script:testModuleName; _exist = $false }) + } | ConvertTo-Json -Depth 5 + $null = & $script:dscExe resource set --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $removeAllInput -o json + + $installOldInput = @{ + repositoryName = $script:localRepo + trustedRepository = $true + resources = @(@{ name = $script:testModuleName; version = '1.0.0' }) + } | ConvertTo-Json -Depth 5 + $null = & $script:dscExe resource set --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $installOldInput -o json $psResourceListParams = @{ repositoryName = $script:localRepo @@ -311,9 +331,16 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { } It 'Get prefers installed version that satisfies requested version range when multiple versions are installed' { - # Install both 1.0.0 and 5.0.0 but request 5.0.0 - get should prefer the satisfying version (5.0.0) - Install-PSResource -Name $script:testModuleName -Version '1.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue - Install-PSResource -Name $script:testModuleName -Version '5.0.0' -Repository $script:localRepo -Reinstall -TrustRepository -ErrorAction SilentlyContinue + # Install both 1.0.0 and 5.0.0 but request 5.0.0 - get should prefer the satisfying version (5.0.0). + # Setup goes through DSC for the same reason as the previous test. + foreach ($setupVersion in @('1.0.0', '5.0.0')) { + $installInput = @{ + repositoryName = $script:localRepo + trustedRepository = $true + resources = @(@{ name = $script:testModuleName; version = $setupVersion }) + } | ConvertTo-Json -Depth 5 + $null = & $script:dscExe resource set --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $installInput -o json + } $psResourceListParams = @{ repositoryName = $script:localRepo From c83c04d56599fc3e9ee641041bb9ae367979b9f5 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 15 Sep 2026 12:14:11 -0700 Subject: [PATCH 4/4] Fix merge issue --- test/DscResource/PSResourceGetDSCResource.Tests.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 index 50212d394..234a0fa71 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -220,7 +220,7 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { $PSDefaultParameterValues = $originalDefaultParameterValues return } - + # Remove test modules installed through DSC so they do not leak into later runs. foreach ($moduleToRemove in @($script:testModuleName, $script:testModuleName2)) { $cleanupInput = @{ @@ -228,7 +228,8 @@ Describe "PSResourceList Resource Tests" -Tags 'CI' { trustedRepository = $true resources = @(@{ name = $moduleToRemove; _exist = $false }) } | ConvertTo-Json -Depth 5 - $null = & $script:dscExe resource set --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $cleanupInput -o json 2>&1 + $null = & $script:dscExe resource set --resource Microsoft.PowerShell.PSResourceGet/PSResourceList --input $cleanupInput -o json 2>&1 + } # Clean up the test repository Get-RevertPSResourceRepositoryFile