diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md
index 82fbce245..e2a9d3371 100644
--- a/help/Find-PSResource.md
+++ b/help/Find-PSResource.md
@@ -200,7 +200,7 @@ Accept wildcard characters: False
```
### -Repository
-Specifies one or more repository names to search.
+Specifies one or more repository names to search, which can include wildcard.
If not specified, search will include all currently registered repositories, in order of highest priority, until a repository is found that contains the package.
```yaml
@@ -212,7 +212,7 @@ Required: False
Position: Named
Default value: None
Accept pipeline input: False
-Accept wildcard characters: False
+Accept wildcard characters: True
```
### -Tag
diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml
index 695dc2813..7b47f3878 100644
--- a/src/PSGet.Format.ps1xml
+++ b/src/PSGet.Format.ps1xml
@@ -11,6 +11,7 @@
+
@@ -19,6 +20,7 @@
NameVersionPrereleaseLabel
+ RepositoryDescription
diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs
index 34d79f289..8ed8db1cc 100644
--- a/src/code/FindHelper.cs
+++ b/src/code/FindHelper.cs
@@ -37,7 +37,12 @@ internal class FindHelper
private SwitchParameter _includeDependencies = false;
private readonly string _psGalleryRepoName = "PSGallery";
private readonly string _psGalleryScriptsRepoName = "PSGalleryScripts";
+ private readonly string _psGalleryURL = "https://www.powershellgallery.com/api/v2";
+ private readonly string _poshTestGalleryRepoName = "PoshTestGallery";
+ private readonly string _poshTestGalleryScriptsRepoName = "PoshTestGalleryScripts";
+ private readonly string _poshTestGalleryURL = "https://www.poshtestgallery.com/api/v2";
private bool _isADOFeedRepository;
+ private bool _repositoryNameContainsWildcard;
// NuGet's SearchAsync() API takes a top parameter of 6000, but testing shows for PSGallery
// usually a max of around 5990 is returned while more are left to retrieve in a second SearchAsync() call
@@ -74,10 +79,23 @@ public IEnumerable FindByResourceName(
List repositoriesToSearch;
+ //determine if repository array of names of repositories input to be searched contains wildcard
+ if (repository != null)
+ {
+ repository = Utils.ProcessNameWildcards(repository, out string[] errorMsgs, out _repositoryNameContainsWildcard);
+ foreach (string error in errorMsgs)
+ {
+ _cmdletPassedIn.WriteError(new ErrorRecord(
+ new PSInvalidOperationException(error),
+ "ErrorFilteringNamesForUnsupportedWildcards",
+ ErrorCategory.InvalidArgument,
+ this));
+ }
+ }
+
try
{
repositoriesToSearch = RepositorySettings.Read(repository, out string[] errorList);
-
foreach (string error in errorList)
{
_cmdletPassedIn.WriteError(new ErrorRecord(
@@ -97,12 +115,14 @@ public IEnumerable FindByResourceName(
yield break;
}
- // loop through repositoriesToSearch and if PSGallery add it to list with same priority as PSGallery repo
+ // loop through repositoriesToSearch and if PSGallery or PoshTestGallery add its Scripts endpoint repo
+ // to list with same priority as PSGallery repo
+ // This special casing is done to handle PSGallery and PoshTestGallery having 2 endpoints currently for different resources.
for (int i = 0; i < repositoriesToSearch.Count; i++)
{
- if (String.Equals(repositoriesToSearch[i].Name, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase))
+ if (String.Equals(repositoriesToSearch[i].Url.AbsoluteUri, _psGalleryURL, StringComparison.InvariantCultureIgnoreCase))
{
- // for PowerShellGallery, Module and Script resources have different endpoints so separate repositories have to be registered
+ // special case: for PowerShellGallery, Module and Script resources have different endpoints so separate repositories have to be registered
// with those endpoints in order for the NuGet APIs to search across both in the case where name includes '*'
// detect if Script repository needs to be added and/or Module repository needs to be skipped
@@ -115,11 +135,32 @@ public IEnumerable FindByResourceName(
}
else if (_type != ResourceType.None && _type == ResourceType.Script)
{
- _cmdletPassedIn.WriteVerbose("Type Script provided, so add PSGalleryScripts and remove PSGallery (Modules only)");
+ _cmdletPassedIn.WriteVerbose("Type Script provided, so add PSGalleryScripts and remove PSGallery (Modules only) from search consideration");
repositoriesToSearch.Insert(i + 1, psGalleryScripts);
repositoriesToSearch.RemoveAt(i); // remove PSGallery
}
+ }
+ else if (String.Equals(repositoriesToSearch[i].Url.AbsoluteUri, _poshTestGalleryURL, StringComparison.InvariantCultureIgnoreCase))
+ {
+ // special case: for PoshTestGallery, Module and Script resources have different endpoints so separate repositories have to be registered
+ // with those endpoints in order for the NuGet APIs to search across both in the case where name includes '*'
+
+ // detect if Script repository needs to be added and/or Module repository needs to be skipped
+ Uri poshTestGalleryScriptsUrl = new Uri("https://www.poshtestgallery.com/api/v2/items/psscript/");
+ PSRepositoryInfo poshTestGalleryScripts = new PSRepositoryInfo(_poshTestGalleryScriptsRepoName, poshTestGalleryScriptsUrl, repositoriesToSearch[i].Priority, false);
+ if (_type == ResourceType.None)
+ {
+ _cmdletPassedIn.WriteVerbose("Null Type provided, so add PoshTestGalleryScripts repository");
+ repositoriesToSearch.Insert(i + 1, poshTestGalleryScripts);
+ }
+ else if (_type != ResourceType.None && _type == ResourceType.Script)
+ {
+ _cmdletPassedIn.WriteVerbose("Type Script provided, so add PoshTestGalleryScripts and remove PoshTestGallery (Modules only) from search consideration");
+ repositoriesToSearch.Insert(i + 1, poshTestGalleryScripts);
+ repositoriesToSearch.RemoveAt(i); // remove PoshTestGallery
+ }
}
+
}
for (int i = 0; i < repositoriesToSearch.Count && _pkgsLeftToFind.Any(); i++)
@@ -203,7 +244,8 @@ public IEnumerable SearchFromRepository(
context = new SourceCacheContext();
foreach(PSResourceInfo pkg in SearchAcrossNamesInRepository(
- repositoryName: repositoryName,
+ repositoryName: String.Equals(repositoryUrl.AbsoluteUri, _psGalleryURL, StringComparison.InvariantCultureIgnoreCase) ? _psGalleryRepoName :
+ (String.Equals(repositoryUrl.AbsoluteUri, _poshTestGalleryURL, StringComparison.InvariantCultureIgnoreCase) ? _poshTestGalleryRepoName : repositoryName),
pkgSearchResource: resourceSearch,
pkgMetadataResource: resourceMetadata,
searchFilter: filter,
@@ -309,7 +351,13 @@ private IEnumerable FindFromPackageSourceSearchAPI(
}
foundPackagesMetadata.AddRange(retrievedPkgs.ToList());
- _pkgsLeftToFind.Remove(pkgName);
+
+ // _pkgsLeftToFind.Remove(pkgName);
+
+ if (!_repositoryNameContainsWildcard)
+ {
+ _pkgsLeftToFind.Remove(pkgName);
+ }
}
else
{
@@ -326,7 +374,6 @@ private IEnumerable FindFromPackageSourceSearchAPI(
IEnumerable wildcardPkgs = null;
try
{
- _cmdletPassedIn.WriteVerbose("searching with name: " + pkgName);
// SearchAsync() API returns the latest version only for all packages that match the wild-card name
wildcardPkgs = pkgSearchResource.SearchAsync(
searchTerm: pkgName,
@@ -369,18 +416,28 @@ private IEnumerable FindFromPackageSourceSearchAPI(
foundPackagesMetadata.AddRange(wildcardPkgs.Where(
p => nameWildcardPattern.IsMatch(p.Identity.Id)).ToList());
- // if the Script Uri endpoint still needs to be searched, don't remove the wildcard name from _pkgsLeftToFind
- // PSGallery + Type == null -> M, S
- // PSGallery + Type == M -> M
- // PSGallery + Type == S -> S (but PSGallery would be skipped early on, only PSGalleryScripts would be checked)
- // PSGallery + Type == C -> M
- // PSGallery + Type == D -> M
-
- bool needToCheckPSGalleryScriptsRepo = String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) && _type == ResourceType.None;
- if (foundPackagesMetadata.Any() && !needToCheckPSGalleryScriptsRepo)
+ if (!_repositoryNameContainsWildcard)
{
- _pkgsLeftToFind.Remove(pkgName);
+ // if the Script Uri endpoint still needs to be searched, don't remove the wildcard name from _pkgsLeftToFind
+ // PSGallery + Type == null -> M, S
+ // PSGallery + Type == M -> M
+ // PSGallery + Type == S -> S (but PSGallery would be skipped early on, only PSGalleryScripts would be checked)
+ // PSGallery + Type == C -> M
+ // PSGallery + Type == D -> M
+
+ if (String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) ||
+ String.Equals(repositoryName, _poshTestGalleryRepoName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (foundPackagesMetadata.Any() && _type != ResourceType.None)
+ {
+ _pkgsLeftToFind.Remove(pkgName);
+ }
+ }
+
}
+
+ // if repository names did contain wildcard, we want to do an exhaustive search across all the repositories
+ // which matched the input repository name search term.
}
if (foundPackagesMetadata.Count == 0)
diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs
index f317c4280..464fddc3d 100644
--- a/src/code/FindPSResource.cs
+++ b/src/code/FindPSResource.cs
@@ -176,26 +176,21 @@ private void ProcessResourceNameParameterSet()
{
if (!MyInvocation.BoundParameters.ContainsKey(nameof(Name)))
{
- // TODO: Add support for Tag and Type parameters without Name parameter being specified.
- if (MyInvocation.BoundParameters.ContainsKey(nameof(Type)) || MyInvocation.BoundParameters.ContainsKey(nameof(Tag)))
+ // only cases where Name is allowed to not be specified is if Type or Tag parameters are
+ if (!MyInvocation.BoundParameters.ContainsKey(nameof(Type)) && !MyInvocation.BoundParameters.ContainsKey(nameof(Tag)))
{
ThrowTerminatingError(
new ErrorRecord(
- new PSNotImplementedException("Search by Tag or Type parameter is not yet implemented."),
- "TagTypeSearchNotYetImplemented",
- ErrorCategory.NotImplemented,
+ new PSInvalidOperationException("Name parameter must be provided."),
+ "NameParameterNotProvided",
+ ErrorCategory.InvalidOperation,
this));
}
- ThrowTerminatingError(
- new ErrorRecord(
- new PSInvalidOperationException("Name parameter must be provided."),
- "NameParameterNotProvided",
- ErrorCategory.InvalidOperation,
- this));
+ Name = new string[] {"*"};
}
-
- var namesToSearch = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard);
+
+ Name = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard);
foreach (string error in errorMsgs)
{
@@ -208,21 +203,10 @@ private void ProcessResourceNameParameterSet()
// this catches the case where Name wasn't passed in as null or empty,
// but after filtering out unsupported wildcard names there are no elements left in namesToSearch
- if (namesToSearch.Length == 0)
- {
- return;
- }
-
- if (String.Equals(namesToSearch[0], "*", StringComparison.InvariantCultureIgnoreCase))
+ if (Name.Length == 0)
{
- // WriteVerbose("Package names were detected to be (or contain an element equal to): '*', so all packages will be updated");
- WriteError(new ErrorRecord(
- new PSInvalidOperationException("-Name '*' is not supported for Find-PSResource so all Name entries will be discarded."),
- "NameEqualsWildcardIsNotSupported",
- ErrorCategory.InvalidArgument,
- this));
return;
- }
+ }
FindHelper findHelper = new FindHelper(_cancellationToken, this);
List foundPackages = new List();
@@ -241,7 +225,7 @@ private void ProcessResourceNameParameterSet()
}
foreach (var uniquePackageVersion in foundPackages.GroupBy(
- m => new {m.Name, m.Version}).Select(
+ m => new {m.Name, m.Version, m.Repository}).Select(
group => group.First()).ToList())
{
WriteObject(uniquePackageVersion);
diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1
index 57ab7a23b..4e82e383b 100644
--- a/test/FindPSResource.Tests.ps1
+++ b/test/FindPSResource.Tests.ps1
@@ -9,6 +9,8 @@ Describe 'Test Find-PSResource for Module' {
$TestGalleryName = Get-PoshTestGalleryName
$PSGalleryName = Get-PSGalleryName
$NuGetGalleryName = Get-NuGetGalleryName
+ $testModuleName = "testmodule"
+ $testScriptName = "test_script"
$commandName = "Get-TargetResource"
$dscResourceName = "SystemLocale"
$parentModuleName = "SystemLocaleDsc"
@@ -41,7 +43,8 @@ Describe 'Test Find-PSResource for Module' {
$res = Find-PSResource -Name "AzureS*" -Repository $PSGalleryName
$res.Count | Should -BeGreaterThan 1
# should find Module and Script resources
- foreach ($item in $res) {
+ foreach ($item in $res)
+ {
if ($item.Type -eq "Script")
{
$foundScript = $true
@@ -51,10 +54,62 @@ Describe 'Test Find-PSResource for Module' {
$foundScript | Should -BeTrue
}
- It "should not find resources given Name that equals wildcard, '*'" {
- Find-PSResource -Name "*" -ErrorVariable err -ErrorAction SilentlyContinue
- $err.Count | Should -Not -Be 0
- $err[0].FullyQualifiedErrorId | Should -BeExactly "NameEqualsWildcardIsNotSupported,Microsoft.PowerShell.PowerShellGet.Cmdlets.FindPSResource"
+ It "should find all resources given Name that equals wildcard, '*'" {
+ $foundPreview = $False
+ $foundTestScript = $False
+ $foundTestModule = $False
+ $res = Find-PSResource -Name "*" -Repository $TestGalleryName
+ #should find Module and Script resources
+ foreach ($item in $res)
+ {
+ if ($item.Name -eq $testModuleName)
+ {
+ $foundTestModule = $True
+ }
+
+ if ($item.Name -eq $testScriptName)
+ {
+ $foundTestScript = $True
+ }
+
+ if(-not [string]::IsNullOrEmpty($item.PrereleaseLabel))
+ {
+ $foundPreview = $True
+ }
+ }
+
+ $foundPreview | Should -Be $False
+ $foundTestScript | Should -Be $True
+ $foundTestModule | Should -Be $True
+ }
+
+ It "should find all resources (including prerelease) given Name that equals wildcard, '*' and Prerelease parameter" {
+ $foundPreview = $False
+ $foundTestScript = $False
+ $foundTestModule = $False
+ $res = Find-PSResource -Name "*" -Prerelease -Repository $TestGalleryName
+ #should find Module and Script resources
+ foreach ($item in $res)
+ {
+ if ($item.Name -eq $testModuleName)
+ {
+ $foundTestModule = $True
+ }
+
+ if ($item.Name -eq $testScriptName)
+ {
+ $foundTestScript = $True
+ }
+
+ if(-not [string]::IsNullOrEmpty($item.PrereleaseLabel))
+ {
+ $foundPreview = $True
+ }
+ }
+
+ $foundPreview | Should -Be $True
+ $foundTestScript | Should -Be $True
+ $foundTestModule | Should -Be $True
}
It "find resource given Name from V3 endpoint repository (NuGetGallery)" {
@@ -194,7 +249,21 @@ Describe 'Test Find-PSResource for Module' {
}
}
- It "find resuources given Tag parameter" {
+ It "find all resources of Type Module when Type parameter set is used" {
+ $foundScript = $False
+ $res = Find-PSResource -Type Module -Repository $PSGalleryName
+ $res.Count | Should -BeGreaterThan 1
+ foreach ($item in $res) {
+ if ($item.Type -eq "Script")
+ {
+ $foundScript = $True
+ }
+ }
+
+ $foundScript | Should -Be $False
+ }
+
+ It "find resources given Tag parameter" {
$resWithEitherExpectedTag = @("NetworkingDsc", "DSCR_FileContent", "SS.PowerShell")
$res = Find-PSResource -Name "NetworkingDsc", "HPCMSL", "DSCR_FileContent", "SS.PowerShell", "PowerShellGet" -Tag "Dsc", "json" -Repository $PSGalleryName
foreach ($item in $res) {
@@ -202,6 +271,29 @@ Describe 'Test Find-PSResource for Module' {
}
}
+ It "find all resources with specified tag given Tag property" {
+ $foundTestModule = $False
+ $foundTestScript = $False
+ $tagToFind = "Tag1"
+ $res = Find-PSResource -Tag $tagToFind -Repository $TestGalleryName
+ foreach ($item in $res) {
+ $item.Tags -contains $tagToFind | Should -Be $True
+
+ if ($item.Name -eq $testModuleName)
+ {
+ $foundTestModule = $True
+ }
+
+ if ($item.Name -eq $testScriptName)
+ {
+ $foundTestScript = $True
+ }
+ }
+
+ $foundTestModule | Should -Be $True
+ $foundTestScript | Should -Be $True
+ }
+
It "find resource with IncludeDependencies parameter" {
$res = Find-PSResource -Name "Az.Compute" -IncludeDependencies -Repository $PSGalleryName
$isDependencyNamePresent = $False