From 63fdabb2d66ab63c50e54e9beed7a7a98982cae6 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 00:27:13 -0400 Subject: [PATCH 01/23] fix test regression --- test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 index 493495282..5c95c5072 100644 --- a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 @@ -24,7 +24,7 @@ Describe 'Test Install-PSResource for local repositories' -tags 'CI' { $testModuleClobber2 = "testModuleClobber2" Get-NewPSResourceRepositoryFile Register-LocalRepos - Register-PSResourceRepository -Name $localNupkgRepo -SourceLocation $localNupkgRepoUri + Register-PSResourceRepository -Name $localNupkgRepo -Uri $localNupkgRepoUri $prereleaseLabel = "alpha001" $tags = @() From d9a337872ccf9fd969d5a81988a27a581ada2cb6 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 10:15:50 -0400 Subject: [PATCH 02/23] fix Describe block error --- .../InstallPSResourceLocal.Tests.ps1 | 4 +--- test/PSGetTestUtils.psm1 | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 index 5c95c5072..0a2fec2bd 100644 --- a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 @@ -16,15 +16,13 @@ Describe 'Test Install-PSResource for local repositories' -tags 'CI' { BeforeAll { $localRepo = "psgettestlocal" $localUNCRepo = "psgettestlocal3" - $localNupkgRepo = "LocalNupkgRepo" - $localNupkgRepoUri = "test\testFiles\testNupkgs" + $localNupkgRepo = "psgettestlocal5" $testModuleName = "test_local_mod" $testModuleName2 = "test_local_mod2" $testModuleClobber = "testModuleClobber" $testModuleClobber2 = "testModuleClobber2" Get-NewPSResourceRepositoryFile Register-LocalRepos - Register-PSResourceRepository -Name $localNupkgRepo -Uri $localNupkgRepoUri $prereleaseLabel = "alpha001" $tags = @() diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index c9f5006b4..a1ad38a5c 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -270,6 +270,24 @@ function Register-LocalRepos { } Register-PSResourceRepository @localRepoParams2 + # Path to folder, within our test folder, where we store special case modules, scripts and nupkgs used for testing + $testDir = (get-item $psscriptroot).FullName + $testFilesFolderPath = Join-Path $testDir -ChildPath "testFiles" + + # Path to specifically to that invalid test nupkgs folder + $testNupkgsFolderPath = Join-Path $testFilesFolderPath -ChildPath "testNupkgs" + Write-Verbose -Verbose "testNupkgsFolderPath: $testNupkgsFolderPath" + + $repoUriAddress5 = $testNupkgsFolderPath + $localRepoParams3 = @{ + Name = "psgettestlocal5" + Uri = $repoUriAddress5 + Priority = 70 + Trusted = $false + } + + Register-PSResourceRepository @localRepoParams3 + Write-Verbose "registered psgettestlocal, psgettestlocal2, psgettestlocal3, psgettestlocal4" } From 8a8cdd727b7aee202069f6489b0c6223671ecde9 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 10:46:34 -0400 Subject: [PATCH 03/23] ADO V2 feed does not return CompanyName property, test for Author instead --- .../InstallPSResourceADOV2Server.Tests.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/InstallPSResourceTests/InstallPSResourceADOV2Server.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceADOV2Server.Tests.ps1 index 3d53fb8c8..589bff92b 100644 --- a/test/InstallPSResourceTests/InstallPSResourceADOV2Server.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceADOV2Server.Tests.ps1 @@ -132,13 +132,14 @@ Describe 'Test Install-PSResource for V3Server scenarios' -tags 'CI' { $pkg.Version | Should -Be "5.0.0" } - It "Install resource with companyname and repository source location and validate properties" { + It "Install resource with author and repository source location and validate properties" { + # CompanyName is not present in ADO V2 feed response properties. Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $ADORepoName -TrustRepository $pkg = Get-InstalledPSResource $testModuleName $pkg.Version | Should -Be "5.2.5" $pkg.Prerelease | Should -Be "alpha001" - $pkg.CompanyName | Should -Be "None" + $pkg.Author | Should -Be "None" $pkg.RepositorySourceLocation | Should -Be $ADORepoUri } From e003c1ba12c161a8ca71f798ef66749a73b9e8b2 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 14:11:09 -0400 Subject: [PATCH 04/23] add separate psm1 function for registering Local TestNupkgs repo --- .../InstallPSResourceLocal.Tests.ps1 | 1 + test/PSGetTestUtils.psm1 | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 index 0a2fec2bd..139bd743d 100644 --- a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 @@ -23,6 +23,7 @@ Describe 'Test Install-PSResource for local repositories' -tags 'CI' { $testModuleClobber2 = "testModuleClobber2" Get-NewPSResourceRepositoryFile Register-LocalRepos + Register-LocalTestNupkgsRepo $prereleaseLabel = "alpha001" $tags = @() diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index a1ad38a5c..6a384c17c 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -270,6 +270,10 @@ function Register-LocalRepos { } Register-PSResourceRepository @localRepoParams2 + Write-Verbose "registered psgettestlocal, psgettestlocal2, psgettestlocal3, psgettestlocal4" +} + +function Register-LocalTestNupkgsRepo { # Path to folder, within our test folder, where we store special case modules, scripts and nupkgs used for testing $testDir = (get-item $psscriptroot).FullName $testFilesFolderPath = Join-Path $testDir -ChildPath "testFiles" @@ -278,17 +282,15 @@ function Register-LocalRepos { $testNupkgsFolderPath = Join-Path $testFilesFolderPath -ChildPath "testNupkgs" Write-Verbose -Verbose "testNupkgsFolderPath: $testNupkgsFolderPath" - $repoUriAddress5 = $testNupkgsFolderPath - $localRepoParams3 = @{ - Name = "psgettestlocal5" - Uri = $repoUriAddress5 + $repoUriAddress = $testNupkgsFolderPath + $localRepoParams = @{ + Name = "localNupkgRepo" + Uri = $repoUriAddress Priority = 70 Trusted = $false } - Register-PSResourceRepository @localRepoParams3 - - Write-Verbose "registered psgettestlocal, psgettestlocal2, psgettestlocal3, psgettestlocal4" + Register-PSResourceRepository @localRepoParams } function Register-PSGallery { From 68e474dfcdf9e35bd11fc82a043c8041a96ca05a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 14:12:06 -0400 Subject: [PATCH 05/23] rename repo --- test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 index 139bd743d..ee7ade6ca 100644 --- a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 @@ -16,7 +16,7 @@ Describe 'Test Install-PSResource for local repositories' -tags 'CI' { BeforeAll { $localRepo = "psgettestlocal" $localUNCRepo = "psgettestlocal3" - $localNupkgRepo = "psgettestlocal5" + $localNupkgRepo = "localNupkgRepo" $testModuleName = "test_local_mod" $testModuleName2 = "test_local_mod2" $testModuleClobber = "testModuleClobber" From 7c3f1483be18f3e353f08c4b9eae61347e503664 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 15:41:21 -0400 Subject: [PATCH 06/23] add debugging --- src/code/LocalServerApiCalls.cs | 25 ++++++++++++++++++- .../InstallPSResourceLocal.Tests.ps1 | 6 ++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index c32f3db57..aa05ecca4 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -646,7 +646,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s File.Move(destNupkgPath, zipFilePath); // extract from .zip - _cmdletPassedIn.WriteDebug($"Extracting '{zipFilePath}' to '{tempDiscoveryPath}'"); + _cmdletPassedIn.WriteVerbose($"Extracting '{zipFilePath}' to '{tempDiscoveryPath}'"); System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempDiscoveryPath); string psd1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.psd1"); @@ -654,6 +654,29 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s string nuspecFilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.nuspec"); List pkgTags = new List(); + _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); + string path = $tempDiscoveryPath; + try { + // Get the files in the directory + string[] files = Directory.GetFiles(path); + // Get the directories in the directory + string[] directories = Directory.GetDirectories(path); + // Output the files + Console.WriteLine("Files:"); + foreach (string file in files) + { + Console.WriteLine(file); + } + // Output the directories + Console.WriteLine("\nDirectories:"); + foreach (string directory in directories) + { + Console.WriteLine(directory); + } + } catch (Exception e) + { + Console.WriteLine("An error occurred: " + e.Message); + } if (File.Exists(psd1FilePath)) { diff --git a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 index ee7ade6ca..437fcd1ad 100644 --- a/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 +++ b/test/InstallPSResourceTests/InstallPSResourceLocal.Tests.ps1 @@ -289,7 +289,11 @@ Describe 'Test Install-PSResource for local repositories' -tags 'CI' { It "Install .nupkg that contains directories (specific package throws errors when accessed by ZipFile.OpenRead)" { $nupkgName = "Microsoft.Web.Webview2" $nupkgVersion = "1.0.2792.45" - Install-PSResource -Name $nupkgName -Version $nupkgVersion -Repository $localNupkgRepo -TrustRepository + $repoPath = Get-PSResourceRepository $localNupkgRepo + Write-Verbose -Verbose "repoPath $($repoPath.Uri)" + $searchPkg = Find-PSResource -Name $nupkgName -Version $nupkgVersion -Repository $localNupkgRepo + Write-Verbose -Verbose "search name: $($searchPkg.Name)" + Install-PSResource -Name $nupkgName -Version $nupkgVersion -Repository $localNupkgRepo -TrustRepository -Verbose $pkg = Get-InstalledPSResource $nupkgName $pkg.Name | Should -Be $nupkgName $pkg.Version | Should -Be $nupkgVersion From 2f788cb0ca2224714d3d0cb3b0242e4c72205e08 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 15:47:17 -0400 Subject: [PATCH 07/23] fix typo --- src/code/LocalServerApiCalls.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index aa05ecca4..ec281b0b0 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -655,7 +655,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s List pkgTags = new List(); _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); - string path = $tempDiscoveryPath; + string path = tempDiscoveryPath; try { // Get the files in the directory string[] files = Directory.GetFiles(path); From 2a4e3b9daca6c751453cbd2df86c5995ece509f9 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 15:56:30 -0400 Subject: [PATCH 08/23] comment out debugging --- src/code/LocalServerApiCalls.cs | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index ec281b0b0..297614193 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -655,28 +655,28 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s List pkgTags = new List(); _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); - string path = tempDiscoveryPath; - try { - // Get the files in the directory - string[] files = Directory.GetFiles(path); - // Get the directories in the directory - string[] directories = Directory.GetDirectories(path); - // Output the files - Console.WriteLine("Files:"); - foreach (string file in files) - { - Console.WriteLine(file); - } - // Output the directories - Console.WriteLine("\nDirectories:"); - foreach (string directory in directories) - { - Console.WriteLine(directory); - } - } catch (Exception e) - { - Console.WriteLine("An error occurred: " + e.Message); - } + // string path = tempDiscoveryPath; + // try { + // // Get the files in the directory + // string[] files = Directory.GetFiles(path); + // // Get the directories in the directory + // string[] directories = Directory.GetDirectories(path); + // // Output the files + // Console.WriteLine("Files:"); + // foreach (string file in files) + // { + // Console.WriteLine(file); + // } + // // Output the directories + // Console.WriteLine("\nDirectories:"); + // foreach (string directory in directories) + // { + // Console.WriteLine(directory); + // } + // } catch (Exception e) + // { + // Console.WriteLine("An error occurred: " + e.Message); + // } if (File.Exists(psd1FilePath)) { From 7da24e8bc486c78f3c9cedd68c4417b5149ee138 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 16:18:18 -0400 Subject: [PATCH 09/23] add back debugging --- src/code/LocalServerApiCalls.cs | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index 297614193..ce2d7cbd0 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -655,28 +655,28 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s List pkgTags = new List(); _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); - // string path = tempDiscoveryPath; - // try { - // // Get the files in the directory - // string[] files = Directory.GetFiles(path); - // // Get the directories in the directory - // string[] directories = Directory.GetDirectories(path); - // // Output the files - // Console.WriteLine("Files:"); - // foreach (string file in files) - // { - // Console.WriteLine(file); - // } - // // Output the directories - // Console.WriteLine("\nDirectories:"); - // foreach (string directory in directories) - // { - // Console.WriteLine(directory); - // } - // } catch (Exception e) - // { - // Console.WriteLine("An error occurred: " + e.Message); - // } + string path = tempDiscoveryPath; + try { + // Get the files in the directory + string[] files = Directory.GetFiles(path); + // Get the directories in the directory + string[] directories = Directory.GetDirectories(path); + // Output the files + _cmdletPassedIn.WriteVerbose("Files:"); + foreach (string file in files) + { + _cmdletPassedIn.WriteVerbose(file); + } + // Output the directories + _cmdletPassedIn.WriteVerbose("\nDirectories:"); + foreach (string directory in directories) + { + _cmdletPassedIn.WriteVerbose(directory); + } + } catch (Exception e) + { + _cmdletPassedIn.WriteVerbose("An error occurred: " + e.Message); + } if (File.Exists(psd1FilePath)) { From 78a0cf60a6ab83ff4c5ee1ab87b5bc6f4d8f66a1 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 17:42:15 -0400 Subject: [PATCH 10/23] skeleton for file finding --- src/code/LocalServerApiCalls.cs | 66 ++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index ce2d7cbd0..48d62757a 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -649,36 +649,52 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s _cmdletPassedIn.WriteVerbose($"Extracting '{zipFilePath}' to '{tempDiscoveryPath}'"); System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempDiscoveryPath); - string psd1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.psd1"); - string ps1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.ps1"); - string nuspecFilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.nuspec"); + var currentFiles = Directory.GetFiles(tempDiscoveryPath); - List pkgTags = new List(); - _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); - string path = tempDiscoveryPath; - try { - // Get the files in the directory - string[] files = Directory.GetFiles(path); - // Get the directories in the directory - string[] directories = Directory.GetDirectories(path); - // Output the files - _cmdletPassedIn.WriteVerbose("Files:"); - foreach (string file in files) - { - _cmdletPassedIn.WriteVerbose(file); - } - // Output the directories - _cmdletPassedIn.WriteVerbose("\nDirectories:"); - foreach (string directory in directories) + string psd1FilePath = String.Empty; + string nuspecFilePath = String.Empty; + string pkgNamePattern = $"{packageName}*"; + Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); + foreach (var x in currentFiles) + { + if (rgx.IsMatch(x)) { - _cmdletPassedIn.WriteVerbose(directory); - } - } catch (Exception e) + if (x.EndsWith("psd1")) + { + psd1FilePath = x; + } + else if (x.EndsWith("nuspec")) + { + nuspecFilePath = x; + } + } + _cmdletPassedIn.WriteVerbose($"file found: " + x); + + } + + foreach (var x in currentFiles) { - _cmdletPassedIn.WriteVerbose("An error occurred: " + e.Message); + _cmdletPassedIn.WriteVerbose($"file found: " + x); + + } + + var files = Directory.EnumerateFiles(tempDiscoveryPath, "*.*", SearchOption.AllDirectories).Where( + s => s.Equals($"{packageName}.nuspec", StringComparison.InvariantCultureIgnoreCase)); + + _cmdletPassedIn.WriteVerbose($"files len: {files.Count()}"); + + foreach (var x in files){ + _cmdletPassedIn.WriteVerbose($"file : {x}"); } - if (File.Exists(psd1FilePath)) + // string psd1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.psd1"); + string ps1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.ps1"); + // string nuspecFilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.nuspec"); + + List pkgTags = new List(); + _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); + + if (files.Contains(psd1FilePath)) { _cmdletPassedIn.WriteDebug($"Attempting to read module manifest file '{psd1FilePath}'"); if (!Utils.TryReadManifestFile(psd1FilePath, out pkgMetadata, out Exception readManifestError)) From 843211bbfb4d4bfb3f8a303d14097ce86addb2e0 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 22:24:15 -0400 Subject: [PATCH 11/23] use regex to properly get package files for local repos especially on Linux --- src/code/LocalServerApiCalls.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index 48d62757a..efe33db10 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -652,6 +652,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s var currentFiles = Directory.GetFiles(tempDiscoveryPath); string psd1FilePath = String.Empty; + string ps1FilePath = String.Empty; string nuspecFilePath = String.Empty; string pkgNamePattern = $"{packageName}*"; Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); @@ -659,6 +660,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s { if (rgx.IsMatch(x)) { + _cmdletPassedIn.WriteVerbose("file is a match: " + x); if (x.EndsWith("psd1")) { psd1FilePath = x; @@ -667,15 +669,13 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s { nuspecFilePath = x; } + else if (x.EndsWith("ps1")) + { + ps1FilePath = x; + } } - _cmdletPassedIn.WriteVerbose($"file found: " + x); - - } - foreach (var x in currentFiles) - { _cmdletPassedIn.WriteVerbose($"file found: " + x); - } var files = Directory.EnumerateFiles(tempDiscoveryPath, "*.*", SearchOption.AllDirectories).Where( @@ -688,7 +688,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s } // string psd1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.psd1"); - string ps1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.ps1"); + // string ps1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.ps1"); // string nuspecFilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.nuspec"); List pkgTags = new List(); From 5c4c7cdefb06c2b291b3df6e8e3b5e1bee8cb730 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 10 Oct 2024 22:57:00 -0400 Subject: [PATCH 12/23] remove unused code --- src/code/LocalServerApiCalls.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index efe33db10..8a7a2bdc6 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -678,15 +678,6 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s _cmdletPassedIn.WriteVerbose($"file found: " + x); } - var files = Directory.EnumerateFiles(tempDiscoveryPath, "*.*", SearchOption.AllDirectories).Where( - s => s.Equals($"{packageName}.nuspec", StringComparison.InvariantCultureIgnoreCase)); - - _cmdletPassedIn.WriteVerbose($"files len: {files.Count()}"); - - foreach (var x in files){ - _cmdletPassedIn.WriteVerbose($"file : {x}"); - } - // string psd1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.psd1"); // string ps1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.ps1"); // string nuspecFilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.nuspec"); @@ -694,7 +685,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s List pkgTags = new List(); _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); - if (files.Contains(psd1FilePath)) + if (File.Exists(psd1FilePath)) { _cmdletPassedIn.WriteDebug($"Attempting to read module manifest file '{psd1FilePath}'"); if (!Utils.TryReadManifestFile(psd1FilePath, out pkgMetadata, out Exception readManifestError)) From c9746cf89ebb2ef2de937c4814227fdaa97a94e0 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 11 Oct 2024 12:54:33 -0400 Subject: [PATCH 13/23] account for version parsring error --- src/code/V2ResponseUtil.cs | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/code/V2ResponseUtil.cs b/src/code/V2ResponseUtil.cs index 68dd1c9c2..6026c44f4 100644 --- a/src/code/V2ResponseUtil.cs +++ b/src/code/V2ResponseUtil.cs @@ -2,8 +2,10 @@ // Licensed under the MIT License. using Microsoft.PowerShell.PSResourceGet.UtilClasses; +using NuGet.Versioning; using System; using System.Collections.Generic; +using System.Linq; using System.Xml; namespace Microsoft.PowerShell.PSResourceGet.Cmdlets @@ -70,6 +72,9 @@ public override IEnumerable ConvertToPSResourceResult(FindResu #region V2 Specific Methods public XmlNode[] ConvertResponseToXML(string httpResponse) { + NuGetVersion emptyVersion = new NuGetVersion("0.0.0.0"); + NuGetVersion firstVersion = emptyVersion; + NuGetVersion lastVersion = emptyVersion; //Create the XmlDocument. XmlDocument doc = new XmlDocument(); @@ -80,7 +85,48 @@ public XmlNode[] ConvertResponseToXML(string httpResponse) { XmlNode[] nodes = new XmlNode[entryNode.Count]; for (int i = 0; i < entryNode.Count; i++) { - nodes[i] = entryNode[i]; + XmlNode node = entryNode[i]; + nodes[i] = node; + var entryChildNodes = node.ChildNodes; + foreach (XmlElement childNode in entryChildNodes) + { + var entryKey = childNode.LocalName; + if (entryKey.Equals("properties")) + { + var propertyChildNodes = childNode.ChildNodes; + foreach (XmlElement propertyChild in propertyChildNodes) + { + var propertyKey = propertyChild.LocalName; + var propertyValue = propertyChild.InnerText; + if (propertyKey.Equals("NormalizedVersion")) + { + if (!NuGetVersion.TryParse(propertyValue, out NuGetVersion parsedNormalizedVersion)) + { + parsedNormalizedVersion = emptyVersion; + } + + if (i == 0) + { + firstVersion = parsedNormalizedVersion; + } + else + { + // later version element + lastVersion = parsedNormalizedVersion; + } + + break; // don't care about rest of the childNode's properties + } + } + } + } + } + + // only order the array in desc order if array has more than 1 element and is currently in ascending order + // check for emptyVersion is in case a version that couldn't be parsed was found, just keep ordering as is. + if (nodes.Length > 1 && firstVersion != emptyVersion && lastVersion != emptyVersion && firstVersion < lastVersion) + { + nodes = nodes.Reverse().ToArray(); } return nodes; From c0177b890cee1ca92bf04fea5376b395f207b547 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 14 Oct 2024 12:13:54 -0400 Subject: [PATCH 14/23] wrap error returned for ADO package not found --- src/code/V2ServerAPICalls.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/code/V2ServerAPICalls.cs b/src/code/V2ServerAPICalls.cs index 5713cfc0c..59b1a3ab4 100644 --- a/src/code/V2ServerAPICalls.cs +++ b/src/code/V2ServerAPICalls.cs @@ -364,6 +364,17 @@ public override FindResults FindName(string packageName, bool includePrerelease, string response = HttpRequestCall(requestUrlV2, out errRecord); if (errRecord != null) { + // usually this is for errors in calling the V2 server, but for ADO V2 this error will include package not found errors which we want to deliver in a standard message + if (_isADORepo && errRecord.Exception is ResourceNotFoundException) + { + errRecord = new ErrorRecord( + new ResourceNotFoundException($"Package with name '{packageName}' could not be found in repository '{Repository.Name}'. For ADO feed, if the package is in an upstream feed make sure you are authenticated to the upstream feed.", errRecord.Exception), + "PackageNotFound", + ErrorCategory.ObjectNotFound, + this); + response = string.Empty; + } + return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); } @@ -648,6 +659,17 @@ public override FindResults FindVersion(string packageName, string version, Reso string response = HttpRequestCall(requestUrlV2, out errRecord); if (errRecord != null) { + // usually this is for errors in calling the V2 server, but for ADO V2 this error will include package not found errors which we want to deliver with a standard message + if (_isADORepo && errRecord.Exception is ResourceNotFoundException) + { + errRecord = new ErrorRecord( + new ResourceNotFoundException($"Package with name '{packageName}' and version '{version}' could not be found in repository '{Repository.Name}'. For ADO feed, if the package is in an upstream feed make sure you are authenticated to the upstream feed.", errRecord.Exception), + "PackageNotFound", + ErrorCategory.ObjectNotFound, + this); + response = string.Empty; + } + return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); } From 256a85c359290fb1cb01c82a7b1657ab592543ce Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 14 Oct 2024 12:38:49 -0400 Subject: [PATCH 15/23] fix test FullyQualifiedErrorId to match existing V2 test FullyQualifiedErrorId --- test/FindPSResourceTests/FindPSResourceADOV2Server.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/FindPSResourceTests/FindPSResourceADOV2Server.Tests.ps1 b/test/FindPSResourceTests/FindPSResourceADOV2Server.Tests.ps1 index 9d4e3f8db..253dad68e 100644 --- a/test/FindPSResourceTests/FindPSResourceADOV2Server.Tests.ps1 +++ b/test/FindPSResourceTests/FindPSResourceADOV2Server.Tests.ps1 @@ -31,7 +31,7 @@ Describe 'Test HTTP Find-PSResource for ADO V2 Server Protocol' -tags 'CI' { $res = Find-PSResource -Name NonExistantModule -Repository $ADOV2RepoName -ErrorVariable err -ErrorAction SilentlyContinue $res | Should -BeNullOrEmpty $err.Count | Should -BeGreaterThan 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFound,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource" + $err[0].FullyQualifiedErrorId | Should -BeExactly "PackageNotFound,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource" $res | Should -BeNullOrEmpty } From dc932a46b99720505c8a7470f4fb7dc9a9f67f51 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 14 Oct 2024 13:08:01 -0400 Subject: [PATCH 16/23] add helper method to discover metadata files from a directory --- src/code/LocalServerApiCalls.cs | 62 ++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index 8a7a2bdc6..9a8c8cbbf 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -646,44 +646,15 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s File.Move(destNupkgPath, zipFilePath); // extract from .zip - _cmdletPassedIn.WriteVerbose($"Extracting '{zipFilePath}' to '{tempDiscoveryPath}'"); + _cmdletPassedIn.WriteDebug($"Extracting '{zipFilePath}' to '{tempDiscoveryPath}'"); System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempDiscoveryPath); - var currentFiles = Directory.GetFiles(tempDiscoveryPath); - string psd1FilePath = String.Empty; string ps1FilePath = String.Empty; string nuspecFilePath = String.Empty; - string pkgNamePattern = $"{packageName}*"; - Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); - foreach (var x in currentFiles) - { - if (rgx.IsMatch(x)) - { - _cmdletPassedIn.WriteVerbose("file is a match: " + x); - if (x.EndsWith("psd1")) - { - psd1FilePath = x; - } - else if (x.EndsWith("nuspec")) - { - nuspecFilePath = x; - } - else if (x.EndsWith("ps1")) - { - ps1FilePath = x; - } - } - - _cmdletPassedIn.WriteVerbose($"file found: " + x); - } - - // string psd1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.psd1"); - // string ps1FilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.ps1"); - // string nuspecFilePath = Path.Combine(tempDiscoveryPath, $"{packageName}.nuspec"); + GetMetadataFilesFromPath(tempDiscoveryPath, packageName, out psd1FilePath, out ps1FilePath, out nuspecFilePath) List pkgTags = new List(); - _cmdletPassedIn.WriteVerbose($"nuspecFilePath: {nuspecFilePath}"); if (File.Exists(psd1FilePath)) { @@ -1113,6 +1084,35 @@ private string[] GetCmdsOrDSCTags(string[] tags, bool isSearchingForCommands) return cmdDSCTags.ToArray(); } + private void GetMetadataFilesFromPath(string dirPath, string packageName, out string psd1FilePath, out string ps1FilePath, out string nuspecFilePath) + { + psd1FilePath = String.Empty; + ps1FilePath = String.Empty; + nuspecFilePath = String.Empty; + + var discoveredFiles = Directory.GetFiles(tempDiscoveryPath, "*.*", SearchOption.AllDirectories); + string pkgNamePattern = $"{packageName}*"; + Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); + foreach (var file in foundFiles) + { + if (rgx.IsMatch(discoveredFiles)) + { + if (file.EndsWith("psd1")) + { + psd1FilePath = file; + } + else if (file.EndsWith("nuspec")) + { + nuspecFilePath = file; + } + else if (file.EndsWith("ps1")) + { + ps1FilePath = file; + } + } + } + } + #endregion } } From 2d088754271b4bc9ba6b840f59f721a827fbbab3 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 14 Oct 2024 13:24:01 -0400 Subject: [PATCH 17/23] fix typo --- src/code/LocalServerApiCalls.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index 9a8c8cbbf..9d16d883e 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -652,7 +652,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s string psd1FilePath = String.Empty; string ps1FilePath = String.Empty; string nuspecFilePath = String.Empty; - GetMetadataFilesFromPath(tempDiscoveryPath, packageName, out psd1FilePath, out ps1FilePath, out nuspecFilePath) + GetMetadataFilesFromPath(tempDiscoveryPath, packageName, out psd1FilePath, out ps1FilePath, out nuspecFilePath); List pkgTags = new List(); From 0535aff3b649cf020860125a5bba74ff7c304daf Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 14 Oct 2024 13:30:49 -0400 Subject: [PATCH 18/23] fix more typos --- src/code/LocalServerApiCalls.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index 9d16d883e..50759546e 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -1090,12 +1090,12 @@ private void GetMetadataFilesFromPath(string dirPath, string packageName, out st ps1FilePath = String.Empty; nuspecFilePath = String.Empty; - var discoveredFiles = Directory.GetFiles(tempDiscoveryPath, "*.*", SearchOption.AllDirectories); + var discoveredFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories); string pkgNamePattern = $"{packageName}*"; Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); - foreach (var file in foundFiles) + foreach (var file in discoveredFiles) { - if (rgx.IsMatch(discoveredFiles)) + if (rgx.IsMatch(file)) { if (file.EndsWith("psd1")) { From d20adb110456d404d32a4cadf925126652c7cad4 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 15 Oct 2024 14:29:41 -0400 Subject: [PATCH 19/23] address PR feedback and remove unused imports --- src/code/LocalServerApiCalls.cs | 32 +------------------------------- src/code/Utils.cs | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index 50759546e..f65cc2427 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -12,7 +12,6 @@ using System.Xml; using System.Net; using System.Management.Automation; -using System.Runtime.ExceptionServices; namespace Microsoft.PowerShell.PSResourceGet.Cmdlets { @@ -652,7 +651,7 @@ private Hashtable GetMetadataFromNupkg(string packageName, string packagePath, s string psd1FilePath = String.Empty; string ps1FilePath = String.Empty; string nuspecFilePath = String.Empty; - GetMetadataFilesFromPath(tempDiscoveryPath, packageName, out psd1FilePath, out ps1FilePath, out nuspecFilePath); + Utils.GetMetadataFilesFromPath(tempDiscoveryPath, packageName, out psd1FilePath, out ps1FilePath, out nuspecFilePath); List pkgTags = new List(); @@ -1084,35 +1083,6 @@ private string[] GetCmdsOrDSCTags(string[] tags, bool isSearchingForCommands) return cmdDSCTags.ToArray(); } - private void GetMetadataFilesFromPath(string dirPath, string packageName, out string psd1FilePath, out string ps1FilePath, out string nuspecFilePath) - { - psd1FilePath = String.Empty; - ps1FilePath = String.Empty; - nuspecFilePath = String.Empty; - - var discoveredFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories); - string pkgNamePattern = $"{packageName}*"; - Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); - foreach (var file in discoveredFiles) - { - if (rgx.IsMatch(file)) - { - if (file.EndsWith("psd1")) - { - psd1FilePath = file; - } - else if (file.EndsWith("nuspec")) - { - nuspecFilePath = file; - } - else if (file.EndsWith("ps1")) - { - ps1FilePath = file; - } - } - } - } - #endregion } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 2227b5e2a..ee5767087 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,4 +1,3 @@ -using System.Net; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. @@ -15,12 +14,13 @@ using System.Runtime.InteropServices; using Microsoft.PowerShell.Commands; using Microsoft.PowerShell.PSResourceGet.Cmdlets; +using System.Net; using System.Net.Http; using System.Globalization; using System.Security; using Azure.Core; using Azure.Identity; -using System.Threading.Tasks; +using System.Text.RegularExpressions; using System.Threading; namespace Microsoft.PowerShell.PSResourceGet.UtilClasses @@ -1171,6 +1171,34 @@ internal static HashSet GetInstalledPackages(List pathsToSearch, return pkgsInstalledOnMachine; } + internal static void GetMetadataFilesFromPath(string dirPath, string packageName, out string psd1FilePath, out string ps1FilePath, out string nuspecFilePath) + { + psd1FilePath = String.Empty; + ps1FilePath = String.Empty; + nuspecFilePath = String.Empty; + + var discoveredFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories); + string pkgNamePattern = $"{packageName}*"; + Regex rgx = new(pkgNamePattern, RegexOptions.IgnoreCase); + foreach (var file in discoveredFiles) + { + if (rgx.IsMatch(file)) + { + if (file.EndsWith("psd1")) + { + psd1FilePath = file; + } + else if (file.EndsWith("nuspec")) + { + nuspecFilePath = file; + } + else if (file.EndsWith("ps1")) + { + ps1FilePath = file; + } + } + } + } #endregion #region PSDataFile parsing From aa2f23fdac39ef79d196064adca3074070b9410a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 15 Oct 2024 14:39:44 -0400 Subject: [PATCH 20/23] add break per PR feedback --- src/code/V2ResponseUtil.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/code/V2ResponseUtil.cs b/src/code/V2ResponseUtil.cs index 6026c44f4..008d5546c 100644 --- a/src/code/V2ResponseUtil.cs +++ b/src/code/V2ResponseUtil.cs @@ -118,6 +118,8 @@ public XmlNode[] ConvertResponseToXML(string httpResponse) { break; // don't care about rest of the childNode's properties } } + + break; // don't care about rest of the childNode's keys } } } From 02708ab1b86f16d13071cdf4d4ee076dc9f69186 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 15 Oct 2024 16:47:41 -0400 Subject: [PATCH 21/23] use SemanticVersion.CompareTo() --- src/code/V2ResponseUtil.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/code/V2ResponseUtil.cs b/src/code/V2ResponseUtil.cs index 008d5546c..fdc0f6122 100644 --- a/src/code/V2ResponseUtil.cs +++ b/src/code/V2ResponseUtil.cs @@ -75,6 +75,7 @@ public XmlNode[] ConvertResponseToXML(string httpResponse) { NuGetVersion emptyVersion = new NuGetVersion("0.0.0.0"); NuGetVersion firstVersion = emptyVersion; NuGetVersion lastVersion = emptyVersion; + bool shouldFixOrder = true; //Create the XmlDocument. XmlDocument doc = new XmlDocument(); @@ -102,7 +103,8 @@ public XmlNode[] ConvertResponseToXML(string httpResponse) { { if (!NuGetVersion.TryParse(propertyValue, out NuGetVersion parsedNormalizedVersion)) { - parsedNormalizedVersion = emptyVersion; + // if a version couldn't be parsed, keep ordering as is. + shouldFixOrder = false; } if (i == 0) @@ -124,9 +126,9 @@ public XmlNode[] ConvertResponseToXML(string httpResponse) { } } - // only order the array in desc order if array has more than 1 element and is currently in ascending order - // check for emptyVersion is in case a version that couldn't be parsed was found, just keep ordering as is. - if (nodes.Length > 1 && firstVersion != emptyVersion && lastVersion != emptyVersion && firstVersion < lastVersion) + // order the array in descending order if not already. + // check for emptyVersion is in case a version that couldn't be parsed was found for the firstVersion we set it to 0.0.0.0 and that messes up compareTo(), so just keep ordering as is. + if (shouldFixOrder && firstVersion.CompareTo(lastVersion) < 0) { nodes = nodes.Reverse().ToArray(); } From a646578c4275516dd33305c3eeb8502722978949 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 15 Oct 2024 17:01:09 -0400 Subject: [PATCH 22/23] clean up comments --- src/code/V2ResponseUtil.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/code/V2ResponseUtil.cs b/src/code/V2ResponseUtil.cs index fdc0f6122..4025f0c83 100644 --- a/src/code/V2ResponseUtil.cs +++ b/src/code/V2ResponseUtil.cs @@ -127,7 +127,6 @@ public XmlNode[] ConvertResponseToXML(string httpResponse) { } // order the array in descending order if not already. - // check for emptyVersion is in case a version that couldn't be parsed was found for the firstVersion we set it to 0.0.0.0 and that messes up compareTo(), so just keep ordering as is. if (shouldFixOrder && firstVersion.CompareTo(lastVersion) < 0) { nodes = nodes.Reverse().ToArray(); From af670795a6b5e98ff08787c3c0b1f9a60d32db83 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 15 Oct 2024 17:10:25 -0400 Subject: [PATCH 23/23] add imports back --- src/code/LocalServerApiCalls.cs | 1 + src/code/Utils.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index f65cc2427..484ed351b 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -12,6 +12,7 @@ using System.Xml; using System.Net; using System.Management.Automation; +using System.Runtime.ExceptionServices; namespace Microsoft.PowerShell.PSResourceGet.Cmdlets { diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ee5767087..769329d84 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -22,6 +22,7 @@ using Azure.Identity; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; namespace Microsoft.PowerShell.PSResourceGet.UtilClasses {