diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 17c341571..2d90347b4 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -38,8 +38,8 @@ FunctionsToExport = @( 'Import-PSGetRepository' ) - VariablesToExport = 'PSGetPath' - AliasesToExport = @( + VariablesToExport = 'PSGetPath' + AliasesToExport = @( 'Get-PSResource', 'fdres', 'gres', diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index 9dfe1a670..00ee40df1 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -89,7 +89,6 @@ protected override void BeginProcessing() { ThrowTerminatingError(new ErrorRecord( new PSArgumentException($"Error: Could not resolve provided Path argument '{Path}' into a single path."), - "ErrorInvalidPathArgument", ErrorCategory.InvalidArgument, this)); @@ -121,7 +120,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - var namesToSearch = Utils.ProcessNameWildcards(Name, removeWildcardEntries:false, out string[] errorMsgs, out bool _); + var namesToSearch = Utils.ProcessNameWildcards(Name, removeWildcardEntries: false, out string[] errorMsgs, out bool _); foreach (string error in errorMsgs) { WriteError(new ErrorRecord( diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 7beb61a56..241751ecb 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -257,7 +257,7 @@ private enum ResourceFileType #endregion - #region Method Overrides + #region Method override - Begin protected override void BeginProcessing() { @@ -266,7 +266,7 @@ protected override void BeginProcessing() RepositorySettings.CheckRepositoryStore(); _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); - List pathsToSearch = Utils.GetAllResourcePaths(this, Scope); + List pathsToSearch = _pathsToInstallPkg; // Only need to find packages installed if -Reinstall is not passed in _packagesOnMachine = Reinstall ? new HashSet(StringComparer.CurrentCultureIgnoreCase) : Utils.GetInstalledPackages(pathsToSearch, this); @@ -275,6 +275,9 @@ protected override void BeginProcessing() _installHelper = new InstallHelper(cmdletPassedIn: this, networkCredential: networkCred); } + #endregion + + #region Method Override - Process protected override void ProcessRecord() { switch (ParameterSetName) @@ -359,7 +362,7 @@ protected override void ProcessRecord() catch (Exception) { ThrowTerminatingError(new ErrorRecord( - new ArgumentException($"Argument for parameter -RequiredResourceFile is not in proper json or hashtable format. Make sure argument is either a valid .json or .psd1 file."), + new ArgumentException($"Argument for parameter -RequiredResourceFile is not in proper json or hashtable format. Make sure argument is either a valid .json or .psd1 file."), "RequiredResourceFileNotInProperJsonFormat", ErrorCategory.InvalidData, this)); diff --git a/src/code/ServerApiCall.cs b/src/code/ServerApiCall.cs index 4ddcfdad7..94433da12 100644 --- a/src/code/ServerApiCall.cs +++ b/src/code/ServerApiCall.cs @@ -2,11 +2,12 @@ // Licensed under the MIT License. using Microsoft.PowerShell.PSResourceGet.UtilClasses; +using NuGet.Versioning; using System; using System.IO; -using System.Net.Http; -using NuGet.Versioning; +using System.Management.Automation; using System.Net; +using System.Net.Http; using System.Text; using System.Runtime.ExceptionServices; using System.Management.Automation; @@ -33,7 +34,7 @@ public ServerApiCall(PSRepositoryInfo repository, NetworkCredential networkCrede HttpClientHandler handler = new HttpClientHandler(); bool token = false; - if(networkCredential != null) + if (networkCredential != null) { token = String.Equals("token", networkCredential.UserName) ? true : false; }; @@ -45,7 +46,9 @@ public ServerApiCall(PSRepositoryInfo repository, NetworkCredential networkCrede _sessionClient = new HttpClient(handler); _sessionClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); - } else { + } + else + { handler.Credentials = networkCredential; diff --git a/src/code/SetPSResourceGetInstallPathOverride.cs b/src/code/SetPSResourceGetInstallPathOverride.cs new file mode 100644 index 000000000..888dcb652 --- /dev/null +++ b/src/code/SetPSResourceGetInstallPathOverride.cs @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PSResourceGet.UtilClasses; +using System; +using System.Linq; +using System.Management.Automation; +using System.Runtime.InteropServices; + +namespace Microsoft.PowerShell.PSResourceGet.Cmdlets +{ + /// + /// The Set-PSResourceGetInstallPathOverride cmdlet is used to override install path for PS resources. + /// + [Cmdlet(VerbsCommon.Set, "PSResourceGetInstallPathOverride", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Medium)] + [Alias("Update-PSResourceGetInstallPathOverride")] + [OutputType(typeof(void))] + + public sealed class SetPSResourceGetInstallPathOverride : PSCmdlet + { + #region Parameters + + /// + /// Specifies the desired path for the override. + /// + [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true, HelpMessage = "Path for the override.")] + [ValidateNotNullOrEmpty] + public string Path + { + get + { + return _path; + } + + set + { + if (WildcardPattern.ContainsWildcardCharacters(value)) + { + throw new PSArgumentException("Wildcard characters are not allowed in the path."); + } + + // This will throw if path cannot be resolved + _path = GetResolvedProviderPathFromPSPath( + Environment.ExpandEnvironmentVariables(value), + out ProviderInfo provider + ).First(); + } + } + private string _path; + + /// + /// Specifies the scope of installation. + /// + [Parameter(Position = 1)] + public ScopeType Scope { get; set; } + + #endregion + + #region Method override - Begin + + protected override void BeginProcessing() + { + // Only run on Windows for now, due to env variables on Unix being very different + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException($"Error this only works on Windows for now"), + "OsIsNotWindows", + ErrorCategory.InvalidOperation, + this + ) + ); + } + } + + #endregion + + #region Method override - Process + + protected override void ProcessRecord() + { + // Assets + EnvironmentVariableTarget EnvScope = (Scope is ScopeType.AllUsers) ? EnvironmentVariableTarget.Machine : EnvironmentVariableTarget.User; + string PathForModules = System.IO.Path.Combine(_path, "Modules"); + string PathForScripts = System.IO.Path.Combine(_path, "Scripts"); + + // Set env variable for install path override + string PathOverrideCurrentValue = Environment.GetEnvironmentVariable( + "PSResourceGetInstallPathOverride", + EnvScope + ); + if (!String.IsNullOrEmpty(PathOverrideCurrentValue)) + { + WriteVerbose( + String.Format( + "Current value of PSResourceGetInstallPathOverride in scope '{0}': '{1}'", + EnvScope.ToString(), + PathOverrideCurrentValue + ) + ); + } + if ( + !String.IsNullOrEmpty(PathOverrideCurrentValue) && + String.Equals( + Environment.ExpandEnvironmentVariables(PathOverrideCurrentValue), + _path, + StringComparison.Ordinal + ) + ) + { + WriteVerbose( + String.Format( + "PSResourceGetInstallPathOverride in scope '{0}' is already '{1}', no change needed.", + EnvScope.ToString(), + _path + ) + ); + } + else + { + if (this.ShouldProcess($"Set environment variable PSResourceGetPathOverride in scope '{EnvScope} to '{_path}")) + { + Environment.SetEnvironmentVariable( + "PSResourceGetInstallPathOverride", + _path, + EnvScope + ); + WriteVerbose( + String.Format( + "PSResourceGetInstallPathOverride in scope '{0}' was successfully set to: '{1}'", + EnvScope.ToString(), + _path + ) + ); + } + } + + // Add install path override for modules to PSModulePath + string CurrentPSModulePath = Environment.GetEnvironmentVariable( + "PSModulePath", + EnvScope + ); + if (String.IsNullOrEmpty(CurrentPSModulePath)) + { + WriteVerbose(String.Format("PSModulePath in scope '{0}' is empty.", EnvScope.ToString())); + if (this.ShouldProcess($"Set environment pariable 'PSModulePath' in scope '{EnvScope} to '{PathForModules}")) + { + Environment.SetEnvironmentVariable( + "PSModulePath", + PathForModules, + EnvScope + ); + } + } + WriteVerbose(string.Format("Current value of PSModulePath in {0} context: '{1}'", EnvScope.ToString(), CurrentPSModulePath)); + string[] CurrentPSModulePaths = CurrentPSModulePath.Trim(';').Split(';').Select(s => Environment.ExpandEnvironmentVariables(s)).ToArray(); + if (CurrentPSModulePaths.Contains(PathForModules)) + { + WriteVerbose(String.Format("PSModulePath in scope '{0}' already contains '{1}', no change needed.", EnvScope.ToString(), PathForModules)); + } + else + { + WriteVerbose( + String.Format( + "PSModulePath in scope '{0}' does not already contain '{1}'", + EnvScope.ToString(), + PathForModules + ) + ); + if (this.ShouldProcess($"Add '{PathForModules}' to environment variable 'PSModulePath' in scope '{EnvScope}")) + { + Environment.SetEnvironmentVariable( + "PSModulePath", + String.Format("{0};{1}", PathForModules, CurrentPSModulePath), + EnvScope + ); + WriteVerbose( + String.Format( + "Successfully added '{0}' to PSModulePath in scope '{1}'", + PathForModules, + EnvScope.ToString() + ) + ); + } + } + + // Add install path override for scripts to Path + string CurrentPath = Environment.GetEnvironmentVariable( + "Path", + EnvScope + ); + if (String.IsNullOrEmpty(CurrentPath)) + { + WriteVerbose(String.Format("Path in scope '{0}' is empty.", EnvScope.ToString())); + if (this.ShouldProcess($"Set environment pariable 'Path' in scope '{EnvScope} to '{PathForScripts}")) + { + Environment.SetEnvironmentVariable( + "Path", + PathForScripts, + EnvScope + ); + } + } + WriteVerbose(string.Format("Current value of Path in {0} context: '{1}'", EnvScope.ToString(), CurrentPath)); + string[] CurrentPaths = CurrentPath.Trim(';').Split(';').Select(s => Environment.ExpandEnvironmentVariables(s)).ToArray(); + if (CurrentPaths.Contains(PathForScripts)) + { + WriteVerbose(String.Format("Path in scope '{0}' already contains '{1}', no change needed.", EnvScope.ToString(), PathForScripts)); + } + else + { + WriteVerbose( + String.Format( + "Override install path is not already in Path for scope '{0}'", + EnvScope.ToString() + ) + ); + if (this.ShouldProcess($"Add '{PathForScripts}' to environment variable 'Path' in scope '{EnvScope}")) + { + Environment.SetEnvironmentVariable( + "Path", + String.Format("{0};{1}", PathForScripts, CurrentPath), + EnvScope + ); + WriteVerbose( + String.Format( + "Successfully added '{0}' to Path in scope '{1}'", + PathForScripts, + EnvScope.ToString() + ) + ); + } + } + } + + #endregion + } +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 20ccc2d65..ae1ce04e0 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,25 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.Core; +using Azure.Identity; +using Microsoft.PowerShell.Commands; +using Microsoft.PowerShell.PSResourceGet.Cmdlets; using NuGet.Versioning; -using System; -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections; +using System.Globalization; using System.IO; using System.Linq; -using System.Management.Automation; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; -using System.Runtime.InteropServices; -using Microsoft.PowerShell.Commands; -using Microsoft.PowerShell.PSResourceGet.Cmdlets; -using System.Net; +using System.Management.Automation; using System.Net.Http; -using System.Globalization; +using System.Net; +using System.Runtime.InteropServices; using System.Security; -using Azure.Core; -using Azure.Identity; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -142,7 +141,8 @@ public static string[] GetStringArrayFromString(string[] delimiter, string strin /// public static string[] GetStringArray(ArrayList list) { - if (list == null) { return null; } + if (list == null) + { return null; } var strArray = new string[list.Count]; for (int i = 0; i < list.Count; i++) @@ -405,7 +405,8 @@ public static bool TryParseVersionOrVersionRange( out VersionRange versionRange) { versionRange = null; - if (version == null) { return false; } + if (version == null) + { return false; } if (version.Trim().Equals("*")) { @@ -1094,30 +1095,88 @@ public static string GetInstalledPackageName(string pkgPath) return new DirectoryInfo(pkgPath).Parent.Name; } - // Find all potential resource paths - public static List GetPathsFromEnvVarAndScope( + // Get standard install paths given scope + public static List GetStandardPathsForScope( PSCmdlet psCmdlet, ScopeType? scope) { + // Assets + List resourcePaths = new(); + + // Get standard paths GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); + psCmdlet, + out string myDocumentsPath, + out string programFilesPath + ); - List resourcePaths = new List(); - if (scope is null || scope.Value is ScopeType.CurrentUser) + // Add paths to output + if (scope.Value is ScopeType.AllUsers) + { + resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + else { resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); } - if (scope.Value is ScopeType.AllUsers) + // Return results + return resourcePaths; + } + + // Find all potential resource paths + public static List GetPathsFromEnvVarAndScope( + PSCmdlet psCmdlet, + ScopeType? scope) + { + // Path override is only implemented for Windows so far + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); + return GetStandardPathsForScope(psCmdlet, scope); } - return resourcePaths; + // Get value of path override environment variable + string pathOverride = Environment.GetEnvironmentVariable( + "PSResourceGetInstallPathOverride", + (scope.Value is ScopeType.AllUsers) ? EnvironmentVariableTarget.Machine : EnvironmentVariableTarget.User + ); + + // Return standard paths if no override was found, else try to expand paths found in override + if (string.IsNullOrEmpty(pathOverride)) + { + return GetStandardPathsForScope(psCmdlet, scope); + } + else + { + try + { + pathOverride = Environment.ExpandEnvironmentVariables(pathOverride); + } + catch (ArgumentException) + { + psCmdlet.WriteWarning("Path override was found, but could not expand environment variable(s). Falling back to standard paths."); + return GetStandardPathsForScope(psCmdlet, scope); + } + } + + // Return override if present, else use default paths + if (!string.IsNullOrEmpty(pathOverride) && Path.IsPathRooted(pathOverride) && Directory.Exists(pathOverride)) + { + psCmdlet.WriteVerbose(string.Format("Path override was found, using '{0}' as base.", pathOverride)); + // Assets + List resourcePaths = new() + { + Path.Combine(pathOverride, "Modules"), + Path.Combine(pathOverride, "Scripts") + }; + return resourcePaths; + } + else + { + return GetStandardPathsForScope(psCmdlet, scope); + } } public static List GetAllResourcePaths( @@ -2270,7 +2329,8 @@ public static Collection InvokeScriptWithHost( // Extract expected output types from results pipeline. foreach (var psItem in results) { - if (psItem == null || psItem.BaseObject == null) { continue; } + if (psItem == null || psItem.BaseObject == null) + { continue; } switch (psItem.BaseObject) { diff --git a/src/code/V2ServerAPICalls.cs b/src/code/V2ServerAPICalls.cs index 6f2c5c3e1..08934913f 100644 --- a/src/code/V2ServerAPICalls.cs +++ b/src/code/V2ServerAPICalls.cs @@ -13,10 +13,7 @@ using System.Xml; using System.Net; using System.Text; -using System.Runtime.ExceptionServices; using System.Management.Automation; -using System.Reflection; -using System.Data.Common; using System.Linq; namespace Microsoft.PowerShell.PSResourceGet.Cmdlets @@ -40,7 +37,7 @@ internal class V2ServerAPICalls : ServerApiCall public override PSRepositoryInfo Repository { get; set; } private readonly PSCmdlet _cmdletPassedIn; private HttpClient _sessionClient { get; set; } - private static readonly Hashtable[] emptyHashResponses = new Hashtable[]{}; + private static readonly Hashtable[] emptyHashResponses = new Hashtable[] { }; public FindResponseType v2FindResponseType = FindResponseType.ResponseString; private bool _isADORepo; private bool _isJFrogRepo; @@ -50,14 +47,14 @@ internal class V2ServerAPICalls : ServerApiCall #region Constructor - public V2ServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn, NetworkCredential networkCredential, string userAgentString) : base (repository, networkCredential) + public V2ServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmdletPassedIn, NetworkCredential networkCredential, string userAgentString) : base(repository, networkCredential) { this.Repository = repository; _cmdletPassedIn = cmdletPassedIn; HttpClientHandler handler = new HttpClientHandler(); bool token = false; - if(networkCredential != null) + if (networkCredential != null) { token = String.Equals("token", networkCredential.UserName) ? true : false; }; @@ -70,7 +67,9 @@ public V2ServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn, N _sessionClient = new HttpClient(handler); _sessionClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); - } else { + } + else + { handler.Credentials = networkCredential; @@ -213,7 +212,7 @@ public override FindResults FindTags(string[] tags, bool includePrerelease, Reso _cmdletPassedIn.WriteDebug($"Count is '{count}'"); // skip 100 scriptSkip += 100; - var tmpResponse = FindTagFromEndpoint(tags, includePrerelease, isSearchingModule: false, scriptSkip, out errRecord); + var tmpResponse = FindTagFromEndpoint(tags, includePrerelease, isSearchingModule: false, scriptSkip, out errRecord); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); @@ -352,7 +351,8 @@ public override FindResults FindName(string packageName, bool includePrerelease, // If it's a JFrog repository do not include the Id filter portion since JFrog uses 'Title' instead of 'Id', // however filtering on 'and Title eq '' returns "Response status code does not indicate success: 500". - if (!_isJFrogRepo) { + if (!_isJFrogRepo) + { filterBuilder.AddCriterion($"Id eq '{packageName}'"); } @@ -395,7 +395,7 @@ public override FindResults FindName(string packageName, bool includePrerelease, response = string.Empty; } - return new FindResults(stringResponse: new string[]{ response }, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); + return new FindResults(stringResponse: new string[] { response }, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); } /// @@ -520,7 +520,8 @@ public override FindResults FindNameWithTag(string packageName, string[] tags, b // If it's a JFrog repository do not include the Id filter portion since JFrog uses 'Title' instead of 'Id', // however filtering on 'and Title eq '' returns "Response status code does not indicate success: 500". - if (!_isJFrogRepo) { + if (!_isJFrogRepo) + { filterBuilder.AddCriterion($"Id eq '{packageName}'"); } @@ -757,7 +758,8 @@ public override FindResults FindVersion(string packageName, string version, Reso // If it's a JFrog repository do not include the Id filter portion since JFrog uses 'Title' instead of 'Id', // however filtering on 'and Title eq '' returns "Response status code does not indicate success: 500". - if (!_isJFrogRepo) { + if (!_isJFrogRepo) + { filterBuilder.AddCriterion($"Id eq '{packageName}'"); } @@ -915,12 +917,14 @@ public override FindResults FindVersionWithTag(string packageName, string versio // If it's a JFrog repository do not include the Id filter portion since JFrog uses 'Title' instead of 'Id', // however filtering on 'and Title eq '' returns "Response status code does not indicate success: 500". - if (!_isJFrogRepo) { + if (!_isJFrogRepo) + { filterBuilder.AddCriterion($"Id eq '{packageName}'"); } filterBuilder.AddCriterion($"NormalizedVersion eq '{version}'"); - if (type != ResourceType.None) { + if (type != ResourceType.None) + { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } @@ -1244,12 +1248,14 @@ private string FindAllFromTypeEndPoint(bool includePrerelease, bool isSearchingM }); var filterBuilder = queryBuilder.FilterBuilder; - if (_isPSGalleryRepo) { + if (_isPSGalleryRepo) + { queryBuilder.AdditionalParameters["$orderby"] = "Id desc"; } // JFrog/Artifactory requires an empty search term to enumerate all packages in the feed - if (_isJFrogRepo) { + if (_isJFrogRepo) + { queryBuilder.SearchTerm = "''"; if (includePrerelease) { @@ -1296,7 +1302,8 @@ private string FindTagFromEndpoint(string[] tags, bool includePrerelease, bool i }); var filterBuilder = queryBuilder.FilterBuilder; - if (_isPSGalleryRepo) { + if (_isPSGalleryRepo) + { queryBuilder.AdditionalParameters["$orderby"] = "Id desc"; } @@ -1346,11 +1353,13 @@ private string FindCommandOrDscResource(string[] tags, bool includePrerelease, b }); var filterBuilder = queryBuilder.FilterBuilder; - if (_isPSGalleryRepo) { + if (_isPSGalleryRepo) + { queryBuilder.AdditionalParameters["$orderby"] = "Id desc"; } - if (includePrerelease) { + if (includePrerelease) + { queryBuilder.AdditionalParameters["includePrerelease"] = "true"; if (_isJFrogRepo) { // note: we add 'eq true' because some PMPs (currently we know of JFrog, but others may do this too) will proxy the query unedited to the upstream remote and if that's PSGallery, it doesn't handle IsAbsoluteLatestVersion correctly @@ -1401,11 +1410,13 @@ private string FindNameGlobbing(string packageName, ResourceType type, bool incl }); var filterBuilder = queryBuilder.FilterBuilder; - if (_isPSGalleryRepo) { + if (_isPSGalleryRepo) + { queryBuilder.AdditionalParameters["$orderby"] = "Id desc"; } - if (includePrerelease) { + if (includePrerelease) + { queryBuilder.AdditionalParameters["includePrerelease"] = "true"; if (_isJFrogRepo) { // note: we add 'eq true' because some PMPs (currently we know of JFrog, but others may do this too) will proxy the query unedited to the upstream remote and if that's PSGallery, it doesn't handle IsAbsoluteLatestVersion correctly @@ -1485,7 +1496,8 @@ private string FindNameGlobbing(string packageName, ResourceType type, bool incl return string.Empty; } - if (type != ResourceType.None) { + if (type != ResourceType.None) + { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } var requestUrlV2 = $"{Repository.Uri}/Search()?{queryBuilder.BuildQueryString()}"; @@ -1509,7 +1521,8 @@ private string FindNameGlobbingWithTag(string packageName, string[] tags, Resour }); var filterBuilder = queryBuilder.FilterBuilder; - if (_isPSGalleryRepo) { + if (_isPSGalleryRepo) + { queryBuilder.AdditionalParameters["$orderby"] = "Id desc"; } @@ -1599,7 +1612,8 @@ private string FindNameGlobbingWithTag(string packageName, string[] tags, Resour filterBuilder.AddCriterion($"substringof('{tag}', Tags) eq true"); } - if (type != ResourceType.None) { + if (type != ResourceType.None) + { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } var requestUrlV2 = $"{Repository.Uri}/Search()?{queryBuilder.BuildQueryString()}"; @@ -1672,7 +1686,8 @@ private string FindVersionGlobbing(string packageName, VersionRange versionRange { maxPart = String.Format(format, operation, $"'{maxVersion.ToNormalizedString()}'"); } - else { + else + { maxPart = String.Format(format, operation, $"'{versionRange.MaxVersion.ToNormalizedString()}'"); } } @@ -1686,7 +1701,8 @@ private string FindVersionGlobbing(string packageName, VersionRange versionRange { filterBuilder.AddCriterion(maxPart); } - if (!includePrerelease) { + if (!includePrerelease) + { filterBuilder.AddCriterion("IsPrerelease eq false"); } @@ -1694,11 +1710,13 @@ private string FindVersionGlobbing(string packageName, VersionRange versionRange // If it's a JFrog repository do not include the Id filter portion since JFrog uses 'Title' instead of 'Id', // however filtering on 'and Title eq '' returns "Response status code does not indicate success: 500". - if (!_isJFrogRepo) { + if (!_isJFrogRepo) + { filterBuilder.AddCriterion($"Id eq '{packageName}'"); } - if (type == ResourceType.Script) { + if (type == ResourceType.Script) + { filterBuilder.AddCriterion($"substringof('PS{type.ToString()}', Tags) eq true"); }