diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 4e13b4b5f..50ecfb54e 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -883,7 +883,8 @@ 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(); + // 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.InstallPackageAsync(depPkgName, depPkgVersion, true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); if (!errorMsgs.IsEmpty) { @@ -921,7 +922,8 @@ private ConcurrentDictionary InstallParentAndDependencyPackag var pkgToInstallName = pkgToBeInstalled.Name; var pkgToInstallVersion = Utils.GetFullVersionString(pkgToBeInstalled.Version.ToString(), pkgToBeInstalled.Prerelease); // Runs on worker threads when parent installs are parallelized; use the async overload to avoid cross-thread cmdlet stream writes. - Stream responseStream = currentServer.InstallPackageAsync(pkgToInstallName, pkgToInstallVersion, true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); + // 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.InstallPackageAsync(pkgToInstallName, pkgToInstallVersion, true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); if (!errorMsgs.IsEmpty) { diff --git a/src/dsc/psresourceget.ps1 b/src/dsc/psresourceget.ps1 index ea452d522..5415ad7e0 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 f6fcf150f..2ca23b525 100644 --- a/test/DscResource/PSResourceGetDSCResource.Tests.ps1 +++ b/test/DscResource/PSResourceGetDSCResource.Tests.ps1 @@ -142,6 +142,16 @@ 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 + $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' { # First, create a repository to delete Register-PSResourceRepository -Name 'TestRepoToDelete' -uri 'https://www.doesnotexist.com' -ErrorAction SilentlyContinue -APIVersion Local