From 7000fd8f24e65fca107c58739dd26553a02500cc Mon Sep 17 00:00:00 2001 From: "G.Reijn" <26114636+Gijsreyn@users.noreply.github.com> Date: Sun, 24 May 2026 09:05:34 +0200 Subject: [PATCH 1/3] fix(Repository:) Add input validation for GetOperation --- src/dsc/psresourceget.ps1 | 5 +++++ test/DscResource/PSResourceGetDSCResource.Tests.ps1 | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/dsc/psresourceget.ps1 b/src/dsc/psresourceget.ps1 index f6f9eb50d..8bc880f28 100644 --- a/src/dsc/psresourceget.ps1 +++ b/src/dsc/psresourceget.ps1 @@ -376,6 +376,11 @@ function GetOperation { [string]$ResourceType ) + if ([string]::IsNullOrEmpty($stdinput)) { + Write-Trace -level error -message "Get operation requires --input with the resource properties. No input was provided." + exit [ExitCode]::Error + } + $inputObj = $stdinput | ConvertFrom-Json -ErrorAction Stop Write-Trace -message "Starting Get operation for ResourceType: $ResourceType" -level trace diff --git a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 index ce320dc62..a278ac748 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -142,6 +142,12 @@ Describe 'Repository Resource Tests' -Tags 'CI' { } } + It 'Get operation without --input exits with a non-zero code and does not produce an unhandled exception' { + $output = & $script:dscExe resource get --resource Microsoft.PowerShell.PSResourceGet/Repository -o json 2>&1 + $LASTEXITCODE | Should -Not -Be 0 + ($output | Out-String) | Should -Not -Match 'Cannot bind argument to parameter' + } + It 'Can delete a Repository resource instance' { # First, create a repository to delete Register-PSResourceRepository -Name 'TestRepoToDelete' -uri 'https://www.doesnotexist.com' -ErrorAction SilentlyContinue -APIVersion Local From 9d06224e9dcbb599bd24f2d2e5ceaf022932624e Mon Sep 17 00:00:00 2001 From: "G.Reijn" <26114636+Gijsreyn@users.noreply.github.com> Date: Sun, 24 May 2026 13:07:24 +0200 Subject: [PATCH 2/3] Update test --- test/DscResource/PSResourceGetDSCResource.Tests.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 index a278ac748..3fd5af70a 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -144,8 +144,12 @@ Describe 'Repository Resource Tests' -Tags 'CI' { It 'Get operation without --input exits with a non-zero code and does not produce an unhandled exception' { $output = & $script:dscExe resource get --resource Microsoft.PowerShell.PSResourceGet/Repository -o json 2>&1 + $outputText = $output | Out-String $LASTEXITCODE | Should -Not -Be 0 - ($output | Out-String) | Should -Not -Match 'Cannot bind argument to parameter' + $outputText | Should -Match '--input' + $outputText | Should -Match 'required' + $outputText | Should -Not -Match 'Cannot bind argument to parameter' + $outputText | Should -Not -Match 'Unhandled exception' } It 'Can delete a Repository resource instance' { From cdc55ff7ccd0c998b93bcb65ad04727d37d33dbe Mon Sep 17 00:00:00 2001 From: "G.Reijn" <26114636+Gijsreyn@users.noreply.github.com> Date: Fri, 11 Sep 2026 06:01:49 +0200 Subject: [PATCH 3/3] Dispose lock --- src/code/InstallHelper.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index c89ef0ee9..11600f472 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -815,8 +815,9 @@ private ConcurrentDictionary BeginPackageInstall( return InstallParentAndDependencyPackages(parentAndDeps, currentServer, tempInstallPath, packagesHash, updatedPackagesHash, pkgToInstall); } else { - // If we don't install dependencies, we're only installing the parent pkg so we can short circut and simply install the parent pkg. - Stream responseStream = currentServer.InstallPackage(pkgToInstall.Name, pkgVersion, true, out ErrorRecord installNameErrRecord); + // If we don't install dependencies, we're only installing the parent pkg so we can short circut and simply install the parent pkg. + // Dispose the stream once done: for local repositories this is a FileStream on the repository's .nupkg and leaving it open locks the file. + using Stream responseStream = currentServer.InstallPackage(pkgToInstall.Name, pkgVersion, true, out ErrorRecord installNameErrRecord); if (installNameErrRecord != null) { @@ -868,7 +869,7 @@ private ConcurrentDictionary InstallParentAndDependencyPackag verboseMsgs.Enqueue($"Installing package '{depPkgName}' version '{depPkgVersion}'"); //Stream responseStream = currentServer.InstallPackage(depPkgName, depPkgVersion, true, out ErrorRecord installNameErrRecord); // add async - Stream responseStream = currentServer.InstallPackageAsync(depPkgName, depPkgVersion, true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); + using Stream responseStream = currentServer.InstallPackageAsync(depPkgName, depPkgVersion, true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); if (errorMsgs.Count > 0) { @@ -906,7 +907,7 @@ private ConcurrentDictionary InstallParentAndDependencyPackag { var pkgToInstallName = pkgToBeInstalled.Name; var pkgToInstallVersion = Utils.GetFullVersionString(pkgToBeInstalled.Version.ToString(), pkgToBeInstalled.Prerelease); - Stream responseStream = currentServer.InstallPackage(pkgToInstallName, pkgToInstallVersion, true, out ErrorRecord installNameErrRecord); + using Stream responseStream = currentServer.InstallPackage(pkgToInstallName, pkgToInstallVersion, true, out ErrorRecord installNameErrRecord); if (installNameErrRecord != null) {