diff --git a/src/Microsoft.PowerShell.PSResourceGet.psd1 b/src/Microsoft.PowerShell.PSResourceGet.psd1 index 3a497db4e..d0b841230 100644 --- a/src/Microsoft.PowerShell.PSResourceGet.psd1 +++ b/src/Microsoft.PowerShell.PSResourceGet.psd1 @@ -37,14 +37,14 @@ FunctionsToExport = @( 'Import-PSGetRepository' ) - VariablesToExport = 'PSGetPath' - AliasesToExport = @( + VariablesToExport = 'PSGetPath' + AliasesToExport = @( 'Get-PSResource', 'fdres', 'isres', 'pbres', 'udres') - PrivateData = @{ + PrivateData = @{ PSData = @{ Prerelease = 'RC1' Tags = @('PackageManagement', @@ -66,7 +66,7 @@ - Fix packaging name matching when searching in local repositories (#1731) - `Compress-PSResource` `-PassThru` now passes `FileInfo` instead of string (#1720) -- Fix for `Compress-PSResource` not properly compressing scripts (#1719) +- Fix for `Compress-PSResource` not properly compressing scripts (#1719) - Add `AcceptLicense` to Save-PSResource (#1718 Thanks @o-l-a-v!) - Better support for NuGet v2 feeds (#1713 Thanks @o-l-a-v!) - Better handling of `-WhatIf` support in `Install-PSResource` (#1531 Thanks @o-l-a-v!) @@ -92,7 +92,7 @@ ### New Features -- Support for Azure Container Registries (#1495, #1497-#1499, #1501, #1502, #1505, #1522, #1545, #1548, #1550, #1554, #1560, #1567, +- Support for Azure Container Registries (#1495, #1497-#1499, #1501, #1502, #1505, #1522, #1545, #1548, #1550, #1554, #1560, #1567, #1573, #1576, #1587, #1588, #1589, #1594, #1598, #1600, #1602, #1604, #1615) ### Bug Fixes @@ -173,7 +173,7 @@ - Bug fix Artifactory v2 endpoint failures (#1428) - Bug fix Artifactory v3 endpoint failures (#1427) - Bug fix `-RequiredResource` silent failures (#1426) -- Bug fix for v2 repository returning extra packages for `-Tag` based search with `-Prerelease` (#1405) +- Bug fix for v2 repository returning extra packages for `-Tag` based search with `-Prerelease` (#1405) See change log (CHANGELOG) at https://github.com/PowerShell/PSResourceGet '@ diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index dafd36400..c66c2df03 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)); @@ -119,7 +118,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( @@ -153,7 +152,7 @@ protected override void ProcessRecord() List pkgsNotFound = new List(); foreach (string name in namesToSearch) { - if (!pkgsFound.Contains(name, StringComparer.OrdinalIgnoreCase)) + if (!pkgsFound.Contains(name, StringComparer.OrdinalIgnoreCase)) { if (name.Contains('*')) { diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index a65797268..6035c6b8b 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -17,15 +17,15 @@ namespace Microsoft.PowerShell.PSResourceGet.Cmdlets /// The Install-PSResource cmdlet installs a resource. /// It returns nothing. /// - [Cmdlet(VerbsLifecycle.Install, - "PSResource", - DefaultParameterSetName = "NameParameterSet", + [Cmdlet(VerbsLifecycle.Install, + "PSResource", + DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] [Alias("isres")] public sealed class InstallPSResource : PSCmdlet { - #region Parameters + #region Parameters /// /// Specifies the exact names of resources to install from a repository. @@ -42,7 +42,7 @@ class InstallPSResource : PSCmdlet [Parameter(ParameterSetName = NameParameterSet, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] public string Version { get; set; } - + /// /// Specifies to allow installation of prerelease versions /// @@ -83,9 +83,9 @@ public string TemporaryPath set { - if (WildcardPattern.ContainsWildcardCharacters(value)) - { - throw new PSArgumentException("Wildcard characters are not allowed in the temporary path."); + if (WildcardPattern.ContainsWildcardCharacters(value)) + { + throw new PSArgumentException("Wildcard characters are not allowed in the temporary path."); } // This will throw if path cannot be resolved @@ -99,7 +99,7 @@ public string TemporaryPath /// [Parameter] public SwitchParameter TrustRepository { get; set; } - + /// /// Overwrites a previously installed resource with the same name and version. /// @@ -130,7 +130,7 @@ public string TemporaryPath /// [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } - + /// /// Check validation for signed and catalog files /// @@ -256,7 +256,7 @@ private enum ResourceFileType #endregion - #region Method Overrides + #region Method override - Begin protected override void BeginProcessing() { @@ -265,7 +265,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); @@ -274,6 +274,9 @@ protected override void BeginProcessing() _installHelper = new InstallHelper(cmdletPassedIn: this, networkCredential: networkCred); } + #endregion + + #region Method Override - Process protected override void ProcessRecord() { switch (ParameterSetName) @@ -287,7 +290,7 @@ protected override void ProcessRecord() pkgCredential: Credential, reqResourceParams: null); break; - + case InputObjectParameterSet: foreach (var inputObj in InputObject) { string normalizedVersionString = Utils.GetNormalizedVersionString(inputObj.Version.ToString(), inputObj.Prerelease); @@ -357,12 +360,12 @@ 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)); } - + RequiredResourceHelper(pkgsInFile); break; @@ -379,7 +382,7 @@ protected override void ProcessRecord() } } */ - + Hashtable pkgsHash = null; try { @@ -441,7 +444,7 @@ private void RequiredResourceHelper(Hashtable reqResourceHash) { var pkgNameEmptyOrWhitespaceError = new ErrorRecord( new ArgumentException($"The package name '{pkgName}' provided cannot be an empty string or whitespace."), - "pkgNameEmptyOrWhitespaceError", + "pkgNameEmptyOrWhitespaceError", ErrorCategory.InvalidArgument, this); @@ -454,7 +457,7 @@ private void RequiredResourceHelper(Hashtable reqResourceHash) { var requiredResourceHashtableInputFormatError = new ErrorRecord( new ArgumentException($"The RequiredResource input with name '{pkgName}' does not have a valid value, the value must be a hashtable."), - "RequiredResourceHashtableInputFormatError", + "RequiredResourceHashtableInputFormatError", ErrorCategory.InvalidArgument, this); @@ -483,7 +486,7 @@ private void RequiredResourceHelper(Hashtable reqResourceHash) ThrowTerminatingError(ParameterParsingError); } } - + if (pkgParams.Scope == ScopeType.AllUsers) { _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, pkgParams.Scope); @@ -513,10 +516,10 @@ private void ProcessInstallHelper(string[] pkgNames, string pkgVersion, bool pkg "NameContainsWildcard", ErrorCategory.InvalidArgument, this)); - + return; } - + foreach (string error in errorMsgs) { WriteError(new ErrorRecord( diff --git a/src/code/ServerApiCall.cs b/src/code/ServerApiCall.cs index 4580e362e..bca013dcb 100644 --- a/src/code/ServerApiCall.cs +++ b/src/code/ServerApiCall.cs @@ -2,14 +2,14 @@ // 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; + namespace Microsoft.PowerShell.PSResourceGet.Cmdlets { @@ -31,7 +31,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; }; @@ -43,7 +43,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 769329d84..c684793e6 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,28 +1,27 @@ // 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; +using System; namespace Microsoft.PowerShell.PSResourceGet.UtilClasses { @@ -140,7 +139,8 @@ public static string[] GetStringArrayFromString(string[] delimeter, 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++) @@ -349,7 +349,8 @@ public static bool TryParseVersionOrVersionRange( out VersionRange versionRange) { versionRange = null; - if (version == null) { return false; } + if (version == null) + { return false; } if (version.Trim().Equals("*")) { @@ -994,30 +995,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( @@ -1570,7 +1629,7 @@ public static void DeleteDirectoryWithRestore(string dirPath) public static void DeleteDirectory(string dirPath) { // Remove read only file attributes first - foreach (var dirFilePath in Directory.GetFiles(dirPath,"*",SearchOption.AllDirectories)) + foreach (var dirFilePath in Directory.GetFiles(dirPath, "*", SearchOption.AllDirectories)) { if (File.GetAttributes(dirFilePath).HasFlag(FileAttributes.ReadOnly)) { @@ -1584,7 +1643,7 @@ public static void DeleteDirectory(string dirPath) { try { - Directory.Delete(dirPath,true); + Directory.Delete(dirPath, true); return; } catch (Exception ex) @@ -1923,7 +1982,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 59b1a3ab4..5108c98c1 100644 --- a/src/code/V2ServerAPICalls.cs +++ b/src/code/V2ServerAPICalls.cs @@ -12,10 +12,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 @@ -39,7 +36,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; @@ -49,14 +46,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; }; @@ -69,7 +66,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; @@ -212,7 +211,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); @@ -351,12 +350,14 @@ 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}'"); } filterBuilder.AddCriterion(includePrerelease ? "IsAbsoluteLatestVersion" : "IsLatestVersion"); - if (type != ResourceType.None) { + if (type != ResourceType.None) + { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } @@ -394,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); } /// @@ -420,12 +421,14 @@ 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}'"); } filterBuilder.AddCriterion(includePrerelease ? "IsAbsoluteLatestVersion" : "IsLatestVersion"); - if (type != ResourceType.None) { + if (type != ResourceType.None) + { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } @@ -646,12 +649,14 @@ 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}'"); } filterBuilder.AddCriterion($"NormalizedVersion eq '{version}'"); - if (type != ResourceType.None) { + if (type != ResourceType.None) + { filterBuilder.AddCriterion(GetTypeFilterForRequest(type)); } @@ -713,12 +718,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)); } @@ -908,19 +915,24 @@ 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) { + if (includePrerelease) + { queryBuilder.AdditionalParameters["includePrerelease"] = "true"; filterBuilder.AddCriterion("IsAbsoluteLatestVersion"); - } else { + } + else + { filterBuilder.AddCriterion("IsLatestVersion"); } var requestUrlV2 = $"{Repository.Uri}{typeEndpoint}/Search()?{queryBuilder.BuildQueryString()}"; @@ -948,19 +960,24 @@ private string FindTagFromEndpoint(string[] tags, bool includePrerelease, bool i }); 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) { + if (includePrerelease) + { queryBuilder.AdditionalParameters["includePrerelease"] = "true"; filterBuilder.AddCriterion("IsAbsoluteLatestVersion"); - } else { + } + else + { filterBuilder.AddCriterion("IsLatestVersion"); } @@ -990,14 +1007,18 @@ 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"; filterBuilder.AddCriterion("IsAbsoluteLatestVersion"); - } else { + } + else + { filterBuilder.AddCriterion("IsLatestVersion"); } @@ -1032,19 +1053,23 @@ 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"; filterBuilder.AddCriterion("IsAbsoluteLatestVersion"); - } else { + } + else + { filterBuilder.AddCriterion("IsLatestVersion"); } - var names = packageName.Split(new char[] {'*'}, StringSplitOptions.RemoveEmptyEntries); + var names = packageName.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); if (names.Length == 0) { @@ -1103,7 +1128,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()}"; @@ -1127,19 +1153,23 @@ private string FindNameGlobbingWithTag(string packageName, string[] tags, Resour }); var filterBuilder = queryBuilder.FilterBuilder; - if (_isPSGalleryRepo) { + if (_isPSGalleryRepo) + { queryBuilder.AdditionalParameters["$orderby"] = "Id desc"; } - if (includePrerelease) { + if (includePrerelease) + { queryBuilder.AdditionalParameters["includePrerelease"] = "true"; filterBuilder.AddCriterion("IsAbsoluteLatestVersion"); - } else { + } + else + { filterBuilder.AddCriterion("IsLatestVersion"); } - var names = packageName.Split(new char[] {'*'}, StringSplitOptions.RemoveEmptyEntries); + var names = packageName.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); if (!_isPSGalleryRepo) { @@ -1203,7 +1233,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()}"; @@ -1276,7 +1307,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()}'"); } } @@ -1290,7 +1322,8 @@ private string FindVersionGlobbing(string packageName, VersionRange versionRange { filterBuilder.AddCriterion(maxPart); } - if (!includePrerelease) { + if (!includePrerelease) + { filterBuilder.AddCriterion("IsPrerelease eq false"); } @@ -1298,11 +1331,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"); } @@ -1361,7 +1396,8 @@ private Stream InstallVersion(string packageName, string version, out ErrorRecor return response.ReadAsStreamAsync().Result; } - private string GetTypeFilterForRequest(ResourceType type) { + private string GetTypeFilterForRequest(ResourceType type) + { string typeFilterPart = string.Empty; if (type == ResourceType.Script) { @@ -1414,7 +1450,7 @@ public int GetCountFromResponse(string httpResponse, out ErrorRecord errRecord) if (!countSearchSucceeded) { - // Note: not all V2 servers may have the 'count' property implemented or valid (i.e CloudSmith server), in this case try to get 'd:Id' property. + // Note: not all V2 servers may have the 'count' property implemented or valid (i.e CloudSmith server), in this case try to get 'd:Id' property. elemList = doc.GetElementsByTagName("d:Id"); if (elemList.Count > 0) {