From a4934fc161e059f3f022b37419e7d2e1c9d31724 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 8 Apr 2021 13:24:23 -0400 Subject: [PATCH 001/276] Refactoring *-PSResourceRepository cmdlets (Register, Get, Unregister) (#346) * added new RegisterPSResourceRepository.cs with parameters so far * add PSRepositoryItemInfo * added passthru, need to complete implementation * added code and tests for REgister-PSResourceRepository * add code for Get-PSResourceRepository and move to srcNew * add files to srcNew * moved cmdlets and added Set-PSResourceRepository cmdlet * removed set, get, unregister resource repository cmdlets to put in later PRs * rename Register-PSResourceRepository cmdlet and references to previous name of cmdlet * added comemnts where needed * revert changes accidentally made * add Get-PSResourceRepository, Unregister-PSResourceRepository so tests for Register can work * reset changes to settings.json * revert unintended changes to srcOld folder * revert unintended changes to testOld * revert unintended changes to PowerShellGet.psd1 script * add EOL to some files that were missing it * remove commented out code from PSGetTestUtils.cs * changed using statements so that namespace and class name can have same names without error * fix reference in ArgumentCompleter.cs * fix some codacy warnings * make RepositorySettings.cs a static class and update rest of classes that use it * remove not so helpful comments * explicitly type variables that were previously implicitly typed as var * remove unintended writeDebug message * use yield to return IEnumerable for ArgumentCompleter and remove private helper method * remove unncessary parameter set names from cmdlets which don't have multiple parameter sets * store parameter set names as const fields * remove unused RemotingCapability field from Cmdlets * RepositorySettings and PSRepositoryItem now belong to UtilClasses namespace and removed older using statements * replace private fields with Properties, use switch case for parameter set names * Remove comments * create helper method to search if repo with name already exists * change error handling to be non terminating where needed, and continue looping through rest of repositories if error arises * remove some unneccessary comments * refactor so there's a helper method calling the Add() API * call Read() to find existing repo by name in Add() * make commented description of Add() clearer * refactor FindRepositoryXML() * throw error if non implemented parameters are attempted to be used * refactor CheckRepositoryStore() and how/where it throws errors * wrap RepositorySettings file handling code with try/catch * minor fix * remove unneccessary using statements * Delete UnregisterPSResourceRepository.Tests.ps1 * include error specific tests for Register-PSResourceRepository * change Repositories parameter type from List to Hashtable[] * add tests for Unregister and refactor RepositorySettings to handle Unregister related errors * add out errorMsgs to RepositorySettings Read() and refactor GetPSResourceRepository and its tests * fix ArgumentCompleter issue * remove uneccesary comments from RepositorySettings * rename FindRepositoryElement helper method * refactor FindRepositoryElement code to just return and be more readable * styling with if keywords * fix indentation and bracket placement according to PowerShell style standards * added Debug statements to register * added try catch to Get and Unregister, changed out string[] errorMsgs syntax * fix Debug statements and remove unneccessary try catch * remove shouldSupportProcess from Get * put check for repo store in BeginProcessing() and change default switch case to use dbg assert * check if repo name is whitespace * correct error message typo * remove unncessary comment * fix typo in tests, rename errorMsgs to errorList * make PSRepositoryItem sealed class, add ShouldProcess() support to Register * add ShouldSupportProcess = true to Unregister * don't write error if names matching wildcard aren't found * not set errorList to null as not needed * add powershell helper to add quotes to ArgumentCompleter to deal with Name with spaces * tests use now * changed Get and Unregister tests to use FullyQualifiedErrorId * remove setters from PSRepositoryItem * remove ValueByPipeline tag from Proxy, ProxyCredential and add onto Repositories * use ErrorId for Unregister tests * all tests now rely on FullyQualifiedErrorId * make shouldsupport() target action message more intuitive * fix target name formatting for ShouldProcess() * add newline after brackets and #endregion per powershell style guidelines * add newline in Utils.cs * trim trailing and leading whitespaces from Name and throw error if Name is just whitespace * add test for throwing error if Name is whitespace for register * rename Get and Unregister to remove hype in cmdlet name * fix codacy warning * fixed some naming conventions in test to fix codacy warnings * renamed PSRepositoryItem -> PSRepositoryInfo to match Amber's output class naming * Update Name parameter description Update name parameter description to say it now supports wildcards in Name * fix styling issues * change Repository settings fields to private * change testcases syntax to Pester v4 syntax * change temp variable name, update PSResourceRepository.xml file comment * add newline to end of Utils.cs * organize using directive statements alphabetically * change error type for checkRepositoryStore error thrown --- src/code/ArgumentCompleter.cs | 36 ++ src/code/GetPSResourceRepository.cs | 80 ++++ src/code/PSRepositoryInfo.cs | 50 ++ src/code/RegisterPSResourceRepository.cs | 377 +++++++++++++++ src/code/RepositorySettings.cs | 290 +++++++++++ src/code/UnregisterPSResourceRepository.cs | 78 +++ src/code/Utils.cs | 44 ++ test/GetPSResourceRepository.Tests.ps1 | 100 ++++ test/PSGetTestUtils.psm1 | 452 ++++++++++++++++++ test/RegisterPSResourceRepository.Tests.ps1 | 221 +++++++++ test/UnregisterPSResourceRepository.Tests.ps1 | 62 +++ test/testRepositories.xml | 6 + 12 files changed, 1796 insertions(+) create mode 100644 src/code/ArgumentCompleter.cs create mode 100644 src/code/GetPSResourceRepository.cs create mode 100644 src/code/PSRepositoryInfo.cs create mode 100644 src/code/RegisterPSResourceRepository.cs create mode 100644 src/code/RepositorySettings.cs create mode 100644 src/code/UnregisterPSResourceRepository.cs create mode 100644 src/code/Utils.cs create mode 100644 test/GetPSResourceRepository.Tests.ps1 create mode 100644 test/PSGetTestUtils.psm1 create mode 100644 test/RegisterPSResourceRepository.Tests.ps1 create mode 100644 test/UnregisterPSResourceRepository.Tests.ps1 create mode 100644 test/testRepositories.xml diff --git a/src/code/ArgumentCompleter.cs b/src/code/ArgumentCompleter.cs new file mode 100644 index 000000000..1afd903df --- /dev/null +++ b/src/code/ArgumentCompleter.cs @@ -0,0 +1,36 @@ +using System.ComponentModel; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using System.Collections; +using System.Collections.Generic; +using System.Management.Automation; +using System.Management.Automation.Language; + +internal class RepositoryNameCompleter : IArgumentCompleter +{ + public IEnumerable CompleteArgument( + string commandName, + string parameterName, + string wordToComplete, + CommandAst commandAst, + IDictionary fakeBoundParameters) + { + List listOfRepositories = RepositorySettings.Read(null, out string[] _); + + wordToComplete = Utils.TrimQuotes(wordToComplete); + var wordToCompletePattern = WildcardPattern.Get( + pattern: string.IsNullOrWhiteSpace(wordToComplete) ? "*" : wordToComplete + "*", + options: WildcardOptions.IgnoreCase); + + foreach (PSRepositoryInfo repo in listOfRepositories) + { + string repoName = repo.Name; + if (wordToCompletePattern.IsMatch(repoName)) + { + yield return new CompletionResult(Utils.QuoteName(repoName)); + } + } + } +} diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs new file mode 100644 index 000000000..a000c8de0 --- /dev/null +++ b/src/code/GetPSResourceRepository.cs @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Get-PSResourceRepository cmdlet replaces the Get-PSRepository cmdlet from V2. + /// It searches for the PowerShell module repositories that are registered for the current user. + /// By default it will return all registered repositories, or if the -Name parameter argument is specified then it wil return the repository with that name. + /// It returns PSRepositoryInfo objects which describe each resource item found. + /// + + [Cmdlet(VerbsCommon.Get, + "PSResourceRepository", + HelpUri = "")] + public sealed + class GetPSResourceRepository : PSCmdlet + { + #region Parameters + + /// + /// Specifies the name(s) of a registered repository to find. + /// Supports wild card characters. + /// + [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } = new string[0]; + + #endregion + + #region Methods + + protected override void BeginProcessing() + { + try + { + WriteDebug("Calling API to check repository store exists in non-corrupted state"); + RepositorySettings.CheckRepositoryStore(); + } + catch (PSInvalidOperationException e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "RepositoryStoreException", + ErrorCategory.ReadError, + this)); + } + } + protected override void ProcessRecord() + { + string nameArrayAsString = (Name == null || !Name.Any() || string.Equals(Name[0], "*") || Name[0] == null) ? "all" : string.Join(", ", Name); + WriteDebug(String.Format("reading repository: {0}. Calling Read() API now", nameArrayAsString)); + List items = RepositorySettings.Read(Name, out string[] errorList); + + // handle non-terminating errors + foreach (string error in errorList) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorGettingSpecifiedRepo", + ErrorCategory.InvalidOperation, + this)); + } + + foreach (PSRepositoryInfo repo in items) + { + WriteObject(repo); + } + } + + #endregion + } +} diff --git a/src/code/PSRepositoryInfo.cs b/src/code/PSRepositoryInfo.cs new file mode 100644 index 000000000..b1d99eb08 --- /dev/null +++ b/src/code/PSRepositoryInfo.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a repository item. + /// + public sealed class PSRepositoryInfo + { + #region Constructor + + public PSRepositoryInfo(string name, Uri url, int priority, bool trusted) + { + Name = name; + Url = url; + Priority = priority; + Trusted = trusted; + } + + #endregion + + #region Properties + + /// + /// the Name of the repository + /// + public string Name { get; } + + /// + /// the Url for the repository + /// + public Uri Url { get; } + + /// + /// whether the repository is trusted + public bool Trusted { get; } + + /// + /// the priority of the repository + /// + [ValidateRange(0, 50)] + public int Priority { get; } + + #endregion + } +} diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs new file mode 100644 index 000000000..a31c110a8 --- /dev/null +++ b/src/code/RegisterPSResourceRepository.cs @@ -0,0 +1,377 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Management.Automation; +using Dbg = System.Diagnostics.Debug; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Register-PSResourceRepository cmdlet replaces the Register-PSRepository from V2. + /// It registers a repository for PowerShell modules. + /// The repository is registered to the current user's scope and does not have a system-wide scope. + /// + + [Cmdlet(VerbsLifecycle.Register, + "PSResourceRepository", + DefaultParameterSetName = NameParameterSet, + SupportsShouldProcess = true, + HelpUri = "")] + public sealed + class RegisterPSResourceRepository : PSCmdlet + { + #region Members + + private readonly string PSGalleryRepoName = "PSGallery"; + private readonly string PSGalleryRepoURL = "https://www.powershellgallery.com/api/v2"; + private const int defaultPriority = 50; + private const bool defaultTrusted = false; + private const string NameParameterSet = "NameParameterSet"; + private const string PSGalleryParameterSet = "PSGalleryParameterSet"; + private const string RepositoriesParameterSet = "RepositoriesParameterSet"; + + #endregion + + #region Parameters + + /// + /// Specifies name for the repository to be registered. + /// + [Parameter(Mandatory = true, Position = 0, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Name { get; set; } + + /// + /// Specifies the location of the repository to be registered. + /// + [Parameter(Mandatory = true, Position = 1, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public Uri URL + { + get + { return _url; } + + set + { + if (!Uri.TryCreate(value, string.Empty, out Uri url)) + { + var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0}", value); + var ex = new ArgumentException(message); + var moduleManifestNotFound = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(moduleManifestNotFound); + } + + _url = url; + } + } + private Uri _url; + + /// + /// When specified, registers PSGallery repository. + /// + [Parameter(Mandatory = true, ParameterSetName = PSGalleryParameterSet)] + public SwitchParameter PSGallery { get; set; } + + /// + /// Specifies a hashtable of repositories and is used to register multiple repositories at once. + /// + [Parameter(Mandatory = true, ParameterSetName = "RepositoriesParameterSet", ValueFromPipeline = true)] + [ValidateNotNullOrEmpty] + public Hashtable[] Repositories {get; set;} + + /// + /// Specifies whether the repository should be trusted. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = PSGalleryParameterSet)] + public SwitchParameter Trusted { get; set; } + + /// + /// Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched + /// before a lower ranking priority one, when searching for a repository item across multiple registered repositories. + /// Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds + /// to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = PSGalleryParameterSet)] + [ValidateRange(0, 50)] + public int Priority { get; set; } = defaultPriority; + + /// + /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. + /// + [Parameter] + [ValidateNotNullOrEmpty] + public Uri Proxy { get; set; } + + /// + /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. + /// + [Parameter] + public PSCredential ProxyCredential { get; set; } + + /// + /// When specified, displays the succcessfully registered repository and its information + /// + [Parameter] + public SwitchParameter PassThru { get; set; } + + #endregion + + #region Methods + + protected override void BeginProcessing() + { + if (Proxy != null || ProxyCredential != null) + { + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("Proxy and ProxyCredential are not yet implemented. Please rerun cmdlet with other parameters."), + "ParametersNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + } + + try + { + RepositorySettings.CheckRepositoryStore(); + } + catch (PSInvalidOperationException e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "RepositoryStoreException", + ErrorCategory.ReadError, + this)); + } + } + protected override void ProcessRecord() + { + List items = new List(); + + switch (ParameterSetName) + { + case NameParameterSet: + try + { + items.Add(NameParameterSetHelper(Name, URL, Priority, Trusted)); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorInNameParameterSet", + ErrorCategory.InvalidArgument, + this)); + } + break; + + case PSGalleryParameterSet: + try + { + items.Add(PSGalleryParameterSetHelper(Priority, Trusted)); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorInPSGalleryParameterSet", + ErrorCategory.InvalidArgument, + this)); + } + break; + + case RepositoriesParameterSet: + try + { + items = RepositoriesParameterSetHelper(); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorInRepositoriesParameterSet", + ErrorCategory.InvalidArgument, + this)); + } + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + + } + + if (PassThru) + { + foreach (PSRepositoryInfo repo in items) + { + WriteObject(repo); + } + } + } + + private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted) + { + // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition + repoName = repoName.Trim(' '); + if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) + { + throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); + } + + if (repoUrl == null || !(repoUrl.Scheme == Uri.UriSchemeHttp || repoUrl.Scheme == Uri.UriSchemeHttps || repoUrl.Scheme == Uri.UriSchemeFtp || repoUrl.Scheme == Uri.UriSchemeFile)) + { + throw new ArgumentException("Invalid url, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); + } + + WriteDebug("All required values to add to repository provided, calling internal Add() API now"); + if (!ShouldProcess(repoName, "Register repository to repository store")) + { + return null; + } + + return RepositorySettings.Add(repoName, repoUrl, repoPriority, repoTrusted); + } + + private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted) + { + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) + { + WriteDebug("Provided Name (NameParameterSet) but with invalid value of PSGallery"); + throw new ArgumentException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"); + } + + return AddToRepositoryStoreHelper(repoName, repoUrl, repoPriority, repoTrusted); + } + + private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repoTrusted) + { + Uri psGalleryUri = new Uri(PSGalleryRepoURL); + WriteDebug("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); + return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted); + } + + private List RepositoriesParameterSetHelper() + { + List reposAddedFromHashTable = new List(); + foreach (Hashtable repo in Repositories) + { + if (repo.ContainsKey(PSGalleryRepoName)) + { + if (repo.ContainsKey("Name") || repo.ContainsKey("Url")) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Repository hashtable cannot contain PSGallery key with -Name and/or -URL key value pairs"), + "NotProvideNameUrlForPSGalleryRepositoriesParameterSetRegistration", + ErrorCategory.InvalidArgument, + this)); + continue; + } + + try + { + WriteDebug("(RepositoriesParameterSet): on repo: PSGallery. Registers PSGallery repository"); + reposAddedFromHashTable.Add(PSGalleryParameterSetHelper( + repo.ContainsKey("Priority") ? (int)repo["Priority"] : defaultPriority, + repo.ContainsKey("Trusted") ? (bool)repo["Trusted"] : defaultTrusted)); + } + catch (Exception e) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorParsingIndividualRepoPSGallery", + ErrorCategory.InvalidArgument, + this)); + } + } + else + { + PSRepositoryInfo parsedRepoAdded = RepoValidationHelper(repo); + if (parsedRepoAdded != null) + { + reposAddedFromHashTable.Add(parsedRepoAdded); + } + } + } + + return reposAddedFromHashTable; + } + + private PSRepositoryInfo RepoValidationHelper(Hashtable repo) + { + if (!repo.ContainsKey("Name") || String.IsNullOrEmpty(repo["Name"].ToString())) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Repository name cannot be null"), + "NullNameForRepositoriesParameterSetRegistration", + ErrorCategory.InvalidArgument, + this)); + return null; + } + + if (repo["Name"].ToString().Equals("PSGallery")) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"), + "PSGalleryProvidedAsNameRepoPSet", + ErrorCategory.InvalidArgument, + this)); + return null; + } + + if (!repo.ContainsKey("Url") || String.IsNullOrEmpty(repo["Url"].ToString())) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Repository url cannot be null"), + "NullURLForRepositoriesParameterSetRegistration", + ErrorCategory.InvalidArgument, + this)); + return null; + } + + if (!Uri.TryCreate(repo["URL"].ToString(), UriKind.Absolute, out Uri repoURL)) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Invalid url, unable to create"), + "InvalidUrlScheme", + ErrorCategory.InvalidArgument, + this)); + return null; + } + + try + { + WriteDebug(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); + return NameParameterSetHelper(repo["Name"].ToString(), + repoURL, + repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : defaultPriority, + repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : defaultTrusted); + } + catch (Exception e) + { + if (!(e is ArgumentException || e is PSInvalidOperationException)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "TerminatingErrorParsingAddingIndividualRepo", + ErrorCategory.InvalidArgument, + this)); + } + + WriteError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorParsingIndividualRepo", + ErrorCategory.InvalidArgument, + this)); + return null; + } + } + + #endregion + } +} diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs new file mode 100644 index 000000000..2169c960e --- /dev/null +++ b/src/code/RepositorySettings.cs @@ -0,0 +1,290 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Xml.Linq; +using static System.Environment; +using Dbg = System.Diagnostics.Debug; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// The class contains basic information of a repository path settings as well as methods to + /// perform CRUD operations on the repository store file. + /// + + internal static class RepositorySettings + { + /// + /// File name for a user's repository store file is 'PSResourceRepository.xml' + /// The repository store file's location is currently only at '%LOCALAPPDATA%\PowerShellGet' for the user account. + /// + private static readonly string RepositoryFileName = "PSResourceRepository.xml"; + private static readonly string RepositoryPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet"); + private static readonly string FullRepositoryPath = Path.Combine(RepositoryPath, RepositoryFileName); + + + /// + /// Check if repository store xml file exists, if not then create + /// + public static void CheckRepositoryStore() + { + if (!File.Exists(FullRepositoryPath)) + { + try + { + if (!Directory.Exists(RepositoryPath)) + { + Directory.CreateDirectory(RepositoryPath); + } + + XDocument newRepoXML = new XDocument( + new XElement("configuration") + ); + newRepoXML.Save(FullRepositoryPath); + } + catch (Exception e) + { + throw new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Repository store creation failed with error: {0}.", e.Message)); + } + } + + // Open file (which should exist now), if cannot/is corrupted then throw error + try + { + XDocument.Load(FullRepositoryPath); + } + catch (Exception e) + { + throw new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Repository store may be corrupted, file reading failed with error: {0}.", e.Message)); + } + } + + /// + /// Add a repository to the store + /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store + /// + /// + public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriority, bool repoTrusted) + { + Dbg.Assert(!string.IsNullOrEmpty(repoName), "Repository name cannot be null or empty"); + Dbg.Assert(!string.IsNullOrEmpty(repoURL.ToString()), "Repository URL cannot be null or empty"); + + try + { + // Open file + XDocument doc = XDocument.Load(FullRepositoryPath); + if (FindRepositoryElement(doc, repoName) != null) + { + throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); + } + + // Else, keep going + // Get root of XDocument (XElement) + var root = doc.Root; + + // Create new element + XElement newElement = new XElement( + "Repository", + new XAttribute("Name", repoName), + new XAttribute("Url", repoURL), + new XAttribute("Priority", repoPriority), + new XAttribute("Trusted", repoTrusted) + ); + + root.Add(newElement); + + // Close the file + root.Save(FullRepositoryPath); + } + catch (Exception e) + { + throw new PSInvalidOperationException(String.Format("Adding to repository store failed: {0}", e.Message)); + } + + return new PSRepositoryInfo(repoName, repoURL, repoPriority, repoTrusted); + } + + /// + /// Updates a repository name, URL, priority, or installation policy + /// Returns: void + /// + public static void Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted) + { + Dbg.Assert(!string.IsNullOrEmpty(repoName), "Repository name cannot be null or empty"); + + try + { + // Open file + XDocument doc = XDocument.Load(FullRepositoryPath); + XElement node = FindRepositoryElement(doc, repoName); + if (node == null) + { + throw new ArgumentException("Cannot find the repository because it does not exist. Try registering the repository using 'Register-PSResourceRepository'"); + } + + // Else, keep going + // Get root of XDocument (XElement) + var root = doc.Root; + + if (repoURL != null) + { + node.Attribute("Url").Value = repoURL.AbsoluteUri; + } + + if (repoPriority >= 0) + { + node.Attribute("Priority").Value = repoPriority.ToString(); + } + + if (repoTrusted != null) + { + node.Attribute("Trusted").Value = repoTrusted.ToString(); + } + + // Close the file + root.Save(FullRepositoryPath); + } + catch (Exception e) + { + throw new PSInvalidOperationException(String.Format("Updating to repository store failed: {0}", e.Message)); + } + } + + /// + /// Removes a repository from the XML + /// Returns: void + /// + /// + public static void Remove(string[] repoNames, out string[] errorList) + { + List tempErrorList = new List(); + + // Check to see if information we're trying to remove from the repository is valid + if (repoNames == null || repoNames.Length == 0) + { + throw new ArgumentException("Repository name cannot be null or empty"); + } + + XDocument doc; + try + { + // Open file + doc = XDocument.Load(FullRepositoryPath); + } + catch (Exception e) + { + throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); + } + + // Get root of XDocument (XElement) + var root = doc.Root; + + foreach (string repo in repoNames) + { + XElement node = FindRepositoryElement(doc, repo); + if (node == null) + { + tempErrorList.Add(String.Format("Unable to find repository '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); + continue; + } + + // Remove item from file + node.Remove(); + } + + // Close the file + root.Save(FullRepositoryPath); + errorList = tempErrorList.ToArray(); + } + + public static List Read(string[] repoNames, out string[] errorList) + { + List tempErrorList = new List(); + var foundRepos = new List(); + + XDocument doc; + try + { + // Open file + doc = XDocument.Load(FullRepositoryPath); + } + catch (Exception e) + { + throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); + } + + if (repoNames == null || !repoNames.Any() || string.Equals(repoNames[0], "*") || repoNames[0] == null) + { + // Name array or single value is null so we will list all repositories registered + // iterate through the doc + foreach (XElement repo in doc.Descendants("Repository")) + { + if (!Uri.TryCreate(repo.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) + { + tempErrorList.Add(String.Format("Unable to read incorrectly formatted URL for repo {0}", repo.Attribute("Name").Value)); + continue; + } + + PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(repo.Attribute("Name").Value, + thisUrl, + Int32.Parse(repo.Attribute("Priority").Value), + Boolean.Parse(repo.Attribute("Trusted").Value)); + + foundRepos.Add(currentRepoItem); + } + } + + else + { + foreach (string repo in repoNames) + { + bool repoMatch = false; + WildcardPattern nameWildCardPattern = new WildcardPattern(repo, WildcardOptions.IgnoreCase); + + foreach (var node in doc.Descendants("Repository").Where(e => nameWildCardPattern.IsMatch(e.Attribute("Name").Value))) + { + repoMatch = true; + if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) + { + //debug statement + tempErrorList.Add(String.Format("Unable to read incorrectly formatted URL for repo {0}", node.Attribute("Name").Value)); + continue; + } + + PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(node.Attribute("Name").Value, + thisUrl, + Int32.Parse(node.Attribute("Priority").Value), + Boolean.Parse(node.Attribute("Trusted").Value)); + + foundRepos.Add(currentRepoItem); + } + + if (!repo.Contains("*") && !repoMatch) + { + tempErrorList.Add(String.Format("Unable to find repository with Name '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); + } + } + } + + errorList = tempErrorList.ToArray(); + // Sort by priority, then by repo name + var reposToReturn = foundRepos.OrderBy(x => x.Priority).ThenBy(x => x.Name); + return reposToReturn.ToList(); + } + + private static XElement FindRepositoryElement(XDocument doc, string name) + { + return doc.Descendants("Repository").Where( + e => string.Equals( + e.Attribute("Name").Value, + name, + StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + } + } +} diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs new file mode 100644 index 000000000..12afc4e14 --- /dev/null +++ b/src/code/UnregisterPSResourceRepository.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using System; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Unregister-PSResourceRepository cmdlet replaces the Unregister-PSRepository cmdlet from V2. + /// It unregisters a repository for the current user. + /// + + [Cmdlet(VerbsLifecycle.Unregister, + "PSResourceRepository", + SupportsShouldProcess = true, + HelpUri = "")] + public sealed + class UnregisterPSResourceRepository : PSCmdlet + { + #region Parameters + + /// + /// Specifies the desired name for the repository to be registered. + /// + [Parameter(Mandatory= true, Position = 0, + ValueFromPipeline = true, + ValueFromPipelineByPropertyName = true)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } = new string[0]; + + #endregion + + #region Methods + + protected override void BeginProcessing() + { + try + { + WriteDebug("Calling API to check repository store exists in non-corrupted state"); + RepositorySettings.CheckRepositoryStore(); + } + catch (PSInvalidOperationException e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "RepositoryStoreException", + ErrorCategory.ReadError, + this)); + } + } + protected override void ProcessRecord() + { + string nameArrayAsString = string.Join(", ", Name); + WriteDebug(String.Format("removing repository {0}. Calling Remove() API now", nameArrayAsString)); + if (!ShouldProcess(nameArrayAsString, "Unregister repositories from repository store")) + { + return; + } + + RepositorySettings.Remove(Name, out string[] errorList); + + // handle non-terminating errors + foreach (string error in errorList) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorUnregisteringSpecifiedRepo", + ErrorCategory.InvalidOperation, + this)); + } + } + + #endregion + } +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs new file mode 100644 index 000000000..95de2075d --- /dev/null +++ b/src/code/Utils.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation.Language; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + #region Utils + + internal static class Utils + { + #region Members + + public static string TrimQuotes(string name) + { + return name.Trim('\'', '"'); + } + + public static string QuoteName(string name) + { + bool quotesNeeded = false; + foreach (var c in name) + { + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } + } + + if (!quotesNeeded) + { + return name; + } + + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + #endregion + } + + #endregion +} diff --git a/test/GetPSResourceRepository.Tests.ps1 b/test/GetPSResourceRepository.Tests.ps1 new file mode 100644 index 000000000..aa9d4773c --- /dev/null +++ b/test/GetPSResourceRepository.Tests.ps1 @@ -0,0 +1,100 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Register-PSResourceRepository" { + BeforeEach { + Get-NewPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-NewTestDirs($tmpDirPaths) + } + AfterEach { + Get-RevertPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-RemoveTestDirs($tmpDirPaths) + } + + It "get single already registered repo" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + $res = Get-PSResourceRepository -Name "testRepository" + $res | Should -Not -BeNullOrEmpty + $res.Name | Should -Be "testRepository" + } + + It "get all repositories matching single wildcard name" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name "testRepository3" -URL $tmpDir3Path + $res = Get-PSResourceRepository -Name "testReposit*" + foreach ($entry in $res) { + $entry.Name | Should -Match "testReposit" + } + } + + It "get all repositories matching multiple wildcard names" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name "MyGallery" -URL $tmpDir3Path + + $res = Get-PSResourceRepository -Name "testReposit*","*Gallery" + foreach ($entry in $res) { + $entry.Name | Should -Match "testReposit|Gallery" + } + } + + It "get all repositories matching multiple valid names provided" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "MyGallery" -URL $tmpDir2Path + + $res = Get-PSResourceRepository -Name "testRepository","MyGallery" + foreach ($entry in $res) { + $entry.Name | Should -BeIn "testRepository","MyGallery" + } + } + + It "not get repository that hasn't been registered/invalid name" { + $nonRegisteredRepoName = "nonRegisteredRepository" + $res = Get-PSResourceRepository -Name $nonRegisteredRepoName -ErrorVariable err -ErrorAction SilentlyContinue + $res | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" + } + + It "given invalid and valid Names, get valid ones and write error for non valid ones" { + $nonRegisteredRepoName = "nonRegisteredRepository" + + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + + $res = Get-PSResourceRepository -Name "testRepository",$nonRegisteredRepoName,"testRepository2" -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" + + # should have successfully got the other valid/registered repositories with no error + foreach ($entry in $res) { + $entry.Name | Should -BeIn "testRepository","testRepository2" + } + } + + It "throw error and get no repositories when provided null Name" { + # $errorMsg = "Cannot validate argument on parameter 'Name'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again." + {Get-PSResourceRepository -Name $null -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" + } + + It "throw error and get no repositories when provided empty string Name" { + # $errorMsg = "Cannot validate argument on parameter 'Name'. The argument is null, empty, or an element of the argument collection contains a null value. Supply a collection that does not contain any null values and then try the command again." + {Get-PSResourceRepository -Name "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" + } + + It "find all repositories if no Name provided" { + $res = Get-PSResourceRepository + $res.Count | Should -BeGreaterThan 0 + } +} diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 new file mode 100644 index 000000000..ca57a7294 --- /dev/null +++ b/test/PSGetTestUtils.psm1 @@ -0,0 +1,452 @@ +<##################################################################################### + # File: PSGetTestUtils.psm1 + # + # Copyright (c) Microsoft Corporation, 2020 + #####################################################################################> + +#."$PSScriptRoot\uiproxy.ps1" + +$psGetMod = Get-Module -Name PowerShellGet +if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) +{ + Write-Verbose -Message "Importing PowerShellGet 3.0.0 for test" -Verbose + Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force +} + +$script:DotnetCommandPath = @() +$script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 } +$script:EnvPATHValueBackup = $null + +$script:PowerShellGet = 'PowerShellGet' +$script:IsInbox = $PSHOME.EndsWith('\WindowsPowerShell\v1.0', [System.StringComparison]::OrdinalIgnoreCase) +$script:IsWindows = (-not (Get-Variable -Name IsWindows -ErrorAction Ignore)) -or $IsWindows +$script:IsLinux = (Get-Variable -Name IsLinux -ErrorAction Ignore) -and $IsLinux +$script:IsMacOS = (Get-Variable -Name IsMacOS -ErrorAction Ignore) -and $IsMacOS +$script:IsCoreCLR = $PSVersionTable.ContainsKey('PSEdition') -and $PSVersionTable.PSEdition -eq 'Core' + +$script:PSGalleryName = 'PSGallery' +$script:PSGalleryLocation = 'https://www.powershellgallery.com/api/v2' + +$script:PoshTestGalleryName = 'PoshTestGallery' +$script:PostTestGalleryLocation = 'https://www.poshtestgallery.com/api/v2' + +if($script:IsInbox) +{ + $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell" +} +elseif($script:IsCoreCLR){ + if($script:IsWindows) { + $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath 'PowerShell' + } + else { + $script:ProgramFilesPSPath = Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('SHARED_MODULES')) -Parent + } +} + +try +{ + $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments") +} +catch +{ + $script:MyDocumentsFolderPath = $null +} + +if($script:IsInbox) +{ + $script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) + { + Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath "WindowsPowerShell" + } + else + { + Microsoft.PowerShell.Management\Join-Path -Path $env:USERPROFILE -ChildPath "Documents\WindowsPowerShell" + } +} +elseif($script:IsCoreCLR) { + if($script:IsWindows) + { + $script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) + { + Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath 'PowerShell' + } + else + { + Microsoft.PowerShell.Management\Join-Path -Path $HOME -ChildPath "Documents\PowerShell" + } + } + else + { + $script:MyDocumentsPSPath = Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('USER_MODULES')) -Parent + } +} + +$script:ProgramFilesModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath 'Modules' +$script:MyDocumentsModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath 'Modules' +$script:ProgramFilesScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath 'Scripts' +$script:MyDocumentsScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath 'Scripts' +$script:TempPath = [System.IO.Path]::GetTempPath() + +if($script:IsWindows) { + $script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' + $script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' +} else { + $script:PSGetProgramDataPath = Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CONFIG')) -ChildPath 'PowerShellGet' + $script:PSGetAppLocalPath = Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CACHE')) -ChildPath 'PowerShellGet' +} + +$script:ProgramDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetProgramDataPath -ChildPath $script:NuGetExeName +$script:ApplocalDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath $script:NuGetExeName +$script:moduleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath 'PSRepositories.xml' + +# PowerShellGetFormatVersion will be incremented when we change the .nupkg format structure. +# PowerShellGetFormatVersion is in the form of Major.Minor. +# Minor is incremented for the backward compatible format change. +# Major is incremented for the breaking change. +$script:CurrentPSGetFormatVersion = "1.0" +$script:PSGetFormatVersionPrefix = "PowerShellGetFormatVersion_" + +function Get-AllUsersModulesPath { + return $script:ProgramFilesModulesPath +} + +function Get-CurrentUserModulesPath { + return $script:MyDocumentsModulesPath +} + +function Get-AllUsersScriptsPath { + return $script:ProgramFilesScriptsPath +} + +function Get-CurrentUserScriptsPath { + return $script:MyDocumentsScriptsPath +} + +function Get-TempPath { + return $script:TempPath +} + +function Get-PSGetLocalAppDataPath { + return $script:PSGetAppLocalPath +} + +function Get-PSGalleryName +{ + return $script:PSGalleryName +} + +function Get-PSGalleryLocation { + return $script:PSGalleryLocation +} + +function Get-PoshTestGalleryName { + return $script:PoshTestGalleryName +} + +function Get-PoshTestGalleryLocation { + return $script:PostTestGalleryLocation +} + +function Get-NewTestDirs { + Param( + [string[]] + $listOfPaths + ) + foreach($path in $listOfPaths) + { + $null = New-Item -Path $path -ItemType Directory + } +} + +function Get-RemoveTestDirs { + Param( + [string[]] + $listOfPaths + ) + foreach($path in $listOfPaths) + { + if(Test-Path -Path $path) + { + Remove-Item -Path $path -Force -ErrorAction Ignore + } + } +} +function Get-NewPSResourceRepositoryFile { + # register our own repositories with desired priority + $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" + $originalXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" + $tempXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "temp.xml" + + if (Test-Path -Path $originalXmlFilePath) { + Copy-Item -Path $originalXmlFilePath -Destination $tempXmlFilePath + Remove-Item -Path $originalXmlFilePath -Force -ErrorAction Ignore + } + + if (! (Test-Path -Path $powerShellGetPath)) { + $null = New-Item -Path $powerShellGetPath -ItemType Directory -Verbose + } + + $fileToCopy = Join-Path -Path $PSScriptRoot -ChildPath "testRepositories.xml" + Copy-Item -Path $fileToCopy -Destination $originalXmlFilePath -Force -Verbose +} + +function Get-RevertPSResourceRepositoryFile { + $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" + $originalXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" + $tempXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "temp.xml" + + if (Test-Path -Path $tempXmlFilePath) { + Remove-Item -Path $originalXmlFilePath -Force -ErrorAction Ignore + Copy-Item -Path $tempXmlFilePath -Destination $originalXmlFilePath -Force + Remove-Item -Path $tempXmlFilePath -Force -ErrorAction Ignore + } +} + +function Get-TestDriveSetUp +{ + $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" + $null = New-Item $repoURLAddress -ItemType Directory -Force + + Set-PSResourceRepository -Name "psgettestlocal" -URL $repoURLAddress + + $testResourcesFolder = Join-Path $TestDrive -ChildPath "TestLocalDirectory" + + $script:testIndividualResourceFolder = Join-Path -Path $testResourcesFolder -ChildPath "PSGet_$(Get-Random)" + $null = New-Item -Path $testIndividualResourceFolder -ItemType Directory -Force +} + +function Get-RoleCapabilityResourcePublishedToLocalRepoTestDrive +{ + Param( + [string] + $roleCapName + ) + + Get-TestDriveSetUp + + $publishModuleName = $roleCapName + $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName + $null = New-Item -Path $publishModuleBase -ItemType Directory -Force + + $version = "1.0" + New-PSRoleCapabilityFile -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psrc") + New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" -DscResourcesToExport @('DefaultGatewayAddress', 'WINSSetting') -Tags @('PSDscResource_', 'DSC') + + Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal +} + +function Get-DSCResourcePublishedToLocalRepoTestDrive +{ + Param( + [string] + $dscName + ) + + Get-TestDriveSetUp + + $publishModuleName = $dscName + $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName + $null = New-Item -Path $publishModuleBase -ItemType Directory -Force + + $version = "1.0" + New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" -DscResourcesToExport @('DefaultGatewayAddress', 'WINSSetting') -Tags @('PSDscResource_', 'DSC') + + Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal +} + +function Get-ScriptResourcePublishedToLocalRepoTestDrive +{ + Param( + [string] + $scriptName + ) + Get-TestDriveSetUp + + $scriptFilePath = Join-Path -Path $script:testIndividualResourceFolder -ChildPath "$scriptName.ps1" + $null = New-Item -Path $scriptFilePath -ItemType File -Force + + $version = "1.0.0" + $params = @{ + #Path = $scriptFilePath + Version = $version + #GUID = + Author = 'Jane' + CompanyName = 'Microsoft Corporation' + Copyright = '(c) 2020 Microsoft Corporation. All rights reserved.' + Description = "Description for the $scriptName script" + LicenseUri = "https://$scriptName.com/license" + IconUri = "https://$scriptName.com/icon" + ProjectUri = "https://$scriptName.com" + Tags = @('Tag1','Tag2', "Tag-$scriptName-$version") + ReleaseNotes = "$scriptName release notes" + } + + $scriptMetadata = Create-PSScriptMetadata @params + Set-Content -Path $scriptFilePath -Value $scriptMetadata + + Publish-PSResource -path $scriptFilePath -Repository psgettestlocal +} + +function Get-CommandResourcePublishedToLocalRepoTestDrive +{ + Param( + [string] + $cmdName + ) + Get-TestDriveSetUp + + $publishModuleName = $cmdName + $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName + $null = New-Item -Path $publishModuleBase -ItemType Directory -Force + + $version = "1.0" + New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" -CmdletsToExport @('Get-Test', 'Set-Test') + + Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal +} + +function Get-ModuleResourcePublishedToLocalRepoTestDrive +{ + Param( + [string] + $moduleName + ) + Get-TestDriveSetUp + + $publishModuleName = $moduleName + $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName + $null = New-Item -Path $publishModuleBase -ItemType Directory -Force + + $version = "1.0" + New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" + + Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal +} + +function RemoveItem +{ + Param( + [string] + $path + ) + + if($path -and (Test-Path $path)) + { + Remove-Item $path -Force -Recurse -ErrorAction SilentlyContinue + } +} + +function Create-PSScriptMetadata +{ + [OutputType([String])] + [CmdletBinding(PositionalBinding=$false, + SupportsShouldProcess=$true)] + + Param + ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Version, + + [Parameter()] + #[ValidateNotNullOrEmpty()] + [Guid] + $Guid, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $Author, + + [Parameter()] + [String] + $CompanyName, + + [Parameter()] + [string] + $Copyright, + + [Parameter()] + [string] + $Description, + + [Parameter()] + [String[]] + $ExternalModuleDependencies, + + [Parameter()] + [string[]] + $RequiredScripts, + + [Parameter()] + [String[]] + $ExternalScriptDependencies, + + [Parameter()] + [string[]] + $Tags, + + [Parameter()] + [Uri] + $ProjectUri, + + [Parameter()] + [Uri] + $LicenseUri, + + [Parameter()] + [Uri] + $IconUri, + + [Parameter()] + [string[]] + $ReleaseNotes, + + [Parameter()] + [string] + $PrivateData + ) + + Process + { + $PSScriptInfoString = @" + +<#PSScriptInfo + +.VERSION$(if ($Version) {" $Version"}) + +.GUID$(if ($Guid) {" $Guid"}) + +.AUTHOR$(if ($Author) {" $Author"}) + +.COMPANYNAME$(if ($CompanyName) {" $CompanyName"}) + +.COPYRIGHT$(if ($Copyright) {" $Copyright"}) + +.DESCRIPTION$(if ($Description) {" $Description"}) + +.TAGS$(if ($Tags) {" $Tags"}) + +.LICENSEURI$(if ($LicenseUri) {" $LicenseUri"}) + +.PROJECTURI$(if ($ProjectUri) {" $ProjectUri"}) + +.ICONURI$(if ($IconUri) {" $IconUri"}) + +.EXTERNALMODULEDEPENDENCIES$(if ($ExternalModuleDependencies) {" $($ExternalModuleDependencies -join ',')"}) + +.REQUIREDSCRIPTS$(if ($RequiredScripts) {" $($RequiredScripts -join ',')"}) + +.EXTERNALSCRIPTDEPENDENCIES$(if ($ExternalScriptDependencies) {" $($ExternalScriptDependencies -join ',')"}) + +.RELEASENOTES +$($ReleaseNotes -join "`r`n") + +.PRIVATEDATA$(if ($PrivateData) {" $PrivateData"}) + +#> +"@ + return $PSScriptInfoString + } +} diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 new file mode 100644 index 000000000..58c1e4c90 --- /dev/null +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -0,0 +1,221 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Register-PSResourceRepository" { + BeforeEach { + $PSGalleryName = Get-PSGalleryName + $PSGalleryURL = Get-PSGalleryLocation + Get-NewPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-NewTestDirs($tmpDirPaths) + } + AfterEach { + Get-RevertPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-RemoveTestDirs($tmpDirPaths) + } + + It "register repository given Name, URL (bare minimum for NameParmaterSet)" { + $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -PassThru + $res.Name | Should -Be "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Trusted | Should -Be False + $res.Priority | Should -Be 50 + } + + It "register repository with Name, URL, Trusted (NameParameterSet)" { + $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -Trusted -PassThru + $res.Name | Should -Be "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Trusted | Should -Be True + $res.Priority | Should -Be 50 + } + + It "register repository given Name, URL, Trusted, Priority (NameParameterSet)" { + $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -Trusted -Priority 20 -PassThru + $res.Name | Should -Be "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Trusted | Should -Be True + $res.Priority | Should -Be 20 + } + + It "register repository with PSGallery parameter (PSGalleryParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + $res = Register-PSResourceRepository -PSGallery -PassThru + $res.Name | Should -Be $PSGalleryName + $res.URL | Should -Be $PSGalleryURL + $res.Trusted | Should -Be False + $res.Priority | Should -Be 50 + } + + It "register repository with PSGallery, Trusted parameters (PSGalleryParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + $res = Register-PSResourceRepository -PSGallery -Trusted -PassThru + $res.Name | Should -Be $PSGalleryName + $res.URL | Should -Be $PSGalleryURL + $res.Trusted | Should -Be True + $res.Priority | Should -Be 50 + } + + It "register repository with PSGallery, Trusted, Priority parameters (PSGalleryParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + $res = Register-PSResourceRepository -PSGallery -Trusted -Priority 20 -PassThru + $res.Name | Should -Be $PSGalleryName + $res.URL | Should -Be $PSGalleryURL + $res.Trusted | Should -Be True + $res.Priority | Should -Be 20 + } + + It "register repositories with Repositories parameter, all name parameter style repositories (RepositoriesParameterSet)" { + $hashtable1 = @{Name = "testRepository"; URL = $tmpDir1Path} + $hashtable2 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} + $hashtable3 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3 + + Register-PSResourceRepository -Repositories $arrayOfHashtables + $res = Get-PSResourceRepository -Name "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Trusted | Should -Be False + $res.Priority | Should -Be 50 + + $res2 = Get-PSResourceRepository -Name "testRepository2" + $res2.URL | Should -Contain $tmpDir2Path + $res2.Trusted | Should -Be True + $res2.Priority | Should -Be 50 + + $res3 = Get-PSResourceRepository -Name "testRepository3" + $res3.URL | Should -Contain $tmpDir3Path + $res3.Trusted | Should -Be True + $res3.Priority | Should -Be 20 + } + + It "register repositories with Repositories parameter, psgallery style repository (RepositoriesParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + $hashtable1 = @{PSGallery = $True} + Register-PSResourceRepository -Repositories $hashtable1 + $res = Get-PSResourceRepository -Name $PSGalleryName + $res.URL | Should -Be $PSGalleryURL + $res.Trusted | Should -Be False + $res.Priority | Should -Be 50 + } + + It "register repositories with Repositories parameter, name and psgallery parameter styles (RepositoriesParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + $hashtable1 = @{PSGallery = $True} + $hashtable2 = @{Name = "testRepository"; URL = $tmpDir1Path} + $hashtable3 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} + $hashtable4 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 + + Register-PSResourceRepository -Repositories $arrayOfHashtables + + $res1 = Get-PSResourceRepository -Name $PSGalleryName + $res1.URL | Should -Be $PSGalleryURL + $res1.Trusted | Should -Be False + $res1.Priority | Should -Be 50 + + $res2 = Get-PSResourceRepository -Name "testRepository" + $res2.URL | Should -Contain $tmpDir1Path + $res2.Trusted | Should -Be False + $res2.Priority | Should -Be 50 + + $res3 = Get-PSResourceRepository -Name "testRepository2" + $res3.URL | Should -Contain $tmpDir2Path + $res3.Trusted | Should -Be True + $res3.Priority | Should -Be 50 + + $res4 = Get-PSResourceRepository -Name "testRepository3" + $res4.URL | Should -Contain $tmpDir3Path + $res4.Trusted | Should -Be True + $res4.Priority | Should -Be 20 + } + + It "not register repository when Name is provided but URL is not" { + {Register-PSResourceRepository -Name "testRepository" -URL "" -ErrorAction Stop} | Should -Throw -ErrorId "InvalidUrl,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + } + + It "not register repository when Name is empty but URL is provided" { + {Register-PSResourceRepository -Name "" -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + } + + It "not register rpeository when Name is null but URL is provided" { + {Register-PSResourceRepository -Name $null -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + } + + It "not register repository when Name is just whitespace but URL is provided" { + {Register-PSResourceRepository -Name " " -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + } + + It "not register PSGallery with NameParameterSet" { + {Register-PSResourceRepository -Name $PSGalleryName -URL $PSGalleryURL -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + } + + # this error message comes from the parameter cmdlet tags (earliest point of detection) + It "not register PSGallery when PSGallery parameter provided with Name or URL" { + {Register-PSResourceRepository -PSGallery -Name $PSGalleryName -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + {Register-PSResourceRepository -PSGallery -URL $PSGalleryURL -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + } + + $testCases = @{Type = "Name key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; Name=$PSGalleryName}}, + @{Type = "URL key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; URL=$PSGalleryURL}} + + It "not register incorrectly formatted PSGallery type repo among correct ones when incorrect type is " -TestCases $testCases { + param($Type, $IncorrectHashTable) + + $correctHashtable1 = @{Name = "testRepository"; URL = $tmpDir1Path} + $correctHashtable2 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} + $correctHashtable3 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + + Unregister-PSResourceRepository -Name "PSGallery" + Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUrlForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + + $res = Get-PSResourceRepository -Name "testRepository" + $res.Name | Should -Be "testRepository" + + $res2 = Get-PSResourceRepository -Name "testRepository2" + $res2.Name | Should -Be "testRepository2" + + $res3 = Get-PSResourceRepository -Name "testRepository3" + $res3.Name | Should -Be "testRepository3" + } + + $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = "PSGallery"; URL = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-URL not specified"; IncorrectHashTable = @{Name = "testRepository"}; ErrorId = "NullURLForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = "testRepository"; URL="www.google.com"}; ErrorId = "InvalidUrlScheme,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + + It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { + param($Type, $IncorrectHashTable, $ErrorId) + + $correctHashtable1 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name "PSGallery" + Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly $ErrorId + + $res = Get-PSResourceRepository -Name "testRepository2" + $res.Name | Should -Be "testRepository2" + + $res2 = Get-PSResourceRepository -Name "testRepository3" + $res2.Name | Should -Be "testRepository3" + + $res3 = Get-PSResourceRepository -Name "PSGallery" + $res3.Name | Should -Be "PSGallery" + $res3.Priority | Should -Be 30 + } +} diff --git a/test/UnregisterPSResourceRepository.Tests.ps1 b/test/UnregisterPSResourceRepository.Tests.ps1 new file mode 100644 index 000000000..4359c4be9 --- /dev/null +++ b/test/UnregisterPSResourceRepository.Tests.ps1 @@ -0,0 +1,62 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Register-PSResourceRepository" { + BeforeEach { + Get-NewPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-NewTestDirs($tmpDirPaths) + } + AfterEach { + Get-RevertPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-RemoveTestDirs($tmpDirPaths) + } + + It "unregister single repository previously registered" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Unregister-PSResourceRepository -Name "testRepository" + + $res = Get-PSResourceRepository -Name "testRepository" -ErrorVariable err -ErrorAction SilentlyContinue + $res | Should -BeNullOrEmpty + } + + It "unregister multiple repositories previously registered" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Unregister-PSResourceRepository -Name "testRepository","testRepository2" + + $res = Get-PSResourceRepository -Name "testRepository","testRepository2" -ErrorVariable err -ErrorAction SilentlyContinue + $res | Should -BeNullOrEmpty + } + + It "not unregister repo not previously registered and throw expected error message" { + $name = "nonRegisteredRepository" + {Unregister-PSResourceRepository -Name $name -ErrorAction Stop} | Should -Throw -ErrorId "ErrorUnregisteringSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" + + } + + It "when multiple repo Names provided, if one name isn't valid unregister the rest and write error message" { + $nonRegisteredRepoName = "nonRegisteredRepository" + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Unregister-PSResourceRepository -Name $nonRegisteredRepoName,"testRepository" -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorUnregisteringSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" + } + + It "throw error if Name is null or empty" { + {Unregister-PSResourceRepository -Name "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" + } + + It "throw error if Name is null" { + {Unregister-PSResourceRepository -Name $null -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" + } +} diff --git a/test/testRepositories.xml b/test/testRepositories.xml new file mode 100644 index 000000000..5f186d004 --- /dev/null +++ b/test/testRepositories.xml @@ -0,0 +1,6 @@ + + + + + + From 04e335f2d5ab9ea01bda12aa82b3916dc459cf57 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 8 Apr 2021 13:56:33 -0400 Subject: [PATCH 002/276] Add help docs for unregister, register, get -psresourcerepository (#355) * add help docs for unregister, register, get -psresourcerepository cmdlets * fix synopsis for Register help doc * minor formatting issue * resolve current user related feedback in Get-PSResourceRepository.md * changes powershell modules to powershell resources * resolved feedback to Register-PSResourceRepository.md * resolve feedback on Unregister-PSResourceRepository.md * remove current user references * change description for Repositories param * fix codacy issue --- help/Get-PSResourceRepository.md | 95 +++++++------- help/Register-PSResourceRepository.md | 160 ++++++++++++------------ help/Unregister-PSResourceRepository.md | 53 +++++--- 3 files changed, 164 insertions(+), 144 deletions(-) diff --git a/help/Get-PSResourceRepository.md b/help/Get-PSResourceRepository.md index 0530f6231..cb3f7e77f 100644 --- a/help/Get-PSResourceRepository.md +++ b/help/Get-PSResourceRepository.md @@ -1,95 +1,100 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- # Get-PSResourceRepository ## SYNOPSIS -{{ Fill in the Synopsis }} +Finds and returns registered repository information. ## SYNTAX ``` -Get-PSResourceRepository [[-Name] ] [-WhatIf] [-Confirm] [] +Get-PSResourceRepository [[-Name] ] [] ``` ## DESCRIPTION -{{ Fill in the Description }} +The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the -Name parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. ## EXAMPLES ### Example 1 -```powershell -PS C:\> {{ Add example code here }} +``` +PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 ``` -{{ Add example description here }} +This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. -## PARAMETERS +### Example 2 +``` +PS C:\> Get-PSResourceRepository -Name "*Gallery" + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 -### -Name -{{ Fill Name Description }} +``` -```yaml -Type: System.String[] -Parameter Sets: (All) -Aliases: +This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. -Required: False -Position: 0 -Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False +### Example 3 ``` +PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 -### -Confirm -Prompts you for confirmation before running the cmdlet. +``` -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: cf +This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + +### Example 4 +``` +PS C:\> Get-PSResourceRepository -Name "*" + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False ``` -### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. +This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. + +## PARAMETERS + +### -Name +This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: String[] Parameter Sets: (All) -Aliases: wi +Aliases: Required: False -Position: Named +Position: 0 Default value: None -Accept pipeline input: False -Accept wildcard characters: False +Accept pipeline input: True (ByPropertyName, ByValue) +Accept wildcard characters: True ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ### System.String[] - ## OUTPUTS -### System.Object - +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo ## NOTES +If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. ## RELATED LINKS - -[]() - diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index ed2cbbd8d..698267ab3 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -1,69 +1,82 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- # Register-PSResourceRepository ## SYNOPSIS -{{ Fill in the Synopsis }} +Registers a repository for PowerShell resources. ## SYNTAX ### NameParameterSet (Default) ``` -Register-PSResourceRepository [-Name] [-URL] [-Credential ] [-Trusted] - [-Proxy ] [-ProxyCredential ] [-Priority ] [-WhatIf] [-Confirm] [] +Register-PSResourceRepository [-Name] [-URL] [-Trusted] [-Priority ] [-PassThru] + [-WhatIf] [-Confirm] [] ``` ### PSGalleryParameterSet ``` -Register-PSResourceRepository [-PSGallery] [-Trusted] [-Proxy ] [-ProxyCredential ] - [-Priority ] [-WhatIf] [-Confirm] [] +Register-PSResourceRepository [-PSGallery] [-Trusted] [-Priority ] [-PassThru] [-WhatIf] [-Confirm] + [] ``` ### RepositoriesParameterSet ``` -Register-PSResourceRepository -Repositories - [-Proxy ] [-ProxyCredential ] [-WhatIf] [-Confirm] [] +Register-PSResourceRepository -Repositories [-PassThru] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -{{ Fill in the Description }} +The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. ## EXAMPLES - +These examples assume that the repository we attempt to reigster is not already registered on the user's machine. ### Example 1 -```powershell -PS C:\> {{ Add example code here }} +``` +PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -URL "https://www.powershellgallery.com/api/v2" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 ``` -{{ Add example description here }} +This example registers the repository with the 'Name' of "PoshTestGallery" along with the associated 'URL' value for it. -## PARAMETERS +### Example 2 +``` +PS C:\> Register-PSResourceRepository -PSGallery +PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 +``` -### -Credential -{{ Fill Credential Description }} +This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the 'Name' or 'URL' parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for URL. -```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: NameParameterSet -Aliases: +### Example 3 +``` +PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; URL = "c:/code/testdir"},@{PSGallery = $True} +PS C:\> Register-PSResourceRepository -Repositories $arrayOfHashtables +PS C:\> Get-PSResourceRepository + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir False 50 -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False ``` +This example registers multiple repositories at once. To do so, we use the 'Repositories' parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. + +## PARAMETERS + ### -Name -{{ Fill Name Description }} +Name of the repository to be registered. ```yaml -Type: System.String +Type: String Parameter Sets: NameParameterSet Aliases: @@ -75,100 +88,72 @@ Accept wildcard characters: False ``` ### -Priority -{{ Fill Priority Description }} +Specifies the priority ranking of the repository. +Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. ```yaml -Type: System.Int32 +Type: Int32 Parameter Sets: NameParameterSet, PSGalleryParameterSet Aliases: Required: False Position: Named -Default value: None +Default value: 50 Accept pipeline input: False Accept wildcard characters: False ``` -### -Proxy -{{ Fill Proxy Description }} - -```yaml -Type: System.Uri -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False -``` - -### -ProxyCredential -{{ Fill ProxyCredential Description }} - -```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False -``` - ### -PSGallery -{{ Fill PSGallery Description }} +When specified, registers PSGallery repository. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: SwitchParameter Parameter Sets: PSGalleryParameterSet Aliases: Required: True Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Repositories -{{ Fill Repositories Description }} +Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. ```yaml -Type: System.Collections.Generic.List`1[System.Collections.Hashtable] +Type: Hashtable[] Parameter Sets: RepositoriesParameterSet Aliases: Required: True Position: Named Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` ### -Trusted -{{ Fill Trusted Description }} +Specifies whether the repository should be trusted. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: SwitchParameter Parameter Sets: NameParameterSet, PSGalleryParameterSet Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -URL -{{ Fill URL Description }} +Specifies the location of the repository to be registered. +URL can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. ```yaml -Type: System.Uri +Type: Uri Parameter Sets: NameParameterSet Aliases: @@ -183,13 +168,13 @@ Accept wildcard characters: False Prompts you for confirmation before running the cmdlet. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` @@ -199,10 +184,25 @@ Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: SwitchParameter Parameter Sets: (All) Aliases: wi +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PassThru +When specified, displays the succcessfully registered repository and its information. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + Required: False Position: Named Default value: None @@ -215,17 +215,13 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS -### System.Management.Automation.PSCredential - +### System.String ### System.Uri - ## OUTPUTS -### System.Object - +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) ## NOTES +Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. +Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'URL' parameters). ## RELATED LINKS - -[]() - diff --git a/help/Unregister-PSResourceRepository.md b/help/Unregister-PSResourceRepository.md index 65fec7043..e875af838 100644 --- a/help/Unregister-PSResourceRepository.md +++ b/help/Unregister-PSResourceRepository.md @@ -1,14 +1,14 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- # Unregister-PSResourceRepository ## SYNOPSIS -{{ Fill in the Synopsis }} +Un-registers a repository from the repository store. ## SYNTAX @@ -17,24 +17,47 @@ Unregister-PSResourceRepository [-Name] [-WhatIf] [-Confirm] [ {{ Add example code here }} ``` +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> -{{ Add example description here }} +``` + +In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. + +### Example 2 +``` +PS C:\> Get-PSResourceRepository + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 + +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" +PS C:\> Get-PSResourceRepository + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + +``` + +In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the 'Name' parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. ## PARAMETERS ### -Name -{{ Fill Name Description }} +This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. ```yaml -Type: System.String[] +Type: String[] Parameter Sets: (All) Aliases: @@ -49,13 +72,13 @@ Accept wildcard characters: False Prompts you for confirmation before running the cmdlet. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` @@ -65,13 +88,13 @@ Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` @@ -82,13 +105,9 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS ### System.String[] - ## OUTPUTS -### System.Object +None ## NOTES ## RELATED LINKS - -[]() - From a332412a5b5555ef1b4e4aa00ab8c6fbce722813 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 15 Apr 2021 11:48:08 -0700 Subject: [PATCH 003/276] Adding cmdlets to design doc (#331) --- Docs/GetPSResource.md | 148 ++++++++++++++++++++ Docs/InstallPSResource.md | 263 ++++++++++++++++++++++++++++++++++++ Docs/SavePSResource.md | 205 ++++++++++++++++++++++++++++ Docs/UninstallPSResource.md | 101 ++++++++++++++ Docs/UpdatePSResource.md | 243 +++++++++++++++++++++++++++++++++ 5 files changed, 960 insertions(+) create mode 100644 Docs/GetPSResource.md create mode 100644 Docs/InstallPSResource.md create mode 100644 Docs/SavePSResource.md create mode 100644 Docs/UninstallPSResource.md create mode 100644 Docs/UpdatePSResource.md diff --git a/Docs/GetPSResource.md b/Docs/GetPSResource.md new file mode 100644 index 000000000..98414aec6 --- /dev/null +++ b/Docs/GetPSResource.md @@ -0,0 +1,148 @@ +# Get-InstalledPSResource + +The `Get-InstalledPSResource` cmdlet combines the `Get-InstalledModule, Get-InstalledScript` cmdlets from V2. +It performs a search within module or script installation paths based on the `-Name` parameter argument. +It returns `PSRepositoryItemInfo` objects which describe each resource item found. +Other parameters allow the returned results to be filtered by version, prerelease version, and path. + +## Syntax + +### NameParameterSet (Default) +``` PowerShell +[[-Name] ] [-Version ] [-Type ] [-Prerelease] [-Path ] [-WhatIf] [-Confirm] [] +``` + + +## Parameters + +### -Name + +Name of a resource or resources to find. +Accepts wild card characters. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Version + +Specifies the version of the resource to be returned. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + +### -Type + +Specifies one or more resource types to find. +Two resource types are supported: Module and Script. + +```yml +Type: string[] +Parameter Sets: ResourceNameParameterSet +AllowedValues: 'Module','Script' +``` + +### -Prerelease + +When specified, includes prerelease versions in search. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + +### -Path + +Specifies the path to search in. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + + +### Outputs + +```json +"PSRepositoryItemInfo" : { + "Name", + "Version", + "Type", + "Description", + "Author", + "CompanyName", + "Copyright", + "PublishedDate", + "InstalledDate", + "UpdatedDate", + "LicenseUri", + "ProjectUri", + "IconUri", + "Tags", + "Includes", + "PowerShellGetFormatVersion", + "ReleaseNotes", + "Dependencies", + "RepositorySourceLocation", + "Repository", + "PackageManagementProvider", + "AdditionalMetadata" +} +``` + +## Notes + +Currently the `-Prerelease` parameter is not implemented. + +Add why + +## Tests + +Most search tests can be performed on a local file system. + +### -Name param + +- Single name search +- Wildcard search +- Multiple name search +- Cancel search +- Errors: Not found (single name, wildcard, multiple name) +- Errors: File path: Invalid name, cannot find, etc + +### -Version param + +- Validate correct resource version returned +- Validate wild card (if supported), correct version range returned +- Errors: Not found +- Errors: Invalid version string format + +### -Prerelease param + +- Validate prerelease version returned + +### -Path param + +- Single path search +- OneDrive path search +- Errors: Path not found + +## Work Items + +### Create cmdlet and parameter sets + +Create cmdlet class, parameters, and functional stubs +2 days + +### Create test support + +Create any test repositories and mocks for tests +4 days + +### Write cmdlet tests + +Create all functional tests to validate cmdlet +5 days + diff --git a/Docs/InstallPSResource.md b/Docs/InstallPSResource.md new file mode 100644 index 000000000..b9a946204 --- /dev/null +++ b/Docs/InstallPSResource.md @@ -0,0 +1,263 @@ +# Install-PSResource + +The `Install-PSResource` cmdlet combines the `Install-Module, Install-Script` cmdlets from V2. +It performs an installation from a package found on a repository (local or remote) based on the `-Name` parameter argument. +It does not return an object. +Other parameters allow the returned results to be further filtered. + +## Syntax + +### NameParameterSet (Default) +``` PowerShell +[[-Name] ] [-Version ] [-Prerelease] [-Repository ] +[-Credential ] [-Scope ] [-NoClobber] [-TrustRepository] +[-Reinstall] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] [] +``` +### InputObjectParameterSet +``` PowerShell +[[-InputObject] ] +``` +### RequiredResourceParameterSet +``` PowerShell +[[-RequiredResource] ] [-Quiet] [-WhatIf] [-Confirm] [] +``` +### RequiredResourceFileParameterSet +``` PowerShell +[[-RequiredResourceFile] ] [-Quiet] [-WhatIf] [-Confirm] [] +``` + +## Parameters + +### -Name + +Name of a resource or resources to be installed. +Accepts wild card characters. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Version + +Specifies the version or version range of the resource to be installed. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + +### -Prerelease + +When specified, allows installation of prerelease versions. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -Repository + +Specifies one or more repository names to search. +If not specified, search will the highest priority repository. + +```yml +Type: string[] +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -Credential + +Optional credentials to be used when accessing a private repository. + +```yml +Type: PSCredential +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -Scope + +When specified, will install to either CurrentUser or AllUsers scope. + +```yml +Type: String +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +AllowedValues: 'CurrentUser','AllUsers' +``` + +### -NoClobber + +Prevents installing modules that have the same cmdlets as a differently named module already installed. + +```yml +Type: string[] +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -TrustRepository + +If specified, suppresses prompt for untrusted repositories. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -Reinstall + +If specified, overwrites a previously installed resource with the same name and version. + +```yml +Type: string +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -Quiet + +If specified, suppresses progress information. + +```yml +Type: string +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -AcceptLicense + +If specified, modules that require a license agreement will be automatically accepted during installation. + +```yml +Type: string +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -RequiredResourceFile + +Specifies a file + +```yml +Type: string +Parameter Sets: RequiredResourceFileParameterSet +``` + +### -RequiredResourceJSON + +Installs the resources specified in the json configuration. + +```yml +Type: string or hashtable +Parameter Sets: RequiredResourceParameterSet +``` + +### -InputObject + +Installs the resources passed in via pipeline. + +```yml +Type: ? +Parameter Sets: InputObjectParameterSet +``` + +### Outputs + +No output. + +## Notes + + +### -Name param + +- Single name search +- Wildcard search +- Multiple name search +- Cancel search +- Errors: Not found (single name, wildcard, multiple name) +- Errors: Repository: Invalid name, connection error, etc + +### -Version param + +- Validate correct resource version installed +- Validate wild card (if supported), correct version range installed +- Errors: Not found +- Errors: Invalid version string format + +### -Prerelease param + +- Validate prerelease version installed + +### -Repository param + +- All repository search +- Single repository search +- Multiple repository search +- Errors: Repository not found + +### -Credential param + +- Validate credential search +- Errors: Credential: Invalid + +### -Scope param + +- Validate installation to correct scope (both current and all users) + +### -NoClobber param + +- Validate proper warning message if clobbering will happen + +### -TrustRepository param + +- Validate that user is not prompted and has access to repository + +### -Reinstall param + +- Validate proper installation when the module version is already installed +- Validate proper installation if resource is not installed + +### -Quiet param + +- Validate that progress bar is supressed + +### -AcceptLicense param + +- Validate that there is no prompt for modules that require license agreement + +### -RequiredResourceFile param + +- + +### -RequiredResourceJSON param + +- Validate that installation works with hashtable input +- Validate that installation works with string input +- Validate that all parameters work in string or hashtable +- Error: incorrect formatting +- Error: incorrect object type + +### -InputObject param + +- Validate that object passed in is able to install + + +## Work Items + +### Create cmdlet and parameter sets + +Create cmdlet class, parameters, and functional stubs +1 day + +### Implement package install helpers + +Create helper functions that support all search functions +Use existing code as starting point +4 days + +### Create test support + +Create any test repositories and mocks for tests +4 days + +### Write cmdlet tests + +Create all functional tests to validate cmdlet +5 days + diff --git a/Docs/SavePSResource.md b/Docs/SavePSResource.md new file mode 100644 index 000000000..741e94002 --- /dev/null +++ b/Docs/SavePSResource.md @@ -0,0 +1,205 @@ +# Save-PSResource + +The `Save-PSResource` cmdlet combines the `Save-Module, Save-Script` cmdlets from V2. +It saves from a package found on a repository (local or remote) based on the `-Name` parameter argument. +It does not return an object. +Other parameters allow the returned results to be further filtered. + +## Syntax + +### NameParameterSet (Default) +``` PowerShell +[[-Name] ] [-Version ] [-Prerelease] [-Repository ] +[-Path string] [-Credential ] [-AsNupkg] [-IncludeXML] [-TrustRepository] [-WhatIf] [-Confirm] [] +``` + +### InputObjectParameterSet +``` PowerShell +[[-InputObject] ] [-WhatIf] [-Confirm] [] +``` + +## Parameters + +### -Name + +Name of a resource or resources to save from a repository. +A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Version + +Specifies the version or version range of the resource to be saved. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + +### -Prerelease + +When specified, allow saving prerelease versions. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + +### -Repository + +Specifies one or more repository names to search. +If not specified, search will only search the highest priority repository. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Credential + +Optional credentials to be used when accessing a private repository. + +```yml +Type: PSCredential +Parameter Sets: NameParameterSet +``` + +### -AsNupkg + +When specified, saves the resource as a .nupkg. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + +### -IncludeXML + +Saves the metadata XML file with the resource. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Path + +Specifies the destination where the resource is to be saved. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + +### -TrustRepository + +When specified, suppresses being prompted for untrusted sources. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + +### -InputObject + +Used to pass in an object via pipeline to save. + +```yml +Type: object[] +Parameter Sets: InputObjectParameterSet +``` + +### Outputs + +No output. + +## Notes + +Should -TrustRepository parameter be removed? Ie, should repositories be trusted by default? +Now that we have repository priorities, one could set an untrusted repository to a lower priority. + +How often is a repository intentionally set as 'untrusted'? + + +## Tests + +Most search tests can be performed on a local repository. + +### -Name param + +- Single name search +- Wildcard search +- Multiple name search +- Cancel search +- Errors: Not found (single name, wildcard, multiple name) +- Errors: Repository: Invalid name, connection error, etc + +### -Version param + +- Validate correct resource version returned +- Validate wild card (if supported), correct version range returned +- Errors: Not found +- Errors: Invalid version string format + +### -Prerelease param + +- Validate prerelease version returned + +### -Repository param + +- All repository search +- Single repository search +- Multiple repository search +- Errors: Repository not found + +### -Credential param + +- Validate credential search +- Errors: Credential: Invalid + +### -AsNupkg param + +- Validate that package gets saved as .nupkg +- Errors: package is unable to save + +### -IncludeXML param + +- Validate that package gets saved with xml +- Errors: unable to create XML, unable to save XML + +### -Path param + +- Validate that package saves in the correct path +- Errors: unable to access path (such as OneDrive or paths with spaces) + +### -TrustRepository + +- Validate that user is not prompted and has access to repository + + + +## Work Items + +### Create cmdlet and parameter sets + +Create cmdlet class, parameters, and functional stubs +1 day + +### Implement uninstall helpers + +Create helper functions that support all search functions +Use existing code as starting point +2 days + +### Create test support + +Create any test repositories and mocks for tests +4 days + +### Write cmdlet tests + +Create all functional tests to validate cmdlet +5 days diff --git a/Docs/UninstallPSResource.md b/Docs/UninstallPSResource.md new file mode 100644 index 000000000..ed447b88e --- /dev/null +++ b/Docs/UninstallPSResource.md @@ -0,0 +1,101 @@ +# Uninstall-PSResource + +The `Uninstall-PSResource` cmdlet combines the `Uninstall-Module, Uninstall-Script` cmdlets from V2. +It uninstalls a package found in a module or script installation path based on the `-Name` parameter argument. +It does not return an object. +Other parameters allow the returned results to be further filtered. + +## Syntax + +### NameParameterSet (Default) +``` PowerShell +[[-Name] ] [-Version ] [-PrereleaseOnly] [-Tags ] +[-WhatIf] [-Confirm] [] +``` + +## Parameters + +### -Name + +Name of a resource or resources that has been installed. +Accepts wild card characters. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Version + +Specifies the version of the resource to be uninstalled. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + +### -PrereleaseOnly + +When specified, allows ONLY prerelease versions to be uninstalled. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + +### Outputs + +No output. + + +## Notes + +Should a -PassThru parameter be added? + +## Tests + +Most search tests can be performed on a local repository. + +### -Name param + +- Single name search +- Wildcard search +- Multiple name search +- Cancel search +- Errors: Not found (single name, wildcard, multiple name) +- Errors: Path errors (OneDrive access, etc) + +### -Version param + +- Validate correct resource version returned +- Validate wild card (if supported), correct version range returned +- Errors: Not found +- Errors: Invalid version string format + +### -Prerelease param + +- Validate prerelease version returned + + +## Work Items + +### Create cmdlet and parameter sets + +Create cmdlet class, parameters, and functional stubs +1 day + +### Implement uninstall helper + +Create helper functions that support all search functions +Use existing code as starting point +2 days + +### Create test support + +Create any test repositories and mocks for tests +4 days + +### Write cmdlet tests + +Create all functional tests to validate cmdlet +5 days diff --git a/Docs/UpdatePSResource.md b/Docs/UpdatePSResource.md new file mode 100644 index 000000000..c22376c9d --- /dev/null +++ b/Docs/UpdatePSResource.md @@ -0,0 +1,243 @@ +# Update-PSResource + +The `Update-PSResource` cmdlet combines the `Update-Module, Update-Script` cmdlets from V2. +It performs an upgraded installation of a package that is already installed based on the `-Name` parameter argument. +It does not return an object. +Other parameters allow the returned results to be further filtered. + +## Syntax + +### NameParameterSet (Default) +``` PowerShell +[[-Name] ] [-Version ] [-Prerelease] [-Scope ] +[-Repository ] [-TrustRepository] [-Credential ] [-Quiet] +[-AcceptLicense] [-NoClobber] [-WhatIf] [-Confirm] [] +``` + +### InputObjectParameterSet +``` PowerShell +[[-InputObject] [-WhatIf] [-Confirm] [] +``` + +## Parameters + +### -Name + +Name of a resource or resources to find. +Accepts wild card characters. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -InputObject + +Specifies an object that is passed in via pipeline. +The object should be of type PSCustomObject. + +```yml +Type: PSCustomObject[] +Parameter Sets: InputObjectParameterSet +``` + +### -Version + +Specifies the version the resource is to be updated to. + +```yml +Type: string +Parameter Sets: NameParameterSet +``` + +### -Prerelease + +When specified, allows updating to a prerelease version. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + +### -Repository + +Specifies one or more repository names to update from. +If not specified, will search in the highest priority repository. + +```yml +Type: string[] +Parameter Sets: NameParameterSet +``` + +### -Scope + +Specifies the scope of the resource to update. + +```yml +Type: string +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +AllowedValues: 'CurrentUser','AllUsers' +``` + +### -TrustRepository + +Suppresses being prompted for untrusted sources. + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +``` + +### -Credential + +Optional credentials to be used when accessing a repository. + +```yml +Type: PSCredential +Parameter Sets: NameParameterSet +``` + +### -Quiet + +Suppresses progress information. + +```yml +Type: SwitchParameter +Parameter Sets: (All) +``` + +### -AcceptLicense + +For modules that require a license, AcceptLicense automatically accepts the license agreement during update. + +```yml +Type: SwitchParameter +Parameter Sets: (All) +``` + +### -NoClobber + +Prevents updating modules that have the same cmdlets as a differently named module already + +```yml +Type: SwitchParameter +Parameter Sets: NameParameterSet +``` + + +### Outputs + +No output. + +## Notes +Input object still needs to be implemented. + +Should a -PassThru parameter be added? + +## Tests + +Most update tests can be performed on a local repository. + +Some tests should be performed on remote repository (PSGallery) to verify remote operation, but can be limited. + +### -Name param + +- Single name search +- Wildcard search +- Multiple name search +- Cancel search +- Errors: Not found (single name, wildcard, multiple name) +- Errors: Repository: Invalid name, connection error, etc + +### -Type InputObject + +- Validate pipeline input +- Errors: The object passed in is not the correct type + +### -Version param + +- Validate the resource is updated to the correct version +- Validate wild card (if supported), that the resource is updated to the correct version range +- Errors: Not found +- Errors: Invalid version string format + +### -Prerelease param + +- Validate prerelease version returned + +### -Repository param + +- All repository search +- Single repository search +- Multiple repository search +- Errors: Repository not found + +### -Credential param + +- Validate credential search +- Errors: Credential: Invalid + +### -Scope param + +- Validate only the resource from the proper scope gets updated + +### -TrustRepository param + +- Validate that prompt is suppresed + +### -Quiet param + +- Validate that progress information is suppressed + +### -AcceptLicense + +- Validate that modules which require license agreements are approved without a prompt + +### -NoClobber + +- Validate that resources are not overwritten when flag is passed + + +## Work Items + +### Create cmdlet and parameter sets + +Create cmdlet class, parameters, and functional stubs +1 day + +### Implement package search helpers + +Create helper functions that support all search functions +Use existing code as starting point +4 days + +### Investigate V3 API wildcard support + +Look into how V3 APIs can be used to reduce what is returned from the server +7 days + +### Implement package filtering functions + +Create helper functions to provide filtering of search results +3 days + +### Investigate and implement local cache + +Write mini-design document on local caching strategy +Implement local cache +10 days + +### Create test support + +Create any test repositories and mocks for tests +4 days + +### Write cmdlet tests + +Create all functional tests to validate cmdlet +5 days + +### Write support function tests + +Create all needed tests to validate caching and search helpers +5 days From f2d624c55e527cb031cdfd9479d71e3e21c557b9 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 26 Apr 2021 09:03:29 -0700 Subject: [PATCH 004/276] Add TryPSGetInfo utility function to read resource installation file data (#361) * Add TryPSGetInfo utility function * Fix Codacy and test issues * Fix DateTime tests * Rename method * Add TryWritePSGetInfo utility method * Fix Codacy issue * Small syntax change * Address CR comments --- src/code/Utils.cs | 407 ++++++++++++++++++++++++++++++- test/PSGetModuleInfo.xml | 152 ++++++++++++ test/PSGetResourceInfo.Tests.ps1 | 54 ++++ test/PSGetTestUtils.psm1 | 66 ++++- test/toBeRemoved.txt | 0 5 files changed, 669 insertions(+), 10 deletions(-) create mode 100644 test/PSGetModuleInfo.xml create mode 100644 test/PSGetResourceInfo.Tests.ps1 delete mode 100644 test/toBeRemoved.txt diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 95de2075d..440a18d86 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -2,15 +2,17 @@ // Licensed under the MIT License. using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Management.Automation; using System.Management.Automation.Language; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { - #region Utils - internal static class Utils { - #region Members + #region Public methods public static string TrimQuotes(string name) { @@ -37,7 +39,406 @@ public static string QuoteName(string name) return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; } + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i + /// Constructor + /// + /// Provided hashtable has form: + /// Key: Cmdlet + /// Value: ArrayList of Cmdlet name strings + /// Key: Command + /// Value: ArrayList of Command name strings + /// Key: DscResource + /// Value: ArrayList of DscResource name strings + /// Key: Function + /// Value: ArrayList of Function name strings + /// Key: RoleCapability (deprecated for PSGetV3) + /// Value: ArrayList of RoleCapability name strings + /// Key: Workflow (deprecated for PSGetV3) + /// Value: ArrayList of Workflow name strings + /// + /// Hashtable of PSGet includes + public PSGetIncludes(Hashtable includes) + { + if (includes == null) { return; } + + Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); + Command = GetHashTableItem(includes, nameof(Command)); + DscResource = GetHashTableItem(includes, nameof(DscResource)); + Function = GetHashTableItem(includes, nameof(Function)); + RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); + Workflow = GetHashTableItem(includes, nameof(Workflow)); + } + + #endregion + + #region Public methods + + public Hashtable ConvertToHashtable() + { + var hashtable = new Hashtable + { + { nameof(Cmdlet), Cmdlet }, + { nameof(Command), Command }, + { nameof(DscResource), DscResource }, + { nameof(Function), Function }, + { nameof(RoleCapability), RoleCapability }, + { nameof(Workflow), Workflow } + }; + + return hashtable; + } + + #endregion + + #region Private methods + + private string[] GetHashTableItem( + Hashtable table, + string name) + { + if (table.ContainsKey(name) && + table[name] is PSObject psObjectItem) + { + return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); + } + + return null; + } + + #endregion + } + + internal sealed class PSGetResourceInfo + { + #region Properties + + public Dictionary AdditionalMetadata { get; set; } + + public string Author { get; set; } + + public string CompanyName { get; set; } + + public string Copyright { get; set; } + + public string[] Dependencies { get; set; } + + public string Description { get; set; } + + public Uri IconUri { get; set; } + + public PSGetIncludes Includes { get; set; } + + public DateTime InstalledDate { get; set; } + + public string InstalledLocation { get; set; } + + public Uri LicenseUri { get; set; } + + public string Name { get; set; } + + public string PackageManagementProvider { get; set; } + + public string PowerShellGetFormatVersion { get; set; } + + public Uri ProjectUri { get; set; } + + public DateTime PublishedDate { get; set; } + + public string ReleaseNotes { get; set; } + + public string Repository { get; set; } + + public string RepositorySourceLocation { get; set; } + + public string[] Tags { get; set; } + + public string Type { get; set; } + + public DateTime UpdatedDate { get; set; } + + public Version Version { get; set; } + + #endregion + + #region Public static methods + + /// + /// Writes the PSGetResourceInfo properties to the specified file path as a + /// PowerShell serialized xml file, maintaining compatibility with + /// PowerShellGet v2 file format. + /// + public bool TryWrite( + string filePath, + out string errorMsg) + { + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + var infoXml = PSSerializer.Serialize( + source: ConvertToCustomObject(), + depth: 5); + + System.IO.File.WriteAllText( + path: filePath, + contents: infoXml); + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", + ex.Message); + + return false; + } + } + + /// + /// Reads a PSGet resource xml (PowerShell serialized) file and returns + /// a PSGetResourceInfo object containing the file contents. + /// + public static bool TryRead( + string filePath, + out PSGetResourceInfo psGetInfo, + out string errorMsg) + { + psGetInfo = null; + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + // Read and deserialize information xml file. + var psObjectInfo = (PSObject) PSSerializer.Deserialize( + System.IO.File.ReadAllText( + filePath)); + + psGetInfo = new PSGetResourceInfo + { + AdditionalMetadata = GetProperty>(nameof(PSGetResourceInfo.AdditionalMetadata), psObjectInfo), + Author = GetProperty(nameof(PSGetResourceInfo.Author), psObjectInfo), + CompanyName = GetProperty(nameof(PSGetResourceInfo.CompanyName), psObjectInfo), + Copyright = GetProperty(nameof(PSGetResourceInfo.Copyright), psObjectInfo), + Dependencies = Utils.GetStringArray(GetProperty(nameof(PSGetResourceInfo.Dependencies), psObjectInfo)), + Description = GetProperty(nameof(PSGetResourceInfo.Description), psObjectInfo), + IconUri = GetProperty(nameof(PSGetResourceInfo.IconUri), psObjectInfo), + Includes = new PSGetIncludes(GetProperty(nameof(PSGetResourceInfo.Includes), psObjectInfo)), + InstalledDate = GetProperty(nameof(PSGetResourceInfo.InstalledDate), psObjectInfo), + InstalledLocation = GetProperty(nameof(PSGetResourceInfo.InstalledLocation), psObjectInfo), + LicenseUri = GetProperty(nameof(PSGetResourceInfo.LicenseUri), psObjectInfo), + Name = GetProperty(nameof(PSGetResourceInfo.Name), psObjectInfo), + PackageManagementProvider = GetProperty(nameof(PSGetResourceInfo.PackageManagementProvider), psObjectInfo), + PowerShellGetFormatVersion = GetProperty(nameof(PSGetResourceInfo.PowerShellGetFormatVersion), psObjectInfo), + ProjectUri = GetProperty(nameof(PSGetResourceInfo.ProjectUri), psObjectInfo), + PublishedDate = GetProperty(nameof(PSGetResourceInfo.PublishedDate), psObjectInfo), + ReleaseNotes = GetProperty(nameof(PSGetResourceInfo.ReleaseNotes), psObjectInfo), + Repository = GetProperty(nameof(PSGetResourceInfo.Repository), psObjectInfo), + RepositorySourceLocation = GetProperty(nameof(PSGetResourceInfo.RepositorySourceLocation), psObjectInfo), + Tags = Utils.GetStringArray(GetProperty(nameof(PSGetResourceInfo.Tags), psObjectInfo)), + Type = GetProperty(nameof(PSGetResourceInfo.Type), psObjectInfo), + UpdatedDate = GetProperty(nameof(PSGetResourceInfo.UpdatedDate), psObjectInfo), + Version = GetProperty(nameof(PSGetResourceInfo.Version), psObjectInfo) + }; + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", + ex.Message); + + return false; + } + } + #endregion + + #region Private static methods + + private static T ConvertToType(PSObject psObject) + { + // We only convert Dictionary types. + if (typeof(T) != typeof(Dictionary)) + { + return default(T); + } + + var dict = new Dictionary(); + foreach (var prop in psObject.Properties) + { + dict.Add(prop.Name, prop.Value.ToString()); + } + + return (T)Convert.ChangeType(dict, typeof(T)); + } + + private static T GetProperty( + string Name, + PSObject psObjectInfo) + { + var val = psObjectInfo.Properties[Name]?.Value; + if (val == null) + { + return default(T); + } + + switch (val) + { + case T valType: + return valType; + + case PSObject valPSObject: + switch (valPSObject.BaseObject) + { + case T valBase: + return valBase; + + case PSCustomObject _: + // A base object of PSCustomObject means this is additional metadata + // and type T should be Dictionary. + return ConvertToType(valPSObject); + + default: + return default(T); + } + + default: + return default(T); + } + } + + #endregion + + #region Private methods + + private PSObject ConvertToCustomObject() + { + var additionalMetadata = new PSObject(); + foreach (var item in AdditionalMetadata) + { + additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); + } + + var psObject = new PSObject(); + psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); + psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); + psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); + psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); + psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); + psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); + psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); + psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); + psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); + psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); + psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); + psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); + psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); + psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(Version), Version)); + + return psObject; + } + + #endregion + } + + #endregion + + #region Test Hooks + + public static class TestHooks + { + public static PSObject ReadPSGetResourceInfo(string filePath) + { + if (PSGetResourceInfo.TryRead(filePath, out PSGetResourceInfo psGetInfo, out string errorMsg)) + { + return PSObject.AsPSObject(psGetInfo); + } + + throw new PSInvalidOperationException(errorMsg); + } + + public static void WritePSGetResourceInfo( + string filePath, + PSObject psObjectGetInfo) + { + if (psObjectGetInfo.BaseObject is PSGetResourceInfo psGetInfo) + { + if (! psGetInfo.TryWrite(filePath, out string errorMsg)) + { + throw new PSInvalidOperationException(errorMsg); + } + + return; + } + + throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); + } } #endregion diff --git a/test/PSGetModuleInfo.xml b/test/PSGetModuleInfo.xml new file mode 100644 index 000000000..082a4ebac --- /dev/null +++ b/test/PSGetModuleInfo.xml @@ -0,0 +1,152 @@ + + + + Microsoft.PowerShell.Commands.PSRepositoryItemInfo + System.Management.Automation.PSCustomObject + System.Object + + + Microsoft.PowerShell.SecretManagement + 1.0.0 + Module + This module provides a convenient way for a user to store and retrieve secrets. The secrets are_x000D__x000A_stored in registered extension vaults. An extension vault can store secrets locally or remotely._x000D__x000A_SecretManagement coordinates access to the secrets through the registered vaults._x000D__x000A__x000D__x000A_Go to GitHub for more information about the module and to submit issues:_x000D__x000A_https://github.com/powershell/SecretManagement + Microsoft Corporation + Microsoft Corporation + (c) Microsoft Corporation. All rights reserved. +
2021-03-25T18:08:10-07:00
+ +
2021-03-25T11:12:41.7662015-07:00
+ + + + Microsoft.PowerShell.Commands.DisplayHintType + System.Enum + System.ValueType + System.Object + + DateTime + 2 + + +
+ + https://github.com/PowerShell/SecretManagement/blob/master/LICENSE + https://github.com/powershell/secretmanagement + + + + System.Object[] + System.Array + System.Object + + + PSModule + PSEdition_Core + + + + + System.Collections.Hashtable + System.Object + + + + DscResource + + + + + + + RoleCapability + + + + Function + + + + Cmdlet + + + + Register-SecretVault + Unregister-SecretVault + Get-SecretVault + Set-SecretVaultDefault + Test-SecretVault + Set-Secret + Set-SecretInfo + Get-Secret + Get-SecretInfo + Remove-Secret + + + + + Command + + + + Register-SecretVault + Unregister-SecretVault + Get-SecretVault + Set-SecretVaultDefault + Test-SecretVault + Set-Secret + Set-SecretInfo + Get-Secret + Get-SecretInfo + Remove-Secret + + + + + Workflow + + + + + + + + + + + https://www.powershellgallery.com/api/v2 + PSGallery + NuGet + + + System.Management.Automation.PSCustomObject + System.Object + + + (c) Microsoft Corporation. All rights reserved. + This module provides a convenient way for a user to store and retrieve secrets. The secrets are_x000D__x000A_stored in registered extension vaults. An extension vault can store secrets locally or remotely._x000D__x000A_SecretManagement coordinates access to the secrets through the registered vaults._x000D__x000A__x000D__x000A_Go to GitHub for more information about the module and to submit issues:_x000D__x000A_https://github.com/powershell/SecretManagement + False + True + True + 0 + 15034 + 55046 + 3/25/2021 6:08:10 PM -07:00 + 3/25/2021 6:08:10 PM -07:00 + 3/25/2021 6:08:10 PM -07:00 + PSModule PSEdition_Core PSCmdlet_Register-SecretVault PSCommand_Register-SecretVault PSCmdlet_Unregister-SecretVault PSCommand_Unregister-SecretVault PSCmdlet_Get-SecretVault PSCommand_Get-SecretVault PSCmdlet_Set-SecretVaultDefault PSCommand_Set-SecretVaultDefault PSCmdlet_Test-SecretVault PSCommand_Test-SecretVault PSCmdlet_Set-Secret PSCommand_Set-Secret PSCmdlet_Set-SecretInfo PSCommand_Set-SecretInfo PSCmdlet_Get-Secret PSCommand_Get-Secret PSCmdlet_Get-SecretInfo PSCommand_Get-SecretInfo PSCmdlet_Remove-Secret PSCommand_Remove-Secret PSIncludes_Cmdlet + False + 2021-03-25T18:08:10Z + 1.0.0 + Microsoft Corporation + false + Module + Microsoft.PowerShell.SecretManagement.nuspec|Microsoft.PowerShell.SecretManagement.dll|Microsoft.PowerShell.SecretManagement.format.ps1xml|Microsoft.PowerShell.SecretManagement.psd1|en-US\about_Microsoft.PowerShell.SecretManagement.help.txt|en-US\Microsoft.PowerShell.SecretManagement.dll-Help.xml + a5c858f6-4a8e-41f1-b1ee-0ff8f6ad69d3 + 5.1 + Microsoft Corporation + + + C:\Users\paulhi\OneDrive - Microsoft\Documents\PowerShell\Modules\Microsoft.PowerShell.SecretManagement\1.0.0 +
+
+
diff --git a/test/PSGetResourceInfo.Tests.ps1 b/test/PSGetResourceInfo.Tests.ps1 new file mode 100644 index 000000000..023c23c18 --- /dev/null +++ b/test/PSGetResourceInfo.Tests.ps1 @@ -0,0 +1,54 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +$psGetMod = Get-Module -Name PowerShellGet +if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) +{ + Write-Verbose -Message "Importing PowerShellGet 3.0.0 for test" -Verbose + Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force +} + +Describe "Read PSGetModuleInfo xml file" -tags 'CI' { + + BeforeAll { + $fileToRead = Join-Path -Path $PSScriptRoot -ChildPath "PSGetModuleInfo.xml" + } + + It "Verifies expected error with null path" { + { [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::ReadPSGetResourceInfo($null) } | Should -Throw -ErrorId 'PSInvalidOperationException' + } + + It "Verifies expected error with invalid file path" { + { [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::ReadPSGetResourceInfo('nonePath') } | Should -Throw -ErrorId 'PSInvalidOperationException' + } + + It "Verifies PSGetModuleInfo.xml file is read successfully" { + $psGetInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::ReadPSGetResourceInfo($fileToRead) + CheckForExpectedPSGetInfo $psGetInfo + } +} + +Describe "Write PSGetModuleInfo xml file" -tags 'CI' { + + BeforeAll { + $fileToRead = Join-Path -Path $PSScriptRoot -ChildPath "PSGetModuleInfo.xml" + $fileToWrite = Join-Path -Path $TestDrive -ChildPath "PSGetModuleInfo_Write.xml" + } + + It "Verifies expected error with null path" { + $psGetInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::ReadPSGetResourceInfo($fileToRead) + { [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::WritePSGetResourceInfo($null, $psGetInfo) } | Should -Throw -ErrorId 'PSInvalidOperationException' + } + + It "Verifies file write is successful" { + $psGetInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::ReadPSGetResourceInfo($fileToRead) + { [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::WritePSGetResourceInfo($fileToWrite, $psGetInfo) } | Should -Not -Throw + } + + It "Verifes written file can be read successfully" { + $newGetInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.TestHooks]::ReadPSGetResourceInfo($fileToWrite) + CheckForExpectedPSGetInfo $newGetInfo + } +} diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index ca57a7294..bfeaea5a2 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -1,10 +1,5 @@ -<##################################################################################### - # File: PSGetTestUtils.psm1 - # - # Copyright (c) Microsoft Corporation, 2020 - #####################################################################################> - -#."$PSScriptRoot\uiproxy.ps1" +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. $psGetMod = Get-Module -Name PowerShellGet if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) @@ -450,3 +445,60 @@ $($ReleaseNotes -join "`r`n") return $PSScriptInfoString } } + +<# +Checks that provided PSGetInfo object contents match the expected data +from the test information file: PSGetModuleInfo.xml +#> +function CheckForExpectedPSGetInfo +{ + param ($psGetInfo) + + $psGetInfo.AdditionalMetadata.Keys | Should -HaveCount 22 + $psGetInfo.AdditionalMetadata['copyright'] | Should -BeExactly '(c) Microsoft Corporation. All rights reserved.' + $psGetInfo.AdditionalMetadata['description'] | Should -BeLike 'This module provides a convenient way for a user to store and retrieve secrets*' + $psGetInfo.AdditionalMetadata['requireLicenseAcceptance'] | Should -BeExactly 'False' + $psGetInfo.AdditionalMetadata['isLatestVersion'] | Should -BeExactly 'True' + $psGetInfo.AdditionalMetadata['isAbsoluteLatestVersion'] | Should -BeExactly 'True' + $psGetInfo.AdditionalMetadata['versionDownloadCount'] | Should -BeExactly '0' + $psGetInfo.AdditionalMetadata['downloadCount'] | Should -BeExactly '15034' + $psGetInfo.AdditionalMetadata['packageSize'] | Should -BeExactly '55046' + $psGetInfo.AdditionalMetadata['published'] | Should -BeExactly '3/25/2021 6:08:10 PM -07:00' + $psGetInfo.AdditionalMetadata['created'] | Should -BeExactly '3/25/2021 6:08:10 PM -07:00' + $psGetInfo.AdditionalMetadata['lastUpdated'] | Should -BeExactly '3/25/2021 6:08:10 PM -07:00' + $psGetInfo.AdditionalMetadata['tags'] | Should -BeLike 'PSModule PSEdition_Core PSCmdlet_Register-SecretVault*' + $psGetInfo.AdditionalMetadata['developmentDependency'] | Should -BeExactly 'False' + $psGetInfo.AdditionalMetadata['updated'] | Should -BeExactly '2021-03-25T18:08:10Z' + $psGetInfo.AdditionalMetadata['NormalizedVersion'] | Should -BeExactly '1.0.0' + $psGetInfo.AdditionalMetadata['Authors'] | Should -BeExactly 'Microsoft Corporation' + $psGetInfo.AdditionalMetadata['IsPrerelease'] | Should -BeExactly 'false' + $psGetInfo.AdditionalMetadata['ItemType'] | Should -BeExactly 'Module' + $psGetInfo.AdditionalMetadata['FileList'] | Should -BeLike 'Microsoft.PowerShell.SecretManagement.nuspec|Microsoft.PowerShell.SecretManagement.dll*' + $psGetInfo.AdditionalMetadata['GUID'] | Should -BeExactly 'a5c858f6-4a8e-41f1-b1ee-0ff8f6ad69d3' + $psGetInfo.AdditionalMetadata['PowerShellVersion'] | Should -BeExactly '5.1' + $psGetInfo.AdditionalMetadata['CompanyName'] | Should -BeExactly 'Microsoft Corporation' + # + $psGetInfo.Author | Should -BeExactly 'Microsoft Corporation' + $psGetInfo.CompanyName | Should -BeExactly 'Microsoft Corporation' + $psGetInfo.Copyright | Should -BeExactly '(c) Microsoft Corporation. All rights reserved.' + $psGetInfo.Dependencies | Should -HaveCount 0 + $psGetInfo.Description | Should -BeLike 'This module provides a convenient way for a user to store*' + $psGetInfo.IconUri | Should -BeNullOrEmpty + $psGetInfo.Includes.Cmdlet | Should -HaveCount 10 + $psGetInfo.Includes.Cmdlet[0] | Should -BeExactly 'Register-SecretVault' + $psGetInfo.InstalledDate.Year | Should -BeExactly 2021 + $psGetInfo.InstalledLocation | Should -BeLike 'C:\Users\*' + $psGetInfo.LicenseUri | Should -BeExactly 'https://github.com/PowerShell/SecretManagement/blob/master/LICENSE' + $psGetInfo.Name | Should -BeExactly 'Microsoft.PowerShell.SecretManagement' + $psGetInfo.PackageManagementProvider | Should -BeExactly 'NuGet' + $psGetInfo.PowerShellGetFormatVersion | Should -BeNullOrEmpty + $psGetInfo.ProjectUri | Should -BeExactly 'https://github.com/powershell/secretmanagement' + $psGetInfo.PublishedDate.Year | Should -BeExactly 2021 + $psGetInfo.ReleasedNotes | Should -BeNullOrEmpty + $psGetInfo.Repository | Should -BeExactly 'PSGallery' + $psGetInfo.RepositorySourceLocation | Should -BeExactly 'https://www.powershellgallery.com/api/v2' + $psGetInfo.Tags | Should -BeExactly @('PSModule', 'PSEdition_Core') + $psGetInfo.Type | Should -BeExactly 'Module' + $psGetInfo.UpdatedDate.Year | Should -BeExactly 1 + $psGetInfo.Version.ToString() | Should -BeExactly '1.0.0' +} diff --git a/test/toBeRemoved.txt b/test/toBeRemoved.txt deleted file mode 100644 index e69de29bb..000000000 From fa09d5ebb8662de09a40929934db6b1616c53e44 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 4 May 2021 10:03:18 -0700 Subject: [PATCH 005/276] Fix resourceinfo (#367) * Move the PSResourceInfo class to its own source file, and rename test * Add missing copyright to new source file * Fix Codeacy warning --- src/code/PSResourceInfo.cs | 416 ++++++++++++++++++ src/code/Utils.cs | 388 ---------------- ...nfo.Tests.ps1 => PSResourceInfo.Tests.ps1} | 0 3 files changed, 416 insertions(+), 388 deletions(-) create mode 100644 src/code/PSResourceInfo.cs rename test/{PSGetResourceInfo.Tests.ps1 => PSResourceInfo.Tests.ps1} (100%) diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs new file mode 100644 index 000000000..cdac5664a --- /dev/null +++ b/src/code/PSResourceInfo.cs @@ -0,0 +1,416 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + #region Enums + + public enum ResourceType + { + Module, + Script + } + + public enum VersionType + { + Unknown, + MinimumVersion, + RequiredVersion, + MaximumVersion + } + + #endregion + + #region VersionInfo + + public sealed class VersionInfo + { + public VersionInfo( + VersionType versionType, + Version versionNum) + { + VersionType = versionType; + VersionNum = versionNum; + } + + public VersionType VersionType { get; } + public Version VersionNum { get; } + + public override string ToString() => $"{VersionType}: {VersionNum}"; + } + + #endregion + + #region ResourceIncludes + + public sealed class ResourceIncludes + { + #region Properties + + public string[] Cmdlet { get; } + + public string[] Command { get; } + + public string[] DscResource { get; } + + public string[] Function { get; } + + public string[] RoleCapability { get; } + + public string[] Workflow { get; } + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// Provided hashtable has form: + /// Key: Cmdlet + /// Value: ArrayList of Cmdlet name strings + /// Key: Command + /// Value: ArrayList of Command name strings + /// Key: DscResource + /// Value: ArrayList of DscResource name strings + /// Key: Function + /// Value: ArrayList of Function name strings + /// Key: RoleCapability (deprecated for PSGetV3) + /// Value: ArrayList of RoleCapability name strings + /// Key: Workflow (deprecated for PSGetV3) + /// Value: ArrayList of Workflow name strings + /// + /// Hashtable of PSGet includes + public ResourceIncludes(Hashtable includes) + { + if (includes == null) { return; } + + Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); + Command = GetHashTableItem(includes, nameof(Command)); + DscResource = GetHashTableItem(includes, nameof(DscResource)); + Function = GetHashTableItem(includes, nameof(Function)); + RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); + Workflow = GetHashTableItem(includes, nameof(Workflow)); + } + + #endregion + + #region Public methods + + public Hashtable ConvertToHashtable() + { + var hashtable = new Hashtable + { + { nameof(Cmdlet), Cmdlet }, + { nameof(Command), Command }, + { nameof(DscResource), DscResource }, + { nameof(Function), Function }, + { nameof(RoleCapability), RoleCapability }, + { nameof(Workflow), Workflow } + }; + + return hashtable; + } + + #endregion + + #region Private methods + + private string[] GetHashTableItem( + Hashtable table, + string name) + { + if (table.ContainsKey(name) && + table[name] is PSObject psObjectItem) + { + return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); + } + + return null; + } + + #endregion + } + + #endregion + + #region PSResourceInfo + + public sealed class PSResourceInfo + { + #region Properties + + public Dictionary AdditionalMetadata { get; set; } + public string Author { get; set; } + public string CompanyName { get; set; } + public string Copyright { get; set; } + public string[] Dependencies { get; set; } + public string Description { get; set; } + public Uri IconUri { get; set; } + public ResourceIncludes Includes { get; set; } + public DateTime? InstalledDate { get; set; } + public string InstalledLocation { get; set; } + public Uri LicenseUri { get; set; } + public string Name { get; set; } + public string PackageManagementProvider { get; set; } + public string PowerShellGetFormatVersion { get; set; } + public Uri ProjectUri { get; set; } + public DateTime? PublishedDate { get; set; } + public string ReleaseNotes { get; set; } + public string Repository { get; set; } + public string RepositorySourceLocation { get; set; } + public string[] Tags { get; set; } + public string Type { get; set; } + public DateTime? UpdatedDate { get; set; } + public Version Version { get; set; } + + #endregion + + #region Public static methods + + /// + /// Writes the PSGetResourceInfo properties to the specified file path as a + /// PowerShell serialized xml file, maintaining compatibility with + /// PowerShellGet v2 file format. + /// + public bool TryWrite( + string filePath, + out string errorMsg) + { + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + var infoXml = PSSerializer.Serialize( + source: ConvertToCustomObject(), + depth: 5); + + System.IO.File.WriteAllText( + path: filePath, + contents: infoXml); + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", + ex.Message); + + return false; + } + } + + /// + /// Reads a PSGet resource xml (PowerShell serialized) file and returns + /// a PSGetResourceInfo object containing the file contents. + /// + public static bool TryRead( + string filePath, + out PSResourceInfo psGetInfo, + out string errorMsg) + { + psGetInfo = null; + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + // Read and deserialize information xml file. + var psObjectInfo = (PSObject) PSSerializer.Deserialize( + System.IO.File.ReadAllText( + filePath)); + + psGetInfo = new PSResourceInfo + { + AdditionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo), + Author = GetProperty(nameof(PSResourceInfo.Author), psObjectInfo), + CompanyName = GetProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), + Copyright = GetProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), + Dependencies = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), + Description = GetProperty(nameof(PSResourceInfo.Description), psObjectInfo), + IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), + Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), + InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), + InstalledLocation = GetProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), + LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), + Name = GetProperty(nameof(PSResourceInfo.Name), psObjectInfo), + PackageManagementProvider = GetProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), + PowerShellGetFormatVersion = GetProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), + ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), + PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), + ReleaseNotes = GetProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), + Repository = GetProperty(nameof(PSResourceInfo.Repository), psObjectInfo), + RepositorySourceLocation = GetProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), + Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), + Type = GetProperty(nameof(PSResourceInfo.Type), psObjectInfo), + UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), + Version = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo) + }; + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", + ex.Message); + + return false; + } + } + + #endregion + + #region Private static methods + + private static T ConvertToType(PSObject psObject) + { + // We only convert Dictionary types. + if (typeof(T) != typeof(Dictionary)) + { + return default(T); + } + + var dict = new Dictionary(); + foreach (var prop in psObject.Properties) + { + dict.Add(prop.Name, prop.Value.ToString()); + } + + return (T)Convert.ChangeType(dict, typeof(T)); + } + + private static T GetProperty( + string Name, + PSObject psObjectInfo) + { + var val = psObjectInfo.Properties[Name]?.Value; + if (val == null) + { + return default(T); + } + + switch (val) + { + case T valType: + return valType; + + case PSObject valPSObject: + switch (valPSObject.BaseObject) + { + case T valBase: + return valBase; + + case PSCustomObject _: + // A base object of PSCustomObject means this is additional metadata + // and type T should be Dictionary. + return ConvertToType(valPSObject); + + default: + return default(T); + } + + default: + return default(T); + } + } + + #endregion + + #region Private methods + + private PSObject ConvertToCustomObject() + { + var additionalMetadata = new PSObject(); + foreach (var item in AdditionalMetadata) + { + additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); + } + + var psObject = new PSObject(); + psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); + psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); + psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); + psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); + psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); + psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); + psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); + psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); + psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); + psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); + psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); + psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); + psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); + psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(Version), Version)); + + return psObject; + } + + #endregion + } + + #endregion + + #region Test Hooks + + public static class TestHooks + { + public static PSObject ReadPSGetResourceInfo(string filePath) + { + if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + return PSObject.AsPSObject(psGetInfo); + } + + throw new PSInvalidOperationException(errorMsg); + } + + public static void WritePSGetResourceInfo( + string filePath, + PSObject psObjectGetInfo) + { + if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) + { + if (! psGetInfo.TryWrite(filePath, out string errorMsg)) + { + throw new PSInvalidOperationException(errorMsg); + } + + return; + } + + throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); + } + } + + #endregion +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 440a18d86..02d13e40d 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -3,9 +3,6 @@ using System; using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Management.Automation; using System.Management.Automation.Language; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses @@ -57,389 +54,4 @@ public static string[] GetStringArray(ArrayList list) #endregion } - - #region PSGetResourceInfo classes - - internal sealed class PSGetIncludes - { - #region Properties - - public string[] Cmdlet { get; } - - public string[] Command { get; } - - public string[] DscResource { get; } - - public string[] Function { get; } - - public string[] RoleCapability { get; } - - public string[] Workflow { get; } - - #endregion - - #region Constructor - - /// - /// Constructor - /// - /// Provided hashtable has form: - /// Key: Cmdlet - /// Value: ArrayList of Cmdlet name strings - /// Key: Command - /// Value: ArrayList of Command name strings - /// Key: DscResource - /// Value: ArrayList of DscResource name strings - /// Key: Function - /// Value: ArrayList of Function name strings - /// Key: RoleCapability (deprecated for PSGetV3) - /// Value: ArrayList of RoleCapability name strings - /// Key: Workflow (deprecated for PSGetV3) - /// Value: ArrayList of Workflow name strings - /// - /// Hashtable of PSGet includes - public PSGetIncludes(Hashtable includes) - { - if (includes == null) { return; } - - Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); - Command = GetHashTableItem(includes, nameof(Command)); - DscResource = GetHashTableItem(includes, nameof(DscResource)); - Function = GetHashTableItem(includes, nameof(Function)); - RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); - Workflow = GetHashTableItem(includes, nameof(Workflow)); - } - - #endregion - - #region Public methods - - public Hashtable ConvertToHashtable() - { - var hashtable = new Hashtable - { - { nameof(Cmdlet), Cmdlet }, - { nameof(Command), Command }, - { nameof(DscResource), DscResource }, - { nameof(Function), Function }, - { nameof(RoleCapability), RoleCapability }, - { nameof(Workflow), Workflow } - }; - - return hashtable; - } - - #endregion - - #region Private methods - - private string[] GetHashTableItem( - Hashtable table, - string name) - { - if (table.ContainsKey(name) && - table[name] is PSObject psObjectItem) - { - return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); - } - - return null; - } - - #endregion - } - - internal sealed class PSGetResourceInfo - { - #region Properties - - public Dictionary AdditionalMetadata { get; set; } - - public string Author { get; set; } - - public string CompanyName { get; set; } - - public string Copyright { get; set; } - - public string[] Dependencies { get; set; } - - public string Description { get; set; } - - public Uri IconUri { get; set; } - - public PSGetIncludes Includes { get; set; } - - public DateTime InstalledDate { get; set; } - - public string InstalledLocation { get; set; } - - public Uri LicenseUri { get; set; } - - public string Name { get; set; } - - public string PackageManagementProvider { get; set; } - - public string PowerShellGetFormatVersion { get; set; } - - public Uri ProjectUri { get; set; } - - public DateTime PublishedDate { get; set; } - - public string ReleaseNotes { get; set; } - - public string Repository { get; set; } - - public string RepositorySourceLocation { get; set; } - - public string[] Tags { get; set; } - - public string Type { get; set; } - - public DateTime UpdatedDate { get; set; } - - public Version Version { get; set; } - - #endregion - - #region Public static methods - - /// - /// Writes the PSGetResourceInfo properties to the specified file path as a - /// PowerShell serialized xml file, maintaining compatibility with - /// PowerShellGet v2 file format. - /// - public bool TryWrite( - string filePath, - out string errorMsg) - { - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - var infoXml = PSSerializer.Serialize( - source: ConvertToCustomObject(), - depth: 5); - - System.IO.File.WriteAllText( - path: filePath, - contents: infoXml); - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", - ex.Message); - - return false; - } - } - - /// - /// Reads a PSGet resource xml (PowerShell serialized) file and returns - /// a PSGetResourceInfo object containing the file contents. - /// - public static bool TryRead( - string filePath, - out PSGetResourceInfo psGetInfo, - out string errorMsg) - { - psGetInfo = null; - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - // Read and deserialize information xml file. - var psObjectInfo = (PSObject) PSSerializer.Deserialize( - System.IO.File.ReadAllText( - filePath)); - - psGetInfo = new PSGetResourceInfo - { - AdditionalMetadata = GetProperty>(nameof(PSGetResourceInfo.AdditionalMetadata), psObjectInfo), - Author = GetProperty(nameof(PSGetResourceInfo.Author), psObjectInfo), - CompanyName = GetProperty(nameof(PSGetResourceInfo.CompanyName), psObjectInfo), - Copyright = GetProperty(nameof(PSGetResourceInfo.Copyright), psObjectInfo), - Dependencies = Utils.GetStringArray(GetProperty(nameof(PSGetResourceInfo.Dependencies), psObjectInfo)), - Description = GetProperty(nameof(PSGetResourceInfo.Description), psObjectInfo), - IconUri = GetProperty(nameof(PSGetResourceInfo.IconUri), psObjectInfo), - Includes = new PSGetIncludes(GetProperty(nameof(PSGetResourceInfo.Includes), psObjectInfo)), - InstalledDate = GetProperty(nameof(PSGetResourceInfo.InstalledDate), psObjectInfo), - InstalledLocation = GetProperty(nameof(PSGetResourceInfo.InstalledLocation), psObjectInfo), - LicenseUri = GetProperty(nameof(PSGetResourceInfo.LicenseUri), psObjectInfo), - Name = GetProperty(nameof(PSGetResourceInfo.Name), psObjectInfo), - PackageManagementProvider = GetProperty(nameof(PSGetResourceInfo.PackageManagementProvider), psObjectInfo), - PowerShellGetFormatVersion = GetProperty(nameof(PSGetResourceInfo.PowerShellGetFormatVersion), psObjectInfo), - ProjectUri = GetProperty(nameof(PSGetResourceInfo.ProjectUri), psObjectInfo), - PublishedDate = GetProperty(nameof(PSGetResourceInfo.PublishedDate), psObjectInfo), - ReleaseNotes = GetProperty(nameof(PSGetResourceInfo.ReleaseNotes), psObjectInfo), - Repository = GetProperty(nameof(PSGetResourceInfo.Repository), psObjectInfo), - RepositorySourceLocation = GetProperty(nameof(PSGetResourceInfo.RepositorySourceLocation), psObjectInfo), - Tags = Utils.GetStringArray(GetProperty(nameof(PSGetResourceInfo.Tags), psObjectInfo)), - Type = GetProperty(nameof(PSGetResourceInfo.Type), psObjectInfo), - UpdatedDate = GetProperty(nameof(PSGetResourceInfo.UpdatedDate), psObjectInfo), - Version = GetProperty(nameof(PSGetResourceInfo.Version), psObjectInfo) - }; - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", - ex.Message); - - return false; - } - } - - #endregion - - #region Private static methods - - private static T ConvertToType(PSObject psObject) - { - // We only convert Dictionary types. - if (typeof(T) != typeof(Dictionary)) - { - return default(T); - } - - var dict = new Dictionary(); - foreach (var prop in psObject.Properties) - { - dict.Add(prop.Name, prop.Value.ToString()); - } - - return (T)Convert.ChangeType(dict, typeof(T)); - } - - private static T GetProperty( - string Name, - PSObject psObjectInfo) - { - var val = psObjectInfo.Properties[Name]?.Value; - if (val == null) - { - return default(T); - } - - switch (val) - { - case T valType: - return valType; - - case PSObject valPSObject: - switch (valPSObject.BaseObject) - { - case T valBase: - return valBase; - - case PSCustomObject _: - // A base object of PSCustomObject means this is additional metadata - // and type T should be Dictionary. - return ConvertToType(valPSObject); - - default: - return default(T); - } - - default: - return default(T); - } - } - - #endregion - - #region Private methods - - private PSObject ConvertToCustomObject() - { - var additionalMetadata = new PSObject(); - foreach (var item in AdditionalMetadata) - { - additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); - } - - var psObject = new PSObject(); - psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); - psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); - psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); - psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); - psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); - psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); - psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); - psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); - psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); - psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); - psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); - psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); - psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); - psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(Version), Version)); - - return psObject; - } - - #endregion - } - - #endregion - - #region Test Hooks - - public static class TestHooks - { - public static PSObject ReadPSGetResourceInfo(string filePath) - { - if (PSGetResourceInfo.TryRead(filePath, out PSGetResourceInfo psGetInfo, out string errorMsg)) - { - return PSObject.AsPSObject(psGetInfo); - } - - throw new PSInvalidOperationException(errorMsg); - } - - public static void WritePSGetResourceInfo( - string filePath, - PSObject psObjectGetInfo) - { - if (psObjectGetInfo.BaseObject is PSGetResourceInfo psGetInfo) - { - if (! psGetInfo.TryWrite(filePath, out string errorMsg)) - { - throw new PSInvalidOperationException(errorMsg); - } - - return; - } - - throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); - } - } - - #endregion } diff --git a/test/PSGetResourceInfo.Tests.ps1 b/test/PSResourceInfo.Tests.ps1 similarity index 100% rename from test/PSGetResourceInfo.Tests.ps1 rename to test/PSResourceInfo.Tests.ps1 From 3df0f5b87a9811719cfcabf38dc61bcc9726b0e3 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 4 Jun 2021 14:08:51 -0700 Subject: [PATCH 006/276] WIP: Refactor Uninstall-PSResource (#353) --- help/Uninstall-PSResource.md | 76 ++-- src/code/GetHelper.cs | 208 +++++++++++ src/code/UninstallPSResource.cs | 316 ++++++++++++++++ src/code/Utils.cs | 240 ++++++++++--- srcOld/code/UninstallPSResource.cs | 554 ----------------------------- test/UninstallPSResource.Tests.ps1 | 189 ++++++++++ 6 files changed, 923 insertions(+), 660 deletions(-) create mode 100644 src/code/GetHelper.cs create mode 100644 src/code/UninstallPSResource.cs delete mode 100644 srcOld/code/UninstallPSResource.cs create mode 100644 test/UninstallPSResource.Tests.ps1 diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index 80bb32391..13844b909 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -1,53 +1,53 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- # Uninstall-PSResource ## SYNOPSIS -{{ Fill in the Synopsis }} +Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. ## SYNTAX ``` -Uninstall-PSResource [-Name] [-Version ] [-PrereleaseOnly] [-Force] [-WhatIf] [-Confirm] - [] +Uninstall-PSResource [-Name] [-Version ] [-Force] [-WhatIf] [] ``` ## DESCRIPTION -{{ Fill in the Description }} +The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. ## EXAMPLES ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Uninstall-PSResource Az ``` -{{ Add example description here }} +Uninstalls the latest version of the Az module. -## PARAMETERS +### Example 2 +```powershell +PS C:\> Uninstall-PSResource -name Az -version "1.0.0" +``` -### -Force -{{ Fill Force Description }} +Uninstalls version 1.0.0 of the Az module. -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: +### Example 3 +```powershell +PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False +Uninstalls all versions within the specified version range. ``` +Uninstalls version 1.0.0 of the Az module. + +## PARAMETERS + ### -Name -{{ Fill Name Description }} +Name of a resource or resources that has been installed. Accepts wild card characters. ```yaml Type: System.String[] @@ -58,26 +58,11 @@ Required: True Position: 0 Default value: None Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` - -### -PrereleaseOnly -{{ Fill PrereleaseOnly Description }} - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -Version -{{ Fill Version Description }} +Specifies the version of the resource to be uninstalled. ```yaml Type: System.String @@ -87,17 +72,17 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: False +Accept pipeline input: True Accept wildcard characters: False ``` -### -Confirm -Prompts you for confirmation before running the cmdlet. +### -Force +Skips check to see if any modules have a dependency on the resource to be uninstalled. ```yaml Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: cf +Aliases: Required: False Position: Named @@ -125,16 +110,9 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). -## INPUTS - -### System.String[] - ## OUTPUTS +None -### System.Object ## NOTES ## RELATED LINKS - -[]() - diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs new file mode 100644 index 000000000..faf50bd95 --- /dev/null +++ b/src/code/GetHelper.cs @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Threading; +using MoreLinq.Extensions; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using static Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Get helper class provides the core functionality for Get-InstalledPSResource. + /// + internal class GetHelper + { + private CancellationToken _cancellationToken; + private readonly PSCmdlet _cmdletPassedIn; + private Dictionary _scriptDictionary; + + public GetHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) + { + _cancellationToken = cancellationToken; + _cmdletPassedIn = cmdletPassedIn; + _scriptDictionary = new Dictionary(); + } + + public IEnumerable ProcessGetParams(string[] name, VersionRange versionRange, List pathsToSearch) + { + List filteredPathsToSearch = FilterPkgPathsByName(name, pathsToSearch); + + foreach (string pkgPath in FilterPkgPathsByVersion(versionRange, filteredPathsToSearch)) + { + yield return OutputPackageObject(pkgPath, _scriptDictionary); + } + } + + // Filter packages by user provided name + public List FilterPkgPathsByName(string[] names, List dirsToSearch) + { + List wildCardDirsToSearch = new List(); + + if (names == null) + { + _cmdletPassedIn.WriteVerbose("No names were provided."); + return wildCardDirsToSearch; + } + + foreach (string name in names) + { + WildcardPattern nameWildCardPattern = new WildcardPattern(name, WildcardOptions.IgnoreCase); + + // ./Modules/Test-Module + // ./Scripts/Test-Script.ps1 + wildCardDirsToSearch.AddRange(dirsToSearch.FindAll( + p => nameWildCardPattern.IsMatch( + System.IO.Path.GetFileNameWithoutExtension((new DirectoryInfo(p).Name))))); + } + _cmdletPassedIn.WriteDebug(wildCardDirsToSearch.Any().ToString()); + + return wildCardDirsToSearch; + } + + // Filter by user provided version + public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, List dirsToSearch) + { + // if no version is specified, just get the latest version + foreach (string pkgPath in dirsToSearch) + { + _cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); + + // if this is a module directory + if (Directory.Exists(pkgPath)) + { + // search modules paths + // ./Modules/Test-Module/1.0.0 + // ./Modules/Test-Module/2.0.0 + _cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); + + string[] versionsDirs = new string[] { }; + try + { + versionsDirs = Directory.GetDirectories(pkgPath); + } + catch (Exception e){ + _cmdletPassedIn.WriteVerbose(string.Format("Error retreiving directories from path '{0}': '{1}'", pkgPath, e.Message)); + + // skip to next iteration of the loop + continue; + } + + // versionRange should not be null if the cmdlet is Get-InstalledPSResource + if (versionRange == null) + { + // if no version is specified, just delete the latest version + Array.Sort(versionsDirs); + + yield return (versionsDirs[versionsDirs.Length - 1]); + continue; + } + + foreach (string versionPath in versionsDirs) + { + _cmdletPassedIn.WriteDebug(string.Format("Searching through package version path: '{0}'", versionPath)); + DirectoryInfo dirInfo = new DirectoryInfo(versionPath); + + // if the version is not valid, we'll just skip it and output a debug message + if (!NuGetVersion.TryParse(dirInfo.Name, out NuGetVersion dirAsNugetVersion)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Leaf directory in path '{0}' cannot be parsed into a version.", versionPath)); + + // skip to next iteration of the loop + continue; + } + _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); + + if (versionRange.Satisfies(dirAsNugetVersion)) + { + // This will be one version or a version range. + // yield results then continue with this iteration of the loop + yield return versionPath; + } + } + } + else if (File.Exists(pkgPath)) + { + // if it's a script + if (versionRange == VersionRange.All) + { + // yield results then continue with this iteration of the loop + yield return pkgPath; + + // We are now done with the current iteration of the for loop because + // only one script version can be installed in a particular script path at a time. + // if looking for all versions and one was found, then we have found all possible versions at that ./Scripts path + // and do not need to parse and check for the version number in the metadata file. + } + else + { + // check to make sure it's within the version range. + // script versions will be parsed from the script xml file + PSResourceInfo scriptInfo = OutputPackageObject(pkgPath, _scriptDictionary); + if (scriptInfo == null) + { + // if script was not found skip to the next iteration of the loop + continue; + } + + if (!NuGetVersion.TryParse(scriptInfo.Version.ToString(), out NuGetVersion scriptVersion)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Version '{0}' could not be properly parsed from the script metadata file from the script installed at '{1}'", scriptInfo.Version.ToString(), scriptInfo.InstalledLocation)); + } + else if (versionRange.Satisfies(scriptVersion)) + { + _scriptDictionary.Add(pkgPath, scriptInfo); + yield return pkgPath; + } + } + } + } + } + + // Create package object for each found resource directory + public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary scriptDictionary) + { + string xmlFilePath = string.Empty; + var parentDir = new DirectoryInfo(pkgPath).Parent; + + // find package name + string pkgName = Utils.GetInstalledPackageName(pkgPath); + _cmdletPassedIn.WriteDebug(string.Format("OutputPackageObject:: package name is {0}.", pkgName)); + // Find xml file + // if the package path is in the deserialized script dictionary, just return that + if (scriptDictionary.ContainsKey(pkgPath)) + { + return scriptDictionary[pkgPath]; + } + // else if the pkgName from pkgpath is a script, find the xml file + else if (File.Exists(pkgPath)) + { + xmlFilePath = System.IO.Path.Combine(parentDir.ToString(), "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); + } + // else we assume it's a module, and look for the xml path that way + else + { + xmlFilePath = System.IO.Path.Combine(pkgPath, "PSGetModuleInfo.xml"); + } + + // Read metadata from XML and parse into PSResourceInfo object + _cmdletPassedIn.WriteVerbose(string.Format("Reading package metadata from: '{0}'", xmlFilePath)); + if (!TryRead(xmlFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + _cmdletPassedIn.WriteVerbose(errorMsg); + } + else + { + _cmdletPassedIn.WriteDebug(string.Format("Found module XML: '{0}'", xmlFilePath)); + return psGetInfo; + } + + return null; + } + } +} diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs new file mode 100644 index 000000000..aff8f16c6 --- /dev/null +++ b/src/code/UninstallPSResource.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Threading; +using NuGet.Versioning; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Uninstall-PSResource uninstalls a package found in a module or script installation path. + /// + [Cmdlet(VerbsLifecycle.Uninstall, "PSResource", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true, HelpUri = "")] + public sealed class UninstallPSResource : PSCmdlet + { + #region Parameters + /// + /// Specifies the exact names of resources to uninstall. + /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies the version or version range of the package to be uninstalled. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = InputObjectSet)] + [ValidateNotNullOrEmpty] + public PSResourceInfo[] InputObject { get; set; } + + /// + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Force { get; set; } + #endregion + + #region Members + private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectSet = "InputObjectSet"; + public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; + private CancellationTokenSource _source; + private CancellationToken _cancellationToken; + VersionRange _versionRange; + List _pathsToSearch = new List(); + #endregion + + #region Methods + protected override void BeginProcessing() + { + _source = new CancellationTokenSource(); + _cancellationToken = _source.Token; + + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (ParameterSetName.Equals("NameParameterSet") && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + _pathsToSearch = Utils.GetAllResourcePaths(this); + } + + protected override void ProcessRecord() + { + switch (ParameterSetName) + { + case NameParameterSet: + if (!UninstallPkgHelper()) + { + // any errors should be caught lower in the stack, this debug statement will let us know if there was an unusual failure + WriteDebug("Did not successfully uninstall all packages"); + } + break; + + case InputObjectSet: + // the for loop will use type PSObject in order to pull the properties from the pkg object + foreach (PSResourceInfo pkg in InputObject) + { + if (pkg == null) + { + continue; + } + + // attempt to parse version + if (!Utils.TryParseVersionOrVersionRange(pkg.Version.ToString(), out VersionRange _versionRange)) + { + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", pkg.Version.ToString(), pkg.Name); + var ex = new ArgumentException(exMessage); + var ErrorParsingVersion = new ErrorRecord(ex, "ErrorParsingVersion", ErrorCategory.ParserError, null); + WriteError(ErrorParsingVersion); + } + + Name = new string[] { pkg.Name }; + if (!String.IsNullOrWhiteSpace(pkg.Name) && !UninstallPkgHelper()) + { + // specific errors will be displayed lower in the stack + var exMessage = String.Format(string.Format("Did not successfully uninstall package {0}", pkg.Name)); + var ex = new ArgumentException(exMessage); + var UninstallResourceError = new ErrorRecord(ex, "UninstallResourceError", ErrorCategory.InvalidOperation, null); + WriteError(UninstallResourceError); + } + } + break; + + default: + WriteDebug("Invalid parameter set"); + break; + } + } + + + private bool UninstallPkgHelper() + { + var successfullyUninstalled = false; + + GetHelper getHelper = new GetHelper(_cancellationToken, this); + List dirsToDelete = getHelper.FilterPkgPathsByName(Name, _pathsToSearch); + + // Checking if module or script + // a module path will look like: + // ./Modules/TestModule/0.0.1 + // note that the xml file is located in this path, eg: ./Modules/TestModule/0.0.1/PSModuleInfo.xml + // a script path will look like: + // ./Scripts/TestScript.ps1 + // note that the xml file is located in ./Scripts/InstalledScriptInfos, eg: ./Scripts/InstalledScriptInfos/TestScript_InstalledScriptInfo.xml + + string pkgName = string.Empty; + + foreach (string pkgPath in getHelper.FilterPkgPathsByVersion(_versionRange, dirsToDelete)) + { + pkgName = Utils.GetInstalledPackageName(pkgPath); + + if (!ShouldProcess(string.Format("Uninstall resource '{0}' from the machine.", pkgName))) + { + this.WriteDebug("ShouldProcess is set to false."); + continue; + } + + if (pkgPath.EndsWith(".ps1")) + { + successfullyUninstalled = UninstallScriptHelper(pkgPath, pkgName); + } + else + { + successfullyUninstalled = UninstallModuleHelper(pkgPath, pkgName); + } + + // if we can't find the resource, write non-terminating error and return + if (!successfullyUninstalled) + { + string message = Version == null || Version.Trim().Equals("*") ? + string.Format("Could not find any version of the resource '{0}' in any path", pkgName) : + string.Format("Could not find verison '{0}' of the resource '{1}' in any path", Version, pkgName); + + WriteError(new ErrorRecord( + new PSInvalidOperationException(message), + "ErrorRetrievingSpecifiedResource", + ErrorCategory.ObjectNotFound, + this)); + } + } + + return successfullyUninstalled; + } + + /* uninstalls a module */ + private bool UninstallModuleHelper(string pkgPath, string pkgName) + { + var successfullyUninstalledPkg = false; + + // if -Force is not specified and the pkg is a dependency for another package, + // an error will be written and we return false + if (!Force && CheckIfDependency(pkgName)) + { + return false; + } + + DirectoryInfo dir = new DirectoryInfo(pkgPath); + dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; + + try + { + // delete recursively + dir.Delete(true); + WriteVerbose(string.Format("Successfully uninstalled '{0}' from path '{1}'", pkgName, dir.FullName)); + + successfullyUninstalledPkg = true; + + // finally: check to see if there's anything left in the parent directory, if not, delete that as well + try + { + if (Directory.GetDirectories(dir.Parent.FullName).Length == 0) + { + Directory.Delete(dir.Parent.FullName, true); + } + } + catch (Exception e) { + // write error + var exMessage = String.Format("Parent directory '{0}' could not be deleted: {1}", dir.Parent.FullName, e.Message); + var ex = new ArgumentException(exMessage); + var ErrorDeletingParentDirectory = new ErrorRecord(ex, "ErrorDeletingParentDirectory", ErrorCategory.InvalidArgument, null); + WriteError(ErrorDeletingParentDirectory); + } + } + catch (Exception err) { + // write error + var exMessage = String.Format("Directory '{0}' could not be deleted: {1}", dir.FullName, err.Message); + var ex = new ArgumentException(exMessage); + var ErrorDeletingDirectory = new ErrorRecord(ex, "ErrorDeletingDirectory", ErrorCategory.PermissionDenied, null); + WriteError(ErrorDeletingDirectory); + } + + return successfullyUninstalledPkg; + } + + /* uninstalls a script */ + private bool UninstallScriptHelper(string pkgPath, string pkgName) + { + var successfullyUninstalledPkg = false; + + // delete the appropriate file + try + { + File.Delete(pkgPath); + successfullyUninstalledPkg = true; + + string scriptXML = string.Empty; + try + { + // finally: Delete the xml from the InstalledModulesInfo directory + DirectoryInfo dir = new DirectoryInfo(pkgPath); + DirectoryInfo parentDir = dir.Parent; + scriptXML = Path.Combine(parentDir.FullName, "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); + if (File.Exists(scriptXML)) + { + File.Delete(scriptXML); + } + } + catch (Exception e) + { + var exMessage = String.Format("Script metadata file '{0}' could not be deleted: {1}", scriptXML, e.Message); + var ex = new ArgumentException(exMessage); + var ErrorDeletingScriptMetadataFile = new ErrorRecord(ex, "ErrorDeletingScriptMetadataFile", ErrorCategory.PermissionDenied, null); + WriteError(ErrorDeletingScriptMetadataFile); + } + } + catch (Exception err){ + var exMessage = String.Format("Script '{0}' could not be deleted: {1}", pkgPath, err.Message); + var ex = new ArgumentException(exMessage); + var ErrorDeletingScript = new ErrorRecord(ex, "ErrorDeletingScript", ErrorCategory.PermissionDenied, null); + WriteError(ErrorDeletingScript); + } + + return successfullyUninstalledPkg; + } + + private bool CheckIfDependency(string pkgName) + { + // this is a primitive implementation + // TODO: implement a dependencies database for querying dependency info + // cannot uninstall a module if another module is dependent on it + using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) + { + // Check all modules for dependencies + var results = pwsh.AddCommand("Get-Module").AddParameter("ListAvailable").Invoke(); + + // Structure of LINQ call: + // Results is a collection of PSModuleInfo objects that contain a property listing module dependencies, "RequiredModules". + // RequiredModules is collection of PSModuleInfo objects that need to be iterated through to see if any of them are the pkg we're trying to uninstall + // If we anything from the final call gets returned, there is a dependency on this pkg. + IEnumerable pkgsWithRequiredModules = new List(); + try + { + pkgsWithRequiredModules = results.Where( + p => ((ReadOnlyCollection)p.Properties["RequiredModules"].Value).Where( + rm => rm.Name.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)).Any()); + } + catch (Exception e) { + var exMessage = String.Format("Error checking if resource is a dependency: {0}. If you would still like to uninstall, rerun the command with -Force", e.Message); + var ex = new ArgumentException(exMessage); + var DependencyCheckError = new ErrorRecord(ex, "DependencyCheckError", ErrorCategory.OperationStopped, null); + WriteError(DependencyCheckError); + } + + if (pkgsWithRequiredModules.Any()) + { + var uniquePkgNames = pkgsWithRequiredModules.Select(p => p.Properties["Name"].Value).Distinct().ToArray(); + var strUniquePkgNames = string.Join(",", uniquePkgNames); + + var exMessage = String.Format("Cannot uninstall '{0}', the following package(s) take a dependency on this package: {1}. If you would still like to uninstall, rerun the command with -Force", pkgName, strUniquePkgNames); + var ex = new ArgumentException(exMessage); + var PackageIsaDependency = new ErrorRecord(ex, "PackageIsaDependency", ErrorCategory.OperationStopped, null); + WriteError(PackageIsaDependency); + return true; + } + } + return false; + } + #endregion + } +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 02d13e40d..7f90bf7c6 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,57 +1,183 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Management.Automation.Language; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - internal static class Utils - { - #region Public methods - - public static string TrimQuotes(string name) - { - return name.Trim('\'', '"'); - } - - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) - { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } - } - - if (!quotesNeeded) - { - return name; - } - - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i GetAllResourcePaths(PSCmdlet psCmdlet) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + List resourcePaths = psModulePath.Split(';').ToList(); + List pathsToSearch = new List(); + var PSVersion6 = new Version(6, 0); + var isCorePS = psCmdlet.Host.Version >= PSVersion6; + string myDocumentsPath; + string programFilesPath; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; + + myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and MacOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); + programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); + } + + // will search first in PSModulePath, then will search in default paths + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); + + // resourcePaths should now contain, eg: + // ./PowerShell/Scripts + // ./PowerShell/Modules + // add all module directories or script files + foreach (string path in resourcePaths) + { + psCmdlet.WriteDebug(string.Format("Retrieving directories in the path '{0}'", path)); + + if (path.EndsWith("Scripts")) + { + try + { + pathsToSearch.AddRange(Directory.GetFiles(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); + } + } + else + { + try + { + pathsToSearch.AddRange(Directory.GetDirectories(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); + } + } + } + + // resourcePaths should now contain eg: + // ./PowerShell/Scripts/Test-Script.ps1 + // ./PowerShell/Modules/TestModule + // need to use .ToList() to cast the IEnumerable to type List + pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + pathsToSearch.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); + + return pathsToSearch; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) + { + strArray[i] = list[i] as string; + } + + return strArray; + } + + #endregion + } +} diff --git a/srcOld/code/UninstallPSResource.cs b/srcOld/code/UninstallPSResource.cs deleted file mode 100644 index 9ed733769..000000000 --- a/srcOld/code/UninstallPSResource.cs +++ /dev/null @@ -1,554 +0,0 @@ - -using System; -using System.Management.Automation; -using System.Threading; -using NuGet.Versioning; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Globalization; -using System.Collections.ObjectModel; -using static System.Environment; -using System.Security.Principal; -using System.Runtime.InteropServices; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - - - /// - /// Uninstall - /// - - [Cmdlet(VerbsLifecycle.Uninstall, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class UninstallPSResource : PSCmdlet - { - // private string PSGalleryRepoName = "PSGallery"; - - /// - /// Specifies the exact names of resources to install from a repository. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name; // = new string[0]; - - - /// - /// Specifies the version or version range of the package to be installed - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Version - { - get - { return _version; } - - set - { _version = value; } - } - private string _version; - - - /// - /// Specifies to allow ONLY prerelease versions to be uninstalled - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter PrereleaseOnly - { - get - { return _prereleaseOnly; } - - set - { _prereleaseOnly = value; } - } - private SwitchParameter _prereleaseOnly; - - - /// - /// Overrides warning messages about resource installation conflicts. - /// If a resource with the same name already exists on the computer, Force allows for multiple versions to be installed. - /// If there is an existing resource with the same name and version, Force does NOT overwrite that version. - /// - [Parameter()] - public SwitchParameter Force - { - get { return _force; } - - set { _force = value; } - } - private SwitchParameter _force; - - public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - private string programFilesPath; - private string myDocumentsPath; - List dirsToDelete; - - private CancellationTokenSource source; - private CancellationToken cancellationToken; - - NuGetVersion nugetVersion; - VersionRange versionRange; - - - /// - /// - protected override void ProcessRecord() - { - source = new CancellationTokenSource(); - cancellationToken = source.Token; - - - - NuGetVersion.TryParse(_version, out nugetVersion); - - - if (nugetVersion == null) - { - VersionRange.TryParse(_version, out versionRange); - } - - var consoleIsElevated = false; - -#if NET472 - // WindowsPS - var id = System.Security.Principal.WindowsIdentity.GetCurrent(); - consoleIsElevated = (id.Owner != id.User); - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "WindowsPowerShell"); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "WindowsPowerShell"); -#else - // If Windows OS (PS6+) - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var id = System.Security.Principal.WindowsIdentity.GetCurrent(); - consoleIsElevated = (id.Owner != id.User); - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "PowerShell"); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "PowerShell"); - } - else - { - // Paths are the same for both Linux and MacOS - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); - programFilesPath = Path.Combine("usr", "local", "share", "Powershell"); - - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) - { - var results = pwsh.AddCommand("id").AddParameter("u").Invoke(); - } - } -#endif - - - foreach (var pkgName in _name) - { - var successfullyUninstalledPkg = UninstallPkgHelper(pkgName, cancellationToken); - if (successfullyUninstalledPkg) - { - Console.WriteLine("Successfully uninstalled {0}", pkgName); - } - else - { - Console.WriteLine("Did not successfully uninstall {0}", pkgName); - } - } - } - - - - /// just uninstall module, not dependencies - private bool UninstallPkgHelper(string pkgName, CancellationToken cancellationToken) - { - var successfullyUninstalled = false; - - dirsToDelete = new List(); - - if (String.IsNullOrWhiteSpace(pkgName)) - { - return successfullyUninstalled; - } - - var psModulesPathMyDocuments = Path.Combine(myDocumentsPath, "Modules"); - var psModulesPathProgramFiles = Path.Combine(programFilesPath, "Modules"); - - var psScriptPathMyDocuments = Path.Combine(myDocumentsPath, "Scripts"); - var psScriptsPathProgramFiles = Path.Combine(programFilesPath, "Scripts"); - - - /* Modules */ - // My Documents - var dirNameMyDocuments = Path.Combine(psModulesPathMyDocuments, pkgName); - var versionDirsMyDocuments = (Directory.Exists(dirNameMyDocuments)) ? Directory.GetDirectories(dirNameMyDocuments) : null; - var parentDirFilesMyDocuments = (Directory.Exists(dirNameMyDocuments)) ? Directory.GetFiles(dirNameMyDocuments) : null; - // Program Files - var dirNameProgramFiles = Path.Combine(psModulesPathProgramFiles, pkgName); - var versionDirsProgramFiles = (Directory.Exists(dirNameProgramFiles)) ? Directory.GetDirectories(dirNameProgramFiles) : null; - var parentDirFilesProgramFiles = (Directory.Exists(dirNameProgramFiles)) ? Directory.GetFiles(dirNameProgramFiles) : null; - - - - - /* Scripts */ - // My Documents - var scriptPathMyDocuments = Path.Combine(psScriptPathMyDocuments, pkgName + ".ps1"); - // Program Files - var scriptPathProgramFiles = Path.Combine(psScriptsPathProgramFiles, pkgName + ".ps1"); - - - var psModulesPathAllDirs = new List(); - if (Directory.Exists(psModulesPathMyDocuments)) - { - psModulesPathAllDirs.AddRange(Directory.GetDirectories(psModulesPathMyDocuments).ToList()); - } - if (Directory.Exists(psModulesPathProgramFiles)) - { - psModulesPathAllDirs.AddRange(Directory.GetDirectories(psModulesPathProgramFiles).ToList()); - } - - var psScriptsPathAllFiles = new List(); - if (Directory.Exists(psScriptPathMyDocuments)) - { - psScriptsPathAllFiles.AddRange(Directory.GetFiles(psScriptPathMyDocuments).ToList()); /// may need to change this to get files - } - if (Directory.Exists(psModulesPathMyDocuments)) - { - psScriptsPathAllFiles.AddRange(Directory.GetFiles(psModulesPathMyDocuments).ToList()); - } - - - var foundInMyDocuments = (Directory.Exists(dirNameMyDocuments) && (versionDirsMyDocuments.Any() || parentDirFilesMyDocuments.Any())) || File.Exists(scriptPathMyDocuments); // check for scripts - var foundInProgramFiles = (Directory.Exists(dirNameProgramFiles) && (versionDirsProgramFiles.Any() || parentDirFilesProgramFiles.Any())) || File.Exists(scriptPathProgramFiles); - - // First check if module or script is installed by looking in the specified modules path and scripts path - var foundResourceObj = foundInMyDocuments || foundInProgramFiles || File.Exists(scriptPathMyDocuments) - || File.Exists(scriptPathProgramFiles) ? true : false; - - - var isScript = (File.Exists(scriptPathMyDocuments) || File.Exists(scriptPathProgramFiles)) ? true : false; - - - // If we can't find the resource, just return - if (!foundResourceObj) - { - return successfullyUninstalled; - } - - - if (!isScript) - { - // Try removing from my documents - if (foundInMyDocuments) - { - successfullyUninstalled = UninstallModuleHelper(pkgName, dirNameMyDocuments, versionDirsMyDocuments, parentDirFilesMyDocuments, cancellationToken); - } - else if (foundInProgramFiles) - { - // try removing from program files - successfullyUninstalled = UninstallModuleHelper(pkgName, dirNameProgramFiles, versionDirsProgramFiles, parentDirFilesProgramFiles, cancellationToken); - } - } - else - { - // Try removing from my documents - if (foundInMyDocuments) - { - successfullyUninstalled = UninstallScriptHelper(pkgName, psScriptPathMyDocuments, scriptPathMyDocuments, cancellationToken); - } - else if (foundInProgramFiles) - { - // try removing from program files - successfullyUninstalled = UninstallScriptHelper(pkgName, psScriptsPathProgramFiles, scriptPathProgramFiles, cancellationToken); - } - } - - - - - return successfullyUninstalled; - - } - - - - - - - - /* Uninstall Module */ - private bool UninstallModuleHelper(string pkgName, string dirName, string[] versionDirs, string[] parentDirFiles, CancellationToken cancellationToken) - { - var successfullyUninstalledPkg = false; - - - // If prereleaseOnly is specified, we'll only take into account prerelease versions of pkgs - if (_prereleaseOnly) - { - List prereleaseOnlyVersionDirs = new List(); - foreach (var dir in versionDirs) - { - var nameOfDir = Path.GetFileName(dir); - var nugVersion = NuGetVersion.Parse(nameOfDir); - - if (nugVersion.IsPrerelease) - { - prereleaseOnlyVersionDirs.Add(dir); - } - } - versionDirs = prereleaseOnlyVersionDirs.ToArray(); - } - - - // if the version specificed is a version range - if (versionRange != null) - { - - foreach (var versionDirPath in versionDirs) - { - var nameOfDir = Path.GetFileName(versionDirPath); - var nugVersion = NuGetVersion.Parse(nameOfDir); - - if (versionRange.Satisfies(nugVersion)) - { - dirsToDelete.Add(versionDirPath); - } - } - } - else if (nugetVersion != null) - { - // if the version specified is a version - - dirsToDelete.Add(nugetVersion.ToNormalizedString()); - } - else - { - // if no version is specified, just delete the latest version - Array.Sort(versionDirs); - - dirsToDelete.Add(versionDirs[versionDirs.Length - 1]); - } - - - - - // if dirsToDelete is empty... meaning we didn't find any modules, it's possible it's a script - if (dirsToDelete.Any()) - { - /// This is a primitive implementation - /// TODO: implement a dependencies database for querying dependency info - /// Cannot uninstall a module if another module is dependent on it - - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) - { - // Check all modules for dependencies - var results = pwsh.AddCommand("Get-Module").AddParameter("ListAvailable").Invoke(); - - // Structure of LINQ call: - // Results is a collection of PSModuleInfo objects that contain a property listing module dependencies, "RequiredModules". - // RequiredModules is collection of PSModuleInfo objects that need to be iterated through to see if any of them are the pkg we're trying to uninstall - // If we anything from the final call gets returned, there is a dependency on this pkg. - var pkgsWithRequiredModules = results.Where(p => ((ReadOnlyCollection)p.Properties["RequiredModules"].Value).Where(rm => rm.Name.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)).Any()); - - - //.Select(p => (p.Properties.Match("Name"), p.Properties.Match("Version"))); - - if (pkgsWithRequiredModules.Any()) - { - var uniquePkgNames = pkgsWithRequiredModules.Select(p => p.Properties["Name"].Value).Distinct().ToArray(); - - var strUniquePkgNames = string.Join(",", uniquePkgNames); - - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Cannot uninstall {0}, the following package(s) take a dependency on this package: {1}", pkgName, strUniquePkgNames)); - - } - } - - - // Delete the appropriate directories - foreach (var dirVersion in dirsToDelete) - { - var dirNameVersion = Path.Combine(dirName, dirVersion); - - // we know it's installed because it has an xml - if (Directory.Exists(dirNameVersion)) - { - var dir = new DirectoryInfo(dirNameVersion.ToString()); - dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; - // Delete recursively - dir.Delete(true); - successfullyUninstalledPkg = true; - } - } - - - - // Finally: - // Check to see if there's anything left in the parent directory, if not, delete that as well - if (Directory.GetDirectories(dirName).Length == 0) - { - Directory.Delete(dirName, true); - } - - } - - - - - return successfullyUninstalledPkg; - } - - - - - - - /* Uninstall script helper */ - private bool UninstallScriptHelper(string pkgName, string scriptsPath, string fullScriptPath, CancellationToken cancellationToken) - { - /* Currently the way PSGet operates is that only one script can be installed at a time. - * I think it's worth seeing if we want allow for multiple scripts to be instlled at a time, - * and if so, we need to rethink the architecture of the scripts installation path. */ - - var successfullyUninstalledPkg = false; - - // TODO: open xml and read from it - var xmlFileName = string.Concat(pkgName, "_InstalledScriptInfo.xml"); - var scriptXMLPath = Path.Combine(scriptsPath, "InstalledScriptInfos", xmlFileName); - - ReadOnlyPSMemberInfoCollection versionInfo; - NuGetVersion nugetVersion; - using (StreamReader sr = new StreamReader(scriptXMLPath)) - { - - string text = sr.ReadToEnd(); - var deserializedObj = (PSObject)PSSerializer.Deserialize(text); - - versionInfo = deserializedObj.Properties.Match("Version"); - }; - - - NuGetVersion.TryParse(versionInfo.FirstOrDefault().Value.ToString(), out nugetVersion); - - - - // If prereleaseOnly is specified, we'll only take into account prerelease versions of pkgs - if (_prereleaseOnly) - { - // If the installed script is a prerelease, we can continue processing it - if (nugetVersion.IsPrerelease) - { - dirsToDelete.Add(fullScriptPath); - } - else - { - return successfullyUninstalledPkg; - } - } - - - if (_version == null) - { - // if no version is specified, just delete the latest version (right now the only version) - dirsToDelete.Add(fullScriptPath); - } - // if the version specificed is a version range - else - { - // Parse the version passed in and compare it to the script version - NuGetVersion argNugetVersion; - NuGetVersion.TryParse(_version, out argNugetVersion); - - VersionRange versionRange; - if (argNugetVersion != null) - { - // exact version - versionRange = new VersionRange(argNugetVersion, true, argNugetVersion, true, null, null); - } - else - { - // check if version range - versionRange = VersionRange.Parse(_version); - } - - - - if (versionRange.Satisfies(nugetVersion)) - { - dirsToDelete.Add(fullScriptPath); - } - } - - - - - // if dirsToDelete is empty... meaning we didn't find any scripts - if (dirsToDelete.Any()) - { - /// This is a primitive implementation - /// TODO: implement a dependencies database for querying dependency info - /// Cannot uninstall a package if another module is dependent on it - - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) - { - // Check all modules for dependencies - var results = pwsh.AddCommand("Get-Module").AddParameter("ListAvailable").Invoke(); - - // Structure of LINQ call: - // Results is a collection of PSModuleInfo objects that contain a property listing module dependencies, "RequiredModules". - // RequiredModules is collection of PSModuleInfo objects that need to be iterated through to see if any of them are the pkg we're trying to uninstall - // If we anything from the final call gets returned, there is a dependency on this pkg. - - // check for nested modules as well - var pkgsWithRequiredModules = results.Where(p => ((ReadOnlyCollection)p.Properties["RequiredModules"].Value).Where(rm => rm.Name.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)).Any()); - - if (pkgsWithRequiredModules.Any()) - { - var uniquePkgNames = pkgsWithRequiredModules.Select(p => p.Properties["Name"].Value).Distinct().ToArray(); - - var strUniquePkgNames = string.Join(",", uniquePkgNames); - - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Cannot uninstall {0}, the following package(s) take a dependency on this package: {1}", pkgName, strUniquePkgNames)); - - } - } - - - - - - - // Delete the appropriate file - if (File.Exists(fullScriptPath)) - { - File.Delete(fullScriptPath); - successfullyUninstalledPkg = true; - } - - // Finally: - // Delete the xml from the InstalledModulesInfo directory - var scriptXML = Path.Combine(scriptsPath, "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); - if (File.Exists(scriptXML)) - { - File.Delete(scriptXML); - } - - - } - - - - return successfullyUninstalledPkg; - } - - - } -} diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 new file mode 100644 index 000000000..a1258d3ef --- /dev/null +++ b/test/UninstallPSResource.Tests.ps1 @@ -0,0 +1,189 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<#// Temporarily comment out tests until Install-PSResource is complete +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Uninstall-PSResource for Modules' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + Get-NewPSResourceRepositoryFile + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Uninstall a specific module by name" { + $pkg = Uninstall-PSResource -name Bicep + } + + It "Uninstall a list of modules by name" { + $pkg = Uninstall-PSResource -Name BaseTestPackage, bicep + } + + It "Uninstall a module when given name and specifying all versions" { + $res = Uninstall-PSResource -Name "Carbon" -version "*" + $res | Should -BeNullOrEmpty + } + + It "Uninstall module when given Name and specifying exact version" { + $res = Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" + $res | Should -BeNullOrEmpty + } + + It "Uninstall module when given Name to " -TestCases @( + @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, + @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, + @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + ) { + param($Version, $ExpectedVersion) + $res = Uninstall-PSResource -Name "Pester" -Version $Version -Repository $TestGalleryName + $res.Name | Should -Be "Pester" + $res.Version | Should -Be $ExpectedVersion + } + + It "Do not uninstall module with incorrectly formatted version such as " -TestCases @( + @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, + @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"}, + @{Version='[1.*.0]'; Description="version with wilcard in middle"}, + @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, + @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.5.0.]'; Description="version with missing digit at end"}, + @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + ) { + param($Version, $Description) + + $res = $null + try { + $res = Uninstall-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore + } + catch {} + + $res | Should -BeNullOrEmpty + } + + It "Does not uninstall when given Name and an invalid version" { + $res = Uninstall-PSResource -Name "ContosoServer" -Version "(0.0.0.1)" + $res | Should -BeNullOrEmpty + } + + It "Uninstall lastest version of a particular module " { + # test_module resource's latest version is a prerelease version, before that it has a non-prerelease version + $res = Uninstall-PSResource -Name "test_module" + $res.Version | Should -Be "5.0.0.0" + + $resPrerelease = Uninstall-PSResource -Name "test_module" -Prerelease + $resPrerelease.Version | Should -Be "5.2.5.0" + } + + It "Uninstall module using -WhatIf, should not uninstall the module" { + $res = Uninstall-PSResource -Name "ActiveDirectoryTools" -WhatIf + } + + It "Do not Uninstall module that is a dependency for another module" { + $res = Uninstall-PSResource -Name "PackageManagement" + } + + It "Uninstall module that is a dependency for another module using -Force" { + $res = Uninstall-PSResource -Name "PackageManagement" -Force + } +} + + +Describe 'Test Uninstall-PSResource for Scripts' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + Get-NewPSResourceRepositoryFile + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Uninstall a specific script by name" { + $pkg = Uninstall-PSResource -name Test-RPC + } + + It "Uninstall a list of scripts by name" { + $pkg = Uninstall-PSResource -Name adsql, airoute + } + + It "Uninstall a script when given name and specifying all versions" { + $res = Uninstall-PSResource -Name "NetworkingDSC" -version "*" + $res | Should -BeNullOrEmpty + } + + It "Uninstall script when given Name and specifying exact version" { + $res = Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" + $res | Should -BeNullOrEmpty + } + + It "Does not uninstall a script when given Name and a version that does not exist" { + $res = Uninstall-PSResource -Name "ContosoServer" -Version "3.0.0" + $res | Should -BeNullOrEmpty + } + + It "Uninstall script when given Name to " -TestCases @( + @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, + @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, + @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + ) { + param($Version, $ExpectedVersion) + $res = Uninstall-PSResource -Name "Pester" -Version $Version -Repository $TestGalleryName + $res.Name | Should -Be "Pester" + $res.Version | Should -Be $ExpectedVersion + } + + It "Do not uninstall module with incorrectly formatted version such as " -TestCases @( + @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, + @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"}, + @{Version='[1.*.0]'; Description="version with wilcard in middle"}, + @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, + @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.5.0.]'; Description="version with missing digit at end"}, + @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + ) { + param($Version, $Description) + + $res = $null + try { + $res = Uninstall-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore + } + catch {} + + $res | Should -BeNullOrEmpty + } + + It "Does not uninstall when given Name and an invalid version" { + $res = Uninstall-PSResource -Name "ContosoServer" -Version "(0.0.0.1)" + $res | Should -BeNullOrEmpty + } + + It "Uninstall script using -WhatIf" { + $res = Uninstall-PSResource -Name "ActiveDirectoryTools" -WhatIf + } +} +#> \ No newline at end of file From 0a21efde263d1c72885af9edc140d63b0ea41d09 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 4 Jun 2021 23:13:18 -0700 Subject: [PATCH 007/276] WIP: Refactoring of Publish-PSResource (#362) --- help/Publish-PSResource.md | 171 +----- src/code/NuGetLogger.cs | 196 +++++++ src/code/PublishPSResource.cs | 926 +++++++++++++++++++++++++++++++ test/PublishPSResource.Tests.ps1 | 284 ++++++++++ 4 files changed, 1429 insertions(+), 148 deletions(-) create mode 100644 src/code/NuGetLogger.cs create mode 100644 src/code/PublishPSResource.cs create mode 100644 test/PublishPSResource.Tests.ps1 diff --git a/help/Publish-PSResource.md b/help/Publish-PSResource.md index c16236508..a73e53ceb 100644 --- a/help/Publish-PSResource.md +++ b/help/Publish-PSResource.md @@ -8,64 +8,49 @@ schema: 2.0.0 # Publish-PSResource ## SYNOPSIS -{{ Fill in the Synopsis }} +Publishes a specified module from the local computer to PSResource repository. ## SYNTAX ### PathParameterSet ``` Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] [-Path] - [-Credential ] [-SkipDependenciesCheck] [-ReleaseNotes ] [-Tags ] - [-LicenseUrl ] [-IconUrl ] [-ProjectUrl ] [-Exclude ] [-Nuspec ] + [-Credential ] [-SkipDependenciesCheck] [-WhatIf] [-Confirm] [] ``` ### PathLiteralParameterSet ``` Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] -LiteralPath - [-Credential ] [-SkipDependenciesCheck] [-ReleaseNotes ] [-Tags ] - [-LicenseUrl ] [-IconUrl ] [-ProjectUrl ] [-Exclude ] [-Nuspec ] + [-Credential ] [-SkipDependenciesCheck] [-WhatIf] [-Confirm] [] ``` -### CreateNuspecParameterSet -``` -Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] - [-Credential ] [-SkipDependenciesCheck] [-ReleaseNotes ] [-Tags ] - [-LicenseUrl ] [-IconUrl ] [-ProjectUrl ] [-Exclude ] [-WhatIf] [-Confirm] - [] -``` - -### ModuleNameParameterSet -``` -Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] - [-Credential ] [-SkipDependenciesCheck] [-Exclude ] [-WhatIf] [-Confirm] - [] -``` - -### NuspecParameterSet -``` -Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] - [-Credential ] [-SkipDependenciesCheck] [-Exclude ] [-Nuspec ] [-WhatIf] - [-Confirm] [] -``` - ## DESCRIPTION -{{ Fill in the Description }} +The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. + +It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. ## EXAMPLES ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Publish-PSResource -Path c:\Test-Module ``` -{{ Add example description here }} +This will publish the module 'Test-Module' to the highest priority repository + +### Example 2 +```powershell +PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' +``` + +This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. ## PARAMETERS ### -APIKey -{{ Fill APIKey Description }} +Specifies the API key that you want to use to publish a resource to the online gallery. ```yaml Type: System.String @@ -80,7 +65,7 @@ Accept wildcard characters: False ``` ### -Credential -{{ Fill Credential Description }} +Specifies a user account that has rights to a specific repository (used for finding dependencies). ```yaml Type: System.Management.Automation.PSCredential @@ -95,7 +80,7 @@ Accept wildcard characters: False ``` ### -DestinationPath -{{ Fill DestinationPath Description }} +Specifies the location to be used to publish a nupkg locally. ```yaml Type: System.String @@ -109,53 +94,8 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Exclude -{{ Fill Exclude Description }} - -```yaml -Type: System.String[] -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -IconUrl -{{ Fill IconUrl Description }} - -```yaml -Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet, CreateNuspecParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -LicenseUrl -{{ Fill LicenseUrl Description }} - -```yaml -Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet, CreateNuspecParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ### -LiteralPath -{{ Fill LiteralPath Description }} +Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is used exactly as entered. No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. Single quotation marks tell PowerShell not to interpret any characters as escape sequences. ```yaml Type: System.String @@ -169,23 +109,8 @@ Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` -### -Nuspec -{{ Fill Nuspec Description }} - -```yaml -Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet, NuspecParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ### -Path -{{ Fill Path Description }} +When specified, includes prerelease versions in search. ```yaml Type: System.String @@ -199,38 +124,8 @@ Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` -### -ProjectUrl -{{ Fill ProjectUrl Description }} - -```yaml -Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet, CreateNuspecParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -ReleaseNotes -{{ Fill ReleaseNotes Description }} - -```yaml -Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet, CreateNuspecParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ### -Repository -{{ Fill Repository Description }} +Specifies the repository to publish to. ```yaml Type: System.String @@ -245,7 +140,7 @@ Accept wildcard characters: False ``` ### -SkipDependenciesCheck -{{ Fill SkipDependenciesCheck Description }} +Bypasses the default check that all dependencies are present. ```yaml Type: System.Management.Automation.SwitchParameter @@ -259,21 +154,6 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Tags -{{ Fill Tags Description }} - -```yaml -Type: System.String[] -Parameter Sets: PathParameterSet, PathLiteralParameterSet, CreateNuspecParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ### -Confirm Prompts you for confirmation before running the cmdlet. @@ -308,17 +188,12 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). -## INPUTS - -### System.String ## OUTPUTS -### System.Object +### None ## NOTES ## RELATED LINKS -[]() - diff --git a/src/code/NuGetLogger.cs b/src/code/NuGetLogger.cs new file mode 100644 index 000000000..baa50d42b --- /dev/null +++ b/src/code/NuGetLogger.cs @@ -0,0 +1,196 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using NuGet.Common; + +// This class is needed for +public class NuGetLogger : ILogger +{ + private readonly ITestOutputHelper _output; + + public NuGetLogger() + { + } + + public NuGetLogger(ITestOutputHelper output) + { + _output = output; + } + + /// + /// Logged messages + /// + public ConcurrentQueue Messages { get; } = new ConcurrentQueue(); + public ConcurrentQueue DebugMessages { get; } = new ConcurrentQueue(); + public ConcurrentQueue VerboseMessages { get; } = new ConcurrentQueue(); + public ConcurrentQueue MinimalMessages { get; } = new ConcurrentQueue(); + public ConcurrentQueue ErrorMessages { get; } = new ConcurrentQueue(); + public ConcurrentQueue WarningMessages { get; } = new ConcurrentQueue(); + public ConcurrentQueue LogMessages { get; } = new ConcurrentQueue(); + public int Errors { get; set; } + public int Warnings { get; set; } + + public void LogDebug(string data) + { + Messages.Enqueue(data); + DebugMessages.Enqueue(data); + DumpMessage("DEBUG", data); + } + + public void LogError(string data) + { + Errors++; + Messages.Enqueue(data); + ErrorMessages.Enqueue(data); + DumpMessage("ERROR", data); + } + + public void LogInformation(string data) + { + Messages.Enqueue(data); + DumpMessage("INFO ", data); + } + + public void LogMinimal(string data) + { + Messages.Enqueue(data); + MinimalMessages.Enqueue(data); + DumpMessage("LOG ", data); + } + + public void LogVerbose(string data) + { + Messages.Enqueue(data); + VerboseMessages.Enqueue(data); + DumpMessage("TRACE", data); + } + + public void LogWarning(string data) + { + Warnings++; + Messages.Enqueue(data); + WarningMessages.Enqueue(data); + DumpMessage("WARN ", data); + } + + public void LogInformationSummary(string data) + { + Messages.Enqueue(data); + DumpMessage("ISMRY", data); + } + + private void DumpMessage(string level, string data) + { + _output?.WriteLine($"{level}: {data}"); + } + + public void Clear() + { + string msg; + while (Messages.TryDequeue(out msg)) + { + // do nothing + } + } + + public string ShowErrors() + { + return string.Join(Environment.NewLine, ErrorMessages); + } + + public string ShowWarnings() + { + return string.Join(Environment.NewLine, WarningMessages); + } + + public string ShowMessages() + { + return string.Join(Environment.NewLine, Messages); + } + + public void Log(LogLevel level, string data) + { + switch (level) + { + case LogLevel.Debug: + { + LogDebug(data); + break; + } + + case LogLevel.Error: + { + LogError(data); + break; + } + + case LogLevel.Information: + { + LogInformation(data); + break; + } + + case LogLevel.Minimal: + { + LogMinimal(data); + break; + } + + case LogLevel.Verbose: + { + LogVerbose(data); + break; + } + + case LogLevel.Warning: + { + LogWarning(data); + break; + } + } + } + + public Task LogAsync(LogLevel level, string data) + { + Log(level, data); + + return Task.FromResult(0); + } + + public void Log(ILogMessage message) + { + LogMessages.Enqueue(message); + + Log(message.Level, message.Message); + } + + public async Task LogAsync(ILogMessage message) + { + LogMessages.Enqueue(message); + + await LogAsync(message.Level, message.Message); + } +} + +// Summary: +// Represents a class which can be used to provide test output. +public interface ITestOutputHelper +{ + // Summary: + // Adds a line of text to the output. + // Parameters: + // message: + // The message + void WriteLine(string message); + // Summary: + // Formats a line of text and adds it to the output. + // Parameters: + // format: + // The message format + // args: + // The format arguments + void WriteLine(string format, params object[] args); +} diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs new file mode 100644 index 000000000..d8dca1118 --- /dev/null +++ b/src/code/PublishPSResource.cs @@ -0,0 +1,926 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Net.Http; +using System.Xml; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using MoreLinq; +using MoreLinq.Extensions; +using NuGet.Commands; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Packaging; +using NuGet.Versioning; + + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Publishes a module, script, or nupkg to a designated repository. + /// + [Cmdlet(VerbsData.Publish, "PSResource", SupportsShouldProcess = true, + HelpUri = "")] + public sealed + class PublishPSResource : PSCmdlet + { + #region Parameters + + /// + /// Specifies the API key that you want to use to publish a module to the online gallery. + /// + [Parameter()] + [ValidateNotNullOrEmpty] + public string APIKey { get; set; } + + /// + /// Specifies the repository to publish to. + /// + [Parameter()] + [ValidateNotNullOrEmpty] + public string Repository { get; set; } + + /// + /// Can be used to publish a nupkg locally. + /// + [Parameter()] + [ValidateNotNullOrEmpty] + public string DestinationPath + { + get + { return _destinationPath; } + + set + { _destinationPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } + } + private string _destinationPath; + + /// + /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. + /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "PathParameterSet")] + [ValidateNotNullOrEmpty] + public string Path + { + get + { return _path; } + + set + { + string resolvedPath = string.Empty; + if (!string.IsNullOrEmpty(value)) + { + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + } + + if (Directory.Exists(resolvedPath)) + { + _path = resolvedPath; + } + else if (File.Exists(resolvedPath) && resolvedPath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + { + _path = resolvedPath; + } + } + } + private string _path; + + /// + /// Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is used exactly as entered. + /// No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. + /// Single quotation marks tell PowerShell not to interpret any characters as escape sequences. + /// + [Parameter(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "PathLiteralParameterSet")] + [ValidateNotNullOrEmpty] + public string LiteralPath + { + get + { return _literalPath; } + + set + { + if (Directory.Exists(value)) + { + _literalPath = value; + } + else if (File.Exists(value) && value.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + { + _literalPath = value; + } + } + } + private string _literalPath; + + /// + /// Specifies a user account that has rights to a specific repository (used for finding dependencies). + /// + [Parameter()] + [ValidateNotNullOrEmpty] + public PSCredential Credential { get; set; } + + /// + /// Bypasses the default check that all dependencies are present. + /// + [Parameter()] + [ValidateNotNullOrEmpty] + public SwitchParameter SkipDependenciesCheck { get; set; } + + /// + /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. + /// + [Parameter(ValueFromPipelineByPropertyName = true)] + [ValidateNotNullOrEmpty] + public Uri Proxy { + set + { + if (value != null) + { + var ex = new ArgumentException("Not yet implemented."); + var ProxyNotImplemented = new ErrorRecord(ex, "ProxyNotImplemented", ErrorCategory.InvalidData, null); + WriteError(ProxyNotImplemented); + } + } + } + + /// + /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. + /// + [Parameter(ValueFromPipelineByPropertyName = true)] + [ValidateNotNullOrEmpty] + public PSCredential ProxyCredential { + set + { + if (value != null) + { + var ex = new ArgumentException("Not yet implemented."); + var ProxyCredentialNotImplemented = new ErrorRecord(ex, "ProxyCredentialNotImplemented", ErrorCategory.InvalidData, null); + WriteError(ProxyCredentialNotImplemented); + } + } + } + + #endregion + + #region members + private NuGetVersion _pkgVersion; + private string _pkgName; + private static char[] _PathSeparators = new [] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; + #endregion + + protected override void ProcessRecord() + { + string moduleManifestOrScriptPath; + FileInfo moduleFileInfo; + Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); + + // _path has been resolved, literal path does not need to be resolved + _path = string.IsNullOrEmpty(_path) ? _literalPath : _path; + // Returns the name of the file or the name of the directory, depending on path + var pkgFileOrDir = new DirectoryInfo(_path); + bool isScript = _path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase); + + // TODO: think about including the repository the resource is being published to + if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine.", _path))) + { + WriteDebug("ShouldProcess is set to false."); + return; + } + + if (isScript) + { + // Get the .psd1 file or .ps1 file + moduleManifestOrScriptPath = pkgFileOrDir.FullName; + moduleFileInfo = new FileInfo(moduleManifestOrScriptPath); + + // Check that script metadata is valid + // ParseScriptMetadata will write non-terminating error if it's unsucessful in parsing + parsedMetadataHash = ParseScriptMetadata(moduleFileInfo); + + var message = string.Empty; + // Check that the value is valid input + // If it does not contain 'Version' or the Version empty or whitespace, write error + if (!parsedMetadataHash.ContainsKey("Version") || String.IsNullOrWhiteSpace(parsedMetadataHash["Version"].ToString())) + { + message = "No version was provided in the script metadata. Script metadata must specify a version, author and description."; + var ex = new ArgumentException(message); + var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); + WriteError(InvalidScriptMetadata); + + return; + } + if (!parsedMetadataHash.ContainsKey("Author") || String.IsNullOrWhiteSpace(parsedMetadataHash["Author"].ToString())) + { + message = "No author was provided in the script metadata. Script metadata must specify a version, author and description."; + var ex = new ArgumentException(message); + var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); + WriteError(InvalidScriptMetadata); + + return; + } + if (!parsedMetadataHash.ContainsKey("Description") || String.IsNullOrWhiteSpace(parsedMetadataHash["Description"].ToString())) + { + message = "No description was provided in the script metadata. Script metadata must specify a version, author and description."; + var ex = new ArgumentException(message); + var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); + WriteError(InvalidScriptMetadata); + + return; + } + + // remove '.ps1' extension from file name + _pkgName = pkgFileOrDir.Name.Remove(pkgFileOrDir.Name.Length - 4); + } + else { + _pkgName = pkgFileOrDir.Name; + moduleManifestOrScriptPath = System.IO.Path.Combine(_path, _pkgName + ".psd1"); + moduleFileInfo = new FileInfo(moduleManifestOrScriptPath); + + // Validate that there's a module manifest + if (!File.Exists(moduleManifestOrScriptPath)) + { + var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", moduleManifestOrScriptPath); + var ex = new ArgumentException(message); + var moduleManifestNotFound = new ErrorRecord(ex, "moduleManifestNotFound", ErrorCategory.ObjectNotFound, null); + WriteError(moduleManifestNotFound); + + return; + } + + // validate that the module manifest has correct data + if (!IsValidModuleManifest(moduleManifestOrScriptPath)) + { + return; + } + } + + // Create a temp folder to push the nupkg to and delete it later + string outputDir = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString()); + if (!Directory.Exists(outputDir)) + { + try + { + Directory.CreateDirectory(outputDir); + } + catch (Exception e) { + var ex = new ArgumentException(e.Message); + var ErrorCreatingTempDir = new ErrorRecord(ex, "ErrorCreatingTempDir", ErrorCategory.InvalidData, null); + WriteError(ErrorCreatingTempDir); + + return; + } + } + + try + { + Hashtable dependencies; + + // Create a nuspec + // Right now parsedMetadataHash will be empty for modules and will contain metadata for scripts + string nuspec = string.Empty; + try + { + nuspec = CreateNuspec(outputDir, moduleFileInfo, out dependencies, parsedMetadataHash); + } + catch { + var message = "Nuspec creation failed."; + var ex = new ArgumentException(message); + var nuspecCreationFailed = new ErrorRecord(ex, "NuspecCreationFailed", ErrorCategory.ObjectNotFound, null); + WriteError(nuspecCreationFailed); + + return; + } + + if (string.IsNullOrEmpty(nuspec)) + { + // nuspec creation failed. + WriteDebug("Nuspec creation failed."); + return; + } + + // Find repository + PSRepositoryInfo repository = RepositorySettings.Read(new[] { Repository }, out string[] errorList).FirstOrDefault(); + if (repository == null) + { + var message = String.Format("The resource repository '{0}' is not a registered. Please run 'Register-PSResourceRepository' in order to publish to this repository.", Repository); + var ex = new ArgumentException(message); + var repositoryNotFound = new ErrorRecord(ex, "repositoryNotFound", ErrorCategory.ObjectNotFound, null); + WriteError(repositoryNotFound); + + return; + } + + string repositoryUrl = repository.Url.AbsoluteUri; + + + // Check if dependencies already exist within the repo if: + // 1) the resource to publish has dependencies and + // 2) the -SkipDependenciesCheck flag is not passed in + if (dependencies != null && !SkipDependenciesCheck) + { + // If error gets thrown, exit process record + if (!CheckDependenciesExist(dependencies, repositoryUrl)) + { + return; + } + } + + if (isScript) + { + // copy the script file to the temp directory + File.Copy(_path, System.IO.Path.Combine(outputDir, _pkgName + ".ps1"), true); + } + else + { + // Create subdirectory structure in temp folder + foreach (string dir in System.IO.Directory.GetDirectories(_path, "*", System.IO.SearchOption.AllDirectories)) + { + var dirName = dir.Substring(_path.Length).Trim(_PathSeparators); + System.IO.Directory.CreateDirectory(System.IO.Path.Combine(outputDir, dirName)); + } + + // Copy files over to temp folder + foreach (string fileNamePath in System.IO.Directory.GetFiles(_path, "*", System.IO.SearchOption.AllDirectories)) + { + var fileName = fileNamePath.Substring(_path.Length).Trim(_PathSeparators); + + // The user may have a .nuspec defined in the module directory + // If that's the case, we will not use that file and use the .nuspec that is generated via PSGet + // The .nuspec that is already in in the output directory is the one that was generated via the CreateNuspec method + var newFilePath = System.IO.Path.Combine(outputDir, fileName); + if (!File.Exists(newFilePath)) + { + System.IO.File.Copy(fileNamePath, newFilePath); + } + } + } + + var outputNupkgDir = System.IO.Path.Combine(outputDir, "nupkg"); + + // pack into a nupkg + try + { + if(!PackNupkg(outputDir, outputNupkgDir, nuspec)) + { + return; + } + } + catch (Exception e) + { + var message = string.Format("Error packing into .nupkg: '{0}'.", e.Message); + var ex = new ArgumentException(message); + var ErrorPackingIntoNupkg = new ErrorRecord(ex, "ErrorPackingIntoNupkg", ErrorCategory.NotSpecified, null); + WriteError(ErrorPackingIntoNupkg); + + // exit process record + return; + } + + PushNupkg(outputNupkgDir, repositoryUrl); + } + finally { + WriteDebug(string.Format("Deleting temporary directory '{0}'", outputDir)); + Directory.Delete(outputDir, recursive:true); + } + } + + private bool IsValidModuleManifest(string moduleManifestPath) + { + var isValid = false; + using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) + { + // use PowerShell cmdlet Test-ModuleManifest + // TODO: Test-ModuleManifest will throw an error if RequiredModules specifies a module that does not exist + // locally on the machine. Consider adding a -Syntax param to Test-ModuleManifest so that it only checks that + // the syntax is correct. In build/release pipelines for example, the modules listed under RequiredModules may + // not be locally available, but we still want to allow the user to publish. + var results = pwsh.AddCommand("Test-ModuleManifest").AddParameter("Path", moduleManifestPath).Invoke(); + + if (pwsh.HadErrors) + { + var message = string.Empty; + if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Author)) + { + message = "No author was provided in the module manifest. The module manifest must specify a version, author and description."; + } + else if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Description)) + { + message = "No description was provided in the module manifest. The module manifest must specify a version, author and description."; + } + else + { + // This will handle version errors + var error = pwsh.Streams.Error; + message = error[0].ToString(); + } + var ex = new ArgumentException(message); + var InvalidModuleManifest = new ErrorRecord(ex, "InvalidModuleManifest", ErrorCategory.InvalidData, null); + WriteError(InvalidModuleManifest); + } + else + { + isValid = true; + } + } + + return isValid; + } + + private string CreateNuspec( + string outputDir, + FileInfo moduleFileInfo, + out Hashtable requiredModules, + Hashtable parsedMetadataHash) + { + WriteVerbose("Creating new nuspec file."); + requiredModules = new Hashtable(); + + // A script will already have the metadata parsed into the parsedMetadatahash, + // a module will still need the module manifest to be parsed. + if (moduleFileInfo.Extension.Equals(".psd1", StringComparison.OrdinalIgnoreCase)) + { + // Parse the module manifest + System.Management.Automation.Language.Token[] tokens; + ParseError[] errors; + var ast = Parser.ParseFile(moduleFileInfo.FullName, out tokens, out errors); + + if (errors.Length > 0) + { + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo.FullName); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + WriteError(psdataParseError); + + return string.Empty; + } + else + { + var data = ast.Find(a => a is HashtableAst, false); + if (data != null) + { + parsedMetadataHash = (Hashtable) data.SafeGetValue(); + } + else + { + var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo.FullName); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + WriteError(psdataParseError); + + return string.Empty; + } + } + } + + /// now we have parsedMetadatahash to fill out the nuspec information + var nameSpaceUri = "http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"; + var doc = new XmlDocument(); + + // xml declaration is recommended, but not mandatory + XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "utf-8", null); + XmlElement root = doc.DocumentElement; + doc.InsertBefore(xmlDeclaration, root); + + // create top-level elements + XmlElement packageElement = doc.CreateElement("package", nameSpaceUri); + XmlElement metadataElement = doc.CreateElement("metadata", nameSpaceUri); + + Dictionary metadataElementsDictionary = new Dictionary(); + + // id is mandatory + metadataElementsDictionary.Add("id", _pkgName); + + string version = String.Empty; + if (parsedMetadataHash.ContainsKey("moduleversion")) + { + version = parsedMetadataHash["moduleversion"].ToString(); + } + else if (parsedMetadataHash.ContainsKey("version")) + { + version = parsedMetadataHash["version"].ToString(); + } + else + { + // no version is specified for the nuspec + var message = "There is no package version specified. Please specify a version before publishing."; + var ex = new ArgumentException(message); + var NoVersionFound = new ErrorRecord(ex, "NoVersionFound", ErrorCategory.InvalidArgument, null); + WriteError(NoVersionFound); + + return string.Empty; + } + + // Look for Prerelease tag + if (parsedMetadataHash.ContainsKey("PrivateData")) + { + if (parsedMetadataHash["PrivateData"] is Hashtable privateData && + privateData.ContainsKey("PSData")) + { + if (privateData["PSData"] is Hashtable psData && + psData.ContainsKey("Prerelease")) + { + if (psData["Prerelease"] is string preReleaseVersion) + { + version = string.Format(@"{0}-{1}", version, preReleaseVersion); + } + } + } + } + + if (NuGetVersion.TryParse(version, out _pkgVersion)) + { + metadataElementsDictionary.Add("version", _pkgVersion.ToNormalizedString()); + } + + if (parsedMetadataHash.ContainsKey("author")) + { + metadataElementsDictionary.Add("authors", parsedMetadataHash["author"].ToString().Trim()); + } + + if (parsedMetadataHash.ContainsKey("companyname")) + { + metadataElementsDictionary.Add("owners", parsedMetadataHash["companyname"].ToString().Trim()); + } + + // defaults to false + var requireLicenseAcceptance = parsedMetadataHash.ContainsKey("requirelicenseacceptance") ? parsedMetadataHash["requirelicenseacceptance"].ToString().ToLower().Trim() + : "false"; + metadataElementsDictionary.Add("requireLicenseAcceptance", requireLicenseAcceptance); + + if (parsedMetadataHash.ContainsKey("description")) + { + metadataElementsDictionary.Add("description", parsedMetadataHash["description"].ToString().Trim()); + } + + if (parsedMetadataHash.ContainsKey("releasenotes")) + { + metadataElementsDictionary.Add("releaseNotes", parsedMetadataHash["releasenotes"].ToString().Trim()); + } + + if (parsedMetadataHash.ContainsKey("copyright")) + { + metadataElementsDictionary.Add("copyright", parsedMetadataHash["copyright"].ToString().Trim()); + } + + string tags = moduleFileInfo.Extension.Equals(".psd1", StringComparison.OrdinalIgnoreCase) ? "PSModule" : "PSScript"; + if (parsedMetadataHash.ContainsKey("tags")) + { + if (parsedMetadataHash["tags"] != null) + { + tags += " " + parsedMetadataHash["tags"].ToString().Trim(); + } + } + metadataElementsDictionary.Add("tags", tags); + + if (parsedMetadataHash.ContainsKey("licenseurl")) + { + metadataElementsDictionary.Add("licenseUrl", parsedMetadataHash["licenseurl"].ToString().Trim()); + } + + if (parsedMetadataHash.ContainsKey("projecturl")) + { + metadataElementsDictionary.Add("projectUrl", parsedMetadataHash["projecturl"].ToString().Trim()); + } + + if (parsedMetadataHash.ContainsKey("iconurl")) + { + metadataElementsDictionary.Add("iconUrl", parsedMetadataHash["iconurl"].ToString().Trim()); + } + + // Example nuspec: + /* + + + + System.Management.Automation + 1.0.0 + Microsoft + Microsoft,PowerShell + false + MIT + https://licenses.nuget.org/MIT + Powershell_black_64.png + https://github.com/PowerShell/PowerShell + Example description here + Microsoft Corporation. All rights reserved. + en-US + PowerShell + + + + + + + + + */ + + foreach (var key in metadataElementsDictionary.Keys) + { + if (metadataElementsDictionary.TryGetValue(key, out string elementInnerText)) + { + XmlElement element = doc.CreateElement(key, nameSpaceUri); + element.InnerText = elementInnerText; + metadataElement.AppendChild(element); + } + else { + WriteDebug(string.Format("Creating XML element failed. Unable to get value from key '{0}'.", key)); + } + } + + requiredModules = ParseRequiredModules(parsedMetadataHash); + if (requiredModules != null) + { + XmlElement dependenciesElement = doc.CreateElement("dependencies", nameSpaceUri); + + foreach (string dependencyName in requiredModules.Keys) + { + XmlElement element = doc.CreateElement("dependency", nameSpaceUri); + + element.SetAttribute("id", dependencyName); + string dependencyVersion = requiredModules[dependencyName].ToString(); + if (!string.IsNullOrEmpty(dependencyVersion)) + { + element.SetAttribute("version", requiredModules[dependencyName].ToString()); + } + + dependenciesElement.AppendChild(element); + } + metadataElement.AppendChild(dependenciesElement); + } + + packageElement.AppendChild(metadataElement); + doc.AppendChild(packageElement); + + var nuspecFullName = System.IO.Path.Combine(outputDir, _pkgName + ".nuspec"); + doc.Save(nuspecFullName); + + WriteVerbose("The newly created nuspec is: " + nuspecFullName); + + return nuspecFullName; + } + + private Hashtable ParseRequiredModules(Hashtable parsedMetadataHash) + { + if (!parsedMetadataHash.ContainsKey("requiredmodules")) + { + return null; + } + + var requiredModules = parsedMetadataHash["requiredmodules"]; + + // Required modules can be: + // a. An array of hash tables of module name and version + // b. A single hash table of module name and version + // c. A string array of module names + // d. A single string module name + + var dependenciesHash = new Hashtable(); + if (LanguagePrimitives.TryConvertTo(requiredModules, out Hashtable[] moduleList)) + { + // instead of returning an array of hashtables, + // loop through the array and add each element of + foreach (Hashtable hash in moduleList) + { + dependenciesHash.Add(hash["ModuleName"], hash["ModuleVersion"]); + } + } + else if (LanguagePrimitives.TryConvertTo(requiredModules, out string[] moduleNames)) + { + foreach (var modName in moduleNames) + { + dependenciesHash.Add(modName, string.Empty); + } + } + + return dependenciesHash; + } + + private Hashtable ParseScriptMetadata(FileInfo moduleFileInfo) + { + // parse .ps1 - example .ps1 metadata: + /* <#PSScriptInfo + .VERSION 1.6 + .GUID abf490023 - 9128 - 4323 - sdf9a - jf209888ajkl + .AUTHOR Jane Doe + .COMPANYNAME Microsoft + .COPYRIGHT + .TAGS Windows MacOS + #> + + <# + .SYNOPSIS + Synopsis description here + .DESCRIPTION + Description here + .PARAMETER Name + .EXAMPLE + Example cmdlet here + #> + */ + // We're retrieving all the comments within a script and grabbing all the key/value pairs + // because there's no standard way to create metadata for a script. + Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); + + // parse comments out + System.Management.Automation.Language.Token[] tokens; + ParseError[] errors; + Parser.ParseFile(moduleFileInfo.FullName, out tokens, out errors); + + if (errors.Length > 0) + { + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo.FullName); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + WriteError(psdataParseError); + } + else + { + // Parse the script metadata located in comments + List parsedComments = new List(); + foreach (var token in tokens) + { + if (token.Kind == TokenKind.Comment) + { + // expecting only one or two comments + var commentText = token.Text; + parsedComments.AddRange(commentText.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries) ); + } + } + + foreach (var line in parsedComments) + { + if (line.StartsWith(".")) + { + char[] TrimBeginning = { '.', ' ' }; + var newlist = line.Split(new char[] { ' ' }); + + var key = newlist[0].TrimStart(TrimBeginning); + var value = newlist.Length > 1 ? newlist[1].Trim() : string.Empty; + parsedMetadataHash.Add(key,value); + } + } + } + + return parsedMetadataHash; + } + + private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUrl) + { + // Check to see that all dependencies are in the repository + // Searches for each dependency in the repository the pkg is being pushed to, + // If the dependency is not there, error + foreach (var dependency in dependencies.Keys) + { + // Need to make individual calls since we're look for exact version numbers or ranges. + var depName = new[] { (string)dependency }; + var depVersion = (string)dependencies[dependency]; + var type = new[] { "module", "script" }; + var repository = new[] { repositoryUrl }; + + // Search for and return the dependency if it's in the repository. + // TODO: When find is complete, uncomment beginFindHelper method below (resourceNameParameterHelper) + //var dependencyFound = findHelper.beginFindHelper(depName, type, depVersion, true, null, null, repository, Credential, false, false); + // TODO: update the type from PSObject to PSResourceInfo + List dependencyFound = null; + if (dependencyFound == null || !dependencyFound.Any()) + { + var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryUrl); + var ex = new ArgumentException(message); // System.ArgumentException vs PSArgumentException + var dependencyNotFound = new ErrorRecord(ex, "DependencyNotFound", ErrorCategory.ObjectNotFound, null); + + WriteError(dependencyNotFound); + return false; + } + } + return true; + } + + private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFile) + { + // Pack the module or script into a nupkg given a nuspec. + var builder = new PackageBuilder(); + var runner = new PackCommandRunner( + new PackArgs + { + CurrentDirectory = outputDir, + OutputDirectory = outputNupkgDir, + Path = nuspecFile, + Exclude = System.Array.Empty(), + Symbols = false, + Logger = NullLogger.Instance + }, + MSBuildProjectFactory.ProjectCreator, + builder); + + bool success = runner.RunPackageBuild(); + if (success) + { + WriteDebug("Successfully packed the resource into a .nupkg"); + } + else + { + WriteDebug("Successfully packed the resource into a .nupkg"); + } + + return success; + } + + private void PushNupkg(string outputNupkgDir, string repoUrl) + { + // Push the nupkg to the appropriate repository + // Pkg version is parsed from .ps1 file or .psd1 file + var fullNupkgFile = System.IO.Path.Combine(outputNupkgDir, _pkgName + "." + _pkgVersion.ToNormalizedString() + ".nupkg"); + + // The PSGallery uses the v2 protocol still and publishes to a slightly different endpoint: + // "https://www.powershellgallery.com/api/v2/package" + // Until the PSGallery is moved onto the NuGet v3 server protocol, we'll modify the repository url + // to accommodate for the approprate publish location. + string publishLocation = repoUrl.EndsWith("/v2", StringComparison.OrdinalIgnoreCase) ? repoUrl + "/package" : repoUrl; + + var settings = NuGet.Configuration.Settings.LoadDefaultSettings(null, null, null); + ILogger log = new NuGetLogger(); + var success = true; + try + { + PushRunner.Run( + settings: Settings.LoadDefaultSettings(root: null, configFileName: null, machineWideSettings: null), + sourceProvider: new PackageSourceProvider(settings), + packagePath: fullNupkgFile, + source: publishLocation, + apiKey: APIKey, + symbolSource: null, + symbolApiKey: null, + timeoutSeconds: 0, + disableBuffering: false, + noSymbols: false, + noServiceEndpoint: false, // enable server endpoint + skipDuplicate: false, // if true-- if a package and version already exists, skip it and continue with the next package in the push, if any. + logger: log // nuget logger + ).GetAwaiter().GetResult(); + } + catch (HttpRequestException e) + { + // look in PS repo for how httpRequestExceptions are handled + + // Unfortunately there is no response message are no status codes provided with the exception and no + var ex = new ArgumentException(e.Message); + if (e.Message.Contains("401")) + { + if (e.Message.Contains("API")) + { + var message = String.Format("{0} Please try running again with the -APIKey parameter and specific API key for the repository specified.", e.Message); + ex = new ArgumentException(message); + var APIKeyError = new ErrorRecord(ex, "APIKeyError", ErrorCategory.AuthenticationError, null); + WriteError(APIKeyError); + } + else + { + var Error401 = new ErrorRecord(ex, "401Error", ErrorCategory.PermissionDenied, null); + WriteError(Error401); + } + } + else if (e.Message.Contains("403")) + { + var Error403 = new ErrorRecord(ex, "403Error", ErrorCategory.PermissionDenied, null); + WriteError(Error403); + } + else if (e.Message.Contains("409")) + { + var Error409 = new ErrorRecord(ex, "409Error", ErrorCategory.PermissionDenied, null); + WriteError(Error409); + } + else + { + var HTTPRequestError = new ErrorRecord(ex, "HTTPRequestError", ErrorCategory.PermissionDenied, null); + WriteError(HTTPRequestError); + } + + success = false; + } + catch (Exception e) + { + var ex = new ArgumentException(e.Message); + var PushNupkgError = new ErrorRecord(ex, "PushNupkgError", ErrorCategory.InvalidResult, null); + WriteError(PushNupkgError); + + success = false; + } + + if (success) + { + WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUrl)); + } + else + { + WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUrl)); + } + } + } +} diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 new file mode 100644 index 000000000..0ed7016cb --- /dev/null +++ b/test/PublishPSResource.Tests.ps1 @@ -0,0 +1,284 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Publish-PSResource" { + BeforeAll { + Get-NewPSResourceRepositoryFile + + # Register temporary repositories + $tmpRepoPath = Join-Path -Path $TestDrive -ChildPath "tmpRepoPath" + New-Item $tmpRepoPath -Itemtype directory -Force + $testRepository = "testRepository" + Register-PSResourceRepository -Name $testRepository -URL $tmpRepoPath -Priority 1 -ErrorAction SilentlyContinue + $script:repositoryPath = (get-psresourcerepository "testRepository").Url.AbsolutePath + + $tmpRepoPath2 = Join-Path -Path $TestDrive -ChildPath "tmpRepoPath2" + New-Item $tmpRepoPath2 -Itemtype directory -Force + $testRepository2 = "testRepository2" + Register-PSResourceRepository -Name $testRepository2 -URL $tmpRepoPath2 -ErrorAction SilentlyContinue + $script:repositoryPath2 = (get-psresourcerepository "testRepository2").Url.AbsolutePath + + # Create module + $script:tmpModulesPath = Join-Path -Path $TestDrive -ChildPath "tmpModulesPath" + $script:PublishModuleName = "PSGetTestModule" + $script:PublishModuleBase = Join-Path $script:tmpModulesPath -ChildPath $script:PublishModuleName + if(!(Test-Path $script:PublishModuleBase)) + { + New-Item -Path $script:PublishModuleBase -ItemType Directory -Force + } + + #Create dependency module + $script:DependencyModuleName = "PackageManagement" + $script:DependencyModuleBase = Join-Path $script:tmpModulesPath -ChildPath $script:DependencyModuleName + if(!(Test-Path $script:DependencyModuleBase)) + { + New-Item -Path $script:DependencyModuleBase -ItemType Directory -Force + } + + # Create temp destination path + $script:destinationPath = Join-Path -Path $TestDrive -ChildPath "tmpDestinationPath" + New-Item $script:destinationPath -ItemType directory -Force + } + AfterAll { + # Get-RevertPSResourceRepositoryFile + } + AfterEach { + # Delete all contents of the repository without deleting the repository directory itself + # $pkgsToDelete = Join-Path -Path "$script:repositoryPath" -ChildPath "*" + # Remove-Item $pkgsToDelete -Recurse + + # $pkgsToDelete = Join-Path -Path "$script:repositoryPath2" -ChildPath "*" + # Remove-Item $pkgsToDelete -Recurse + } + + + It "Publish a module with -Path to the highest priority repo" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + } + + It "Publish a module with -Path and -Repository" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } + + It "Publish a module with -Path and -DestinationPath" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -DestinationPath $script:destinationPath + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + } + + It "Publish a module with -LiteralPath" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -LiteralPath $script:PublishModuleBase + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + } + +<# Temporarily comment this test out until Find Helper is complete and code within PublishPSResource is uncommented + It "Publish a module with dependencies" { + # Create dependency module + $dependencyVersion = "2.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:DependencyModuleBase -ChildPath "$script:DependencyModuleName.psd1") -ModuleVersion $dependencyVersion -Description "$script:DependencyModuleName module" + + Publish-PSResource -LiteralPath $script:DependencyModuleBase + + # Create module to test + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" -RequiredModules @{ModuleName = "$script:DependencyModuleName"; ModuleVersion = "$dependencyVersion" } + + Publish-PSResource -LiteralPath $script:PublishModuleBase + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | select-object -Last 1 | Should -Be $expectedPath + } +#> + + It "Publish a module with a dependency that is not published, should throw" { + $version = "1.0.0" + $dependencyVersion = "2.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName="PackageManagement"; ModuleVersion="$dependencyVersion"}) + + Publish-PSResource -Path $script:PublishModuleBase -ErrorAction SilentlyContinue + + $Error[0].FullyQualifiedErrorId | Should -be "DependencyNotFound,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + } + + + It "Publish a module with -SkipDependenciesCheck" { + $version = "1.0.0" + $dependencyVersion = "2.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -RequiredModules @{ModuleName = "$script:DependencyModuleName"; ModuleVersion = "$dependencyVersion" } + + Publish-PSResource -Path $script:PublishModuleBase -SkipDependenciesCheck + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | select-object -Last 1 | Should -Be $expectedPath + } + + <# The following tests are related to passing in parameters to customize a nuspec. + # These parameters are not going in the current release, but is open for discussion to include in the future. + It "Publish a module with -Nuspec" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + + # Create nuspec + $nuspec = +@' + + + + PSGetTestModule + 1.0.0 + americks + americks + false + test + + (c) 2021 Contoso Corporation. All rights reserved. + PSModule + + +'@ + + $nuspecPath = Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.nuspec" + New-Item $nuspecPath -ItemType File -Value $nuspec + + Publish-PSResource -Path $script:PublishModuleBase -Nuspec $nuspecPath + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | Should -Be $expectedPath + } + + It "Publish a module with -ReleaseNotes" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + + $releaseNotes = "Test release notes." + Publish-PSResource -Path $script:PublishModuleBase -ReleaseNotes $releaseNotes + + $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + + $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" + New-Item -Path $expectedExpandedPath -ItemType directory + Expand-Archive -Path $expectedNupkgPath -DestinationPath $expectedExpandedPath + + $expectedNuspec = Join-path -Path $expectedExpandedPath -ChildPath "$script:PublishModuleName.nuspec" + $expectedNuspecContents = Get-Content -Path $expectedNuspec -Raw + $expectedNuspecContents.Contains($releaseNotes) | Should Be $true + } + + It "Publish a module with -LicenseUrl" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + + $licenseUrl = "https://www.fakelicenseurl.com" + Publish-PSResource -Path $script:PublishModuleBase -LicenseUrl $licenseUrl + + $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + + $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" + New-Item -Path $expectedExpandedPath -ItemType directory + Expand-Archive -Path $expectedNupkgPath -DestinationPath $expectedExpandedPath + + $expectedNuspec = Join-path -Path $expectedExpandedPath -ChildPath "$script:PublishModuleName.nuspec" + $expectedNuspecContents = Get-Content -Path $expectedNuspec -Raw + $expectedNuspecContents.Contains($licenseUrl) | Should Be $true + } + + It "Publish a module with -IconUrl" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + + $iconUrl = "https://www.fakeiconurl.com" + Publish-PSResource -Path $script:PublishModuleBase -IconUrl $iconUrl + + $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + + $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" + New-Item -Path $expectedExpandedPath -ItemType directory + Expand-Archive -Path $expectedNupkgPath -DestinationPath $expectedExpandedPath + + $expectedNuspec = Join-path -Path $expectedExpandedPath -ChildPath "$script:PublishModuleName.nuspec" + $expectedNuspecContents = Get-Content -Path $expectedNuspec -Raw + $expectedNuspecContents.Contains($iconUrl) | Should Be $true + } + + + It "Publish a module with -ProjectUrl" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + + $projectUrl = "https://www.fakeprojecturl.com" + Publish-PSResource -Path $script:PublishModuleBase -ProjectUrl $projectUrl + + $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + + $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" + New-Item -Path $expectedExpandedPath -ItemType directory + Expand-Archive -Path $expectedNupkgPath -DestinationPath $expectedExpandedPath + + $expectedNuspec = Join-path -Path $expectedExpandedPath -ChildPath "$script:PublishModuleName.nuspec" + $expectedNuspecContents = Get-Content -Path $expectedNuspec -Raw + $expectedNuspecContents.Contains($projectUrl) | Should Be $true + } + + It "Publish a module with -Tags" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + $tags = "Tag1" + Publish-PSResource -Path $script:PublishModuleBase -Tags $tags + + $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + + $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" + New-Item -Path $expectedExpandedPath -ItemType directory + Expand-Archive -Path $expectedNupkgPath -DestinationPath $expectedExpandedPath + + $expectedNuspec = Join-path -Path $expectedExpandedPath -ChildPath "$script:PublishModuleName.nuspec" + $expectedNuspecContents = Get-Content -Path $expectedNuspec -Raw + $expectedNuspecContents.Contains($tags) | Should Be $true + } +#> + It "Publish a module to PSGallery without -APIKey, should throw" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository PSGallery -ErrorAction SilentlyContinue + + $Error[0].FullyQualifiedErrorId | Should -be "APIKeyError,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + } + + It "Publish a module to PSGallery using incorrect API key, should throw" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository PSGallery -APIKey "123456789" -ErrorAction SilentlyContinue + + $Error[0].FullyQualifiedErrorId | Should -be "403Error,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + } +} From e8c9d58b45039ae984ecff3094d82864fc9fb569 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 7 Jun 2021 12:46:09 -0400 Subject: [PATCH 008/276] Refactor SetPSResourceRepository cmdlet (#359) * added implemenation and test for Set * remove unnecessary comments * add some summary parameter comments * remove more comments * remove NameParameterSetHelper() * add test and code for detecting if name key in repositories param is null * update help doc for Set * fix codacy issues * add Debug statements * add newline at end of SetPSResourceRepository.cs file * used parameterset name const variables instead of parameter set strings * remove Credential parameter * remove Proxy and ProxyCredential parameters * remove Credential parameter from help docs as well * trim whitespace with Trim(), no param needed * order directives alphabetically * remove Priority and URL parameters from pipeline --- help/Set-PSResourceRepository.md | 116 +++++----- src/code/RepositorySettings.cs | 22 +- src/code/SetPSResourceRepository.cs | 284 +++++++++++++++++++++++++ test/SetPSResourceRepository.Tests.ps1 | 155 ++++++++++++++ 4 files changed, 511 insertions(+), 66 deletions(-) create mode 100644 src/code/SetPSResourceRepository.cs create mode 100644 test/SetPSResourceRepository.Tests.ps1 diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index 1179589f9..1b2e76236 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -8,53 +8,74 @@ schema: 2.0.0 # Set-PSResourceRepository ## SYNOPSIS -{{ Fill in the Synopsis }} +Sets information for a registered repository. ## SYNTAX ### NameParameterSet (Default) ``` -Set-PSResourceRepository [-Name] [-URL ] [-Credential ] [-Trusted] [-Proxy ] - [-ProxyCredential ] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository [-Name] [-URL ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet ``` -Set-PSResourceRepository -Repositories - [-Proxy ] [-ProxyCredential ] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository -Repositories [-Priority ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -{{ Fill in the Description }} +The Set-PSResourceRepository cmdlet sets information for a registered repository. ## EXAMPLES - +These examples are run independently of each other and assume the repositories used are already registered. The 'PassThru' parameter used with Set-PSResourceRepository is only used to display the changes made to the repository and is not mandatory. ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -URL "c:/code/testdir" -PassThru + Name Url Trusted Priority + ---- --- ------- -------- + PoshTestGallery file:///c:/code/testdir False 50 ``` -{{ Add example description here }} - -## PARAMETERS +This example first checks if the PoshTestGallery repository has been registered. We wish to set the 'URL' value of this repository by running the Set-PSResourceRepository cmdlet with the 'URL' parameter and a valid Uri scheme url. We run the Get-PSResourceRepository cmdlet again to ensure that the 'URL' of the repository was changed. We also use the 'PassThru' parameter to see the changed repository. -### -Credential -{{ Fill Credential Description }} +### Example 2 +```powershell +PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 25 +``` -```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: NameParameterSet -Aliases: +This example first checks if the PSGallery repository has been registered. We wish to set the 'Priority' and 'Trusted' values of this repository by running the Set-PSResourceRepository cmdlet with the 'Priority' parameter set to a value between 0 and 50 and by using the 'Trusted' parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the 'Priority' and 'Trusted' values of the repository were changed. An important note here is that just for the default PSGallery repository, the 'URL' value can't be changed/set. We also use the 'PassThru' parameter to see the changed repository. -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False +### Example 3 +```powershell +PS C:\> Get-PSResourceRepository -Name "*" + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True},@{Name = "PoshTestGallery"; URL = "c:/code/testdir"} +PS C:\> Set-PSResourceRepository -Repositories $arrayOfHashtables -PassThru + Name Url Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 50 + PoshTestGallery file:///c:/code/testdir False 50 ``` +This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the 'Repositories' parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the 'PassThru' parameter to see the changed repositories. + +## PARAMETERS + ### -Name -{{ Fill Name Description }} +Specifies the name of the repository to be set. ```yaml Type: System.String @@ -69,7 +90,7 @@ Accept wildcard characters: False ``` ### -Priority -{{ Fill Priority Description }} +Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). ```yaml Type: System.Int32 @@ -83,41 +104,11 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` -### -Proxy -{{ Fill Proxy Description }} - -```yaml -Type: System.Uri -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False -``` - -### -ProxyCredential -{{ Fill ProxyCredential Description }} - -```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False -``` - ### -Repositories -{{ Fill Repositories Description }} +Specifies a hashtable of repositories and is used to register multiple repositories at once. ```yaml -Type: System.Collections.Generic.List`1[System.Collections.Hashtable] +Type: Hashtable[] Parameter Sets: RepositoriesParameterSet Aliases: @@ -129,7 +120,7 @@ Accept wildcard characters: False ``` ### -Trusted -{{ Fill Trusted Description }} +Specifies whether the repository should be trusted. ```yaml Type: System.Management.Automation.SwitchParameter @@ -144,7 +135,7 @@ Accept wildcard characters: False ``` ### -URL -{{ Fill URL Description }} +Specifies the location of the repository to be set. ```yaml Type: System.Uri @@ -198,19 +189,14 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.Uri -### System.Management.Automation.PSCredential - -### System.Collections.Generic.List`1[[System.Collections.Hashtable, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] +### System.Collections.Hashtable[] ### System.Int32 ## OUTPUTS -### System.Object +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) ## NOTES ## RELATED LINKS - -[]() - diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 2169c960e..99911a39e 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -114,10 +114,11 @@ public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriorit /// Updates a repository name, URL, priority, or installation policy /// Returns: void /// - public static void Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted) + public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted) { Dbg.Assert(!string.IsNullOrEmpty(repoName), "Repository name cannot be null or empty"); + PSRepositoryInfo updatedRepo; try { // Open file @@ -132,21 +133,38 @@ public static void Update(string repoName, Uri repoURL, int repoPriority, bool? // Get root of XDocument (XElement) var root = doc.Root; + // A null URL value passed in signifies the URL was not attempted to be set. + // So only set Url attribute if non-null value passed in for repoUrl if (repoURL != null) { node.Attribute("Url").Value = repoURL.AbsoluteUri; } + // A negative Priority value passed in signifies the Priority value was not attempted to be set. + // So only set Priority attribute if non-null value passed in for repoPriority if (repoPriority >= 0) { node.Attribute("Priority").Value = repoPriority.ToString(); } + // A null Trusted value passed in signifies the Trusted value was not attempted to be set. + // So only set Trusted attribute if non-null value passed in for repoTrusted. if (repoTrusted != null) { node.Attribute("Trusted").Value = repoTrusted.ToString(); } + // Create Uri from node Url attribute to create PSRepositoryInfo item to return. + if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted URL for repo {0}", repoName)); + } + + updatedRepo = new PSRepositoryInfo(repoName, + thisUrl, + Int32.Parse(node.Attribute("Priority").Value), + Boolean.Parse(node.Attribute("Trusted").Value)); + // Close the file root.Save(FullRepositoryPath); } @@ -154,6 +172,8 @@ public static void Update(string repoName, Uri repoURL, int repoPriority, bool? { throw new PSInvalidOperationException(String.Format("Updating to repository store failed: {0}", e.Message)); } + + return updatedRepo; } /// diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs new file mode 100644 index 000000000..c3f161333 --- /dev/null +++ b/src/code/SetPSResourceRepository.cs @@ -0,0 +1,284 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.Globalization; +using System.Management.Automation; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Set-PSResourceRepository cmdlet is used to set information for a repository. + /// + [Cmdlet(VerbsCommon.Set, + "PSResourceRepository", + DefaultParameterSetName = NameParameterSet, + SupportsShouldProcess = true, + HelpUri = "")] + public sealed + class SetPSResourceRepository : PSCmdlet + { + #region Members + + private const string NameParameterSet = "NameParameterSet"; + private const string RepositoriesParameterSet = "RepositoriesParameterSet"; + private const int DefaultPriority = -1; + #endregion + + #region Parameters + + /// + /// Specifies the name of the repository to be set. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, + ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string Name { get; set; } + + /// + /// Specifies the location of the repository to be set. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public Uri URL + { + get + { return _url; } + + set + { + if (!Uri.TryCreate(value, string.Empty, out Uri url)) + { + var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not a valid url: {0}", value); + var ex = new ArgumentException(message); + var urlErrorRecord = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(urlErrorRecord); + } + + _url = url; + } + } + private Uri _url; + + /// + /// Specifies a hashtable of repositories and is used to register multiple repositories at once. + /// + [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = RepositoriesParameterSet)] + [ValidateNotNullOrEmpty] + public Hashtable[] Repositories { get; set; } + + /// + /// Specifies whether the repository should be trusted. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Trusted + { + get + { return _trusted; } + + set + { + _trusted = value; + isSet = true; + } + } + private SwitchParameter _trusted; + private bool isSet; + + /// + /// Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched + /// before a lower ranking priority one, when searching for a repository item across multiple registered repositories. + /// Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds + /// to a higher priority ranking than a higher numeric value (i.e 40). + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + [ValidateRange(0, 50)] + public int Priority { get; set; } = DefaultPriority; + + /// + /// When specified, displays the succcessfully registered repository and its information + /// + [Parameter] + public SwitchParameter PassThru { get; set; } + + #endregion + + #region Methods + protected override void BeginProcessing() + { + try + { + WriteDebug("Calling API to check repository store exists in non-corrupted state"); + RepositorySettings.CheckRepositoryStore(); + } + catch (PSInvalidOperationException e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "RepositoryStoreException", + ErrorCategory.ReadError, + this)); + } + } + + protected override void ProcessRecord() + { + List items = new List(); + + switch(ParameterSetName) + { + case NameParameterSet: + try + { + items.Add(UpdateRepositoryStoreHelper(Name, URL, Priority, Trusted)); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorInNameParameterSet", + ErrorCategory.InvalidArgument, + this)); + } + break; + + case RepositoriesParameterSet: + try + { + items = RepositoriesParameterSetHelper(); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorInRepositoriesParameterSet", + ErrorCategory.InvalidArgument, + this)); + } + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + + if (PassThru) + { + foreach(PSRepositoryInfo item in items) + { + WriteObject(item); + } + } + } + + private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted) + { + if (repoUrl != null && !(repoUrl.Scheme == Uri.UriSchemeHttp || repoUrl.Scheme == Uri.UriSchemeHttps || repoUrl.Scheme == Uri.UriSchemeFtp || repoUrl.Scheme == Uri.UriSchemeFile)) + { + throw new ArgumentException("Invalid url, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); + } + + // check repoName can't contain * or just be whitespace + // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition + repoName = repoName.Trim(); + if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) + { + throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); + } + + // check PSGallery URL is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUrl != null) + { + throw new ArgumentException("The PSGallery repository has a pre-defined URL. Setting the -URL parmeter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); + } + + // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) + bool? _trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); + + // determine if either 1 of 3 values are attempting to be set: URL, Priority, Trusted. + // if none are (i.e only Name parameter was provided, write error) + if(repoUrl == null && repoPriority == DefaultPriority && _trustedNullable == null) + { + throw new ArgumentException("Either URL, Priority or Trusted parameters must be requested to be set"); + } + + WriteDebug("All required values to set repository provided, calling internal Update() API now"); + if (!ShouldProcess(repoName, "Set repository's value(s) in repository store")) + { + return null; + } + return RepositorySettings.Update(repoName, repoUrl, repoPriority, _trustedNullable); + } + + private List RepositoriesParameterSetHelper() + { + List reposUpdatedFromHashtable = new List(); + foreach (Hashtable repo in Repositories) + { + if (!repo.ContainsKey("Name") || repo["Name"] == null || String.IsNullOrEmpty(repo["Name"].ToString())) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Repository hashtable must contain Name key value pair"), + "NullNameForRepositoriesParameterSetRepo", + ErrorCategory.InvalidArgument, + this)); + continue; + } + + PSRepositoryInfo parsedRepoAdded = RepoValidationHelper(repo); + if (parsedRepoAdded != null) + { + reposUpdatedFromHashtable.Add(parsedRepoAdded); + } + } + return reposUpdatedFromHashtable; + } + + private PSRepositoryInfo RepoValidationHelper(Hashtable repo) + { + WriteDebug(String.Format("Parsing through repository: {0}", repo["Name"])); + Uri repoURL = null; + if (repo.ContainsKey("Url") && !Uri.TryCreate(repo["URL"].ToString(), UriKind.Absolute, out repoURL)) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Invalid Url, unable to parse and create Uri"), + "InvalidUrl", + ErrorCategory.InvalidArgument, + this)); + return null; + } + + bool repoTrusted = false; + isSet = false; + if(repo.ContainsKey("Trusted")) + { + repoTrusted = (bool) repo["Trusted"]; + isSet = true; + } + try + { + return UpdateRepositoryStoreHelper(repo["Name"].ToString(), + repoURL, + repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, + repoTrusted); + } + catch (Exception e) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorSettingIndividualRepoFromRepositories", + ErrorCategory.InvalidArgument, + this)); + return null; + } + } + + #endregion + } +} diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 new file mode 100644 index 000000000..24cb5dfc3 --- /dev/null +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -0,0 +1,155 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Register-PSResourceRepository" { + BeforeEach { + $PSGalleryName = Get-PSGalleryName + $PSGalleryURL = Get-PSGalleryLocation + Get-NewPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-NewTestDirs($tmpDirPaths) + } + AfterEach { + Get-RevertPSResourceRepositoryFile + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" + $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + Get-RemoveTestDirs($tmpDirPaths) + } + + It "set repository given Name and URL parameters" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Set-PSResourceRepository -Name "testRepository" -URL $tmpDir2Path + $res = Get-PSResourceRepository -Name "testRepository" + $res.Name | Should -Be "testRepository" + $res.URL | Should -Contain $tmpDir2Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be False + } + + It "set repository given Name and Priority parameters" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Set-PSResourceRepository -Name "testRepository" -Priority 25 + $res = Get-PSResourceRepository -Name "testRepository" + $res.Name | Should -Be "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 25 + $res.Trusted | Should -Be False + } + + It "set repository given Name and Trusted parameters" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Set-PSResourceRepository -Name "testRepository" -Trusted + $res = Get-PSResourceRepository -Name "testRepository" + $res.Name | Should -Be "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be True + } + + It "not set repository and write error given just Name parameter" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + {Set-PSResourceRepository -Name "testRepository" -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + } + + $testCases = @{Type = "contains *"; Name = "test*Repository"; ErrorId = "ErrorInNameParameterSet"}, + @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorInNameParameterSet"}, + @{Type = "is null"; Name = $null; ErrorId = "ParameterArgumentValidationError"} + + It "not set repository and throw error given Name (NameParameterSet)" -TestCases $testCases { + param($Type, $Name) + + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + {Set-PSResourceRepository -Name $Name -Priority 25 -ErrorAction Stop} | Should -Throw -ErrorId "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + } + + $testCases2 = @{Type = "contains *"; Name = "test*Repository2"; ErrorId = "ErrorSettingIndividualRepoFromRepositories"}, + @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorSettingIndividualRepoFromRepositories"}, + @{Type = "is null"; Name = $null; ErrorId = "NullNameForRepositoriesParameterSetRepo"} + It "not set repository and write error given Name (RepositoriesParameterSet)" -TestCases $testCases2 { + param($Type, $Name, $ErrorId) + + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + + $hashtable1 = @{Name = "testRepository"; URL = $tmpDir3Path} + $hashtable2 = @{Name = "testRepository2"; Priority = 25} + $incorrectHashTable = @{Name = $Name; Trusted = $True} + $arrayOfHashtables = $hashtable1, $incorrectHashTable, $hashtable2 + + Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + + $res = Get-PSResourceRepository -Name "testRepository" + $res.URL | Should -Contain $tmpDir3Path + $res.Trusted | Should -Be False + + $res2 = Get-PSResourceRepository -Name "testRepository2" + $res2.Priority | Should -Be 25 + $res2.Trusted | Should -Be False + } + + It "set repositories with Repositories parameter" { + Unregister-PSResourceRepository -Name "PSGallery" + Register-PSResourceRepository -Name "testRepository1" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -PSGallery + + $hashtable1 = @{Name = "testRepository1"; URL = $tmpDir2Path}; + $hashtable2 = @{Name = "testRepository2"; Priority = 25}; + $hashtable3 = @{Name = "PSGallery"; Trusted = $True}; + $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3 + + Set-PSResourceRepository -Repositories $arrayOfHashtables + $res = Get-PSResourceRepository -Name "testRepository1" + $res.Name | Should -Be "testRepository1" + $res.URL | Should -Contain $tmpDir2Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be False + + $res2 = Get-PSResourceRepository -Name "testRepository2" + $res2.Name | Should -Be "testRepository2" + $res2.URL | Should -Contain $tmpDir2Path + $res2.Priority | Should -Be 25 + $res2.Trusted | Should -Be False + + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.URL | Should -Contain $PSGalleryURL + $res3.Priority | Should -Be 50 + $res3.Trusted | Should -Be True + } + + It "not set and throw error for trying to set PSGallery URL (NameParameterSet)" { + Unregister-PSResourceRepository -Name "PSGallery" + Register-PSResourceRepository -PSGallery + {Set-PSResourceRepository -Name "PSGallery" -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + } + + It "not set repository and throw error for trying to set PSGallery URL (RepositoriesParameterSet)" { + Unregister-PSResourceRepository -Name "PSGallery" + Register-PSResourceRepository -PSGallery + + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + + $hashtable1 = @{Name = "PSGallery"; URL = $tmpDir1Path} + $hashtable2 = @{Name = "testRepository"; Priority = 25} + $arrayOfHashtables = $hashtable1, $hashtable2 + + Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + + $res = Get-PSResourceRepository -Name "testRepository" + $res.URL | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 25 + $res.Trusted | Should -Be False + } +} From b7ad2d3c8401d821b2a7287029c6f1a6fba2537c Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 7 Jun 2021 10:58:15 -0700 Subject: [PATCH 009/276] Add ci release yaml files (#373) --- .ci/ci_release.yml | 396 +++++++++++++++++++++++++++++++++++++++++++++ .ci/release.yml | 47 ++++++ 2 files changed, 443 insertions(+) create mode 100644 .ci/ci_release.yml create mode 100644 .ci/release.yml diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml new file mode 100644 index 000000000..ecacfaf8b --- /dev/null +++ b/.ci/ci_release.yml @@ -0,0 +1,396 @@ +name: $(BuildDefinitionName)-$(date:yyMM).$(date:dd)$(rev:rrr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master +pr: + branches: + include: + - master + +variables: + - group: ESRP + +resources: + repositories: + - repository: ComplianceRepo + type: github + endpoint: ComplianceGHRepo + name: PowerShell/compliance + +stages: +- stage: Build + displayName: Build PowerShellGet Module Package + jobs: + - job: BuildPkg + displayName: Build Package + pool: + name: 1ES + demands: + - ImageOverride -equals MMS2019 + + steps: + - powershell: | + $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' + Invoke-WebRequest -Uri https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.ps1 -outfile ./install-powershell.ps1 + ./install-powershell.ps1 -Destination $powerShellPath + $vstsCommandString = "vso[task.setvariable variable=PATH]$powerShellPath;$env:PATH" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Install PowerShell Core + + - task: UseDotNet@2 + displayName: 'Install .NET Core 3.1.401 sdk' + inputs: + packageType: sdk + version: 3.1.401 + + - task: NuGetToolInstaller@1 + displayName: 'Install NuGet 5.6.0' + inputs: + checkLatest: false + version: 5.6.0 + + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture environment for build + condition: succeededOrFailed() + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + if (Test-Path -Path $modulePath) { + Write-Verbose -Verbose "Deleting existing temp module path: $modulePath" + Remove-Item -Path $modulePath -Recurse -Force -ErrorAction Ignore + } + if (! (Test-Path -Path $modulePath)) { + Write-Verbose -Verbose "Creating new temp module path: $modulePath" + $null = New-Item -Path $modulePath -ItemType Directory + } + displayName: Create temporary module path + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + Write-Verbose -Verbose "Install PowerShellGet V3 to temp module path" + Save-Module -Name PowerShellGet -Path $modulePath -MinimumVersion 3.0.0-beta10 -AllowPrerelease -Force + Write-Verbose -Verbose "Install PlatyPS to temp module path" + Save-Module -Name "platyPS" -Path $modulePath -Force + Write-Verbose -Verbose "Install PSScriptAnalyzer to temp module path" + Save-Module -Name "PSScriptAnalyzer" -Path $modulePath -RequiredVersion 1.18.0 -Force + Write-Verbose -Verbose "Install Pester 5.X to temp module path" + Save-Module -Name "Pester" -MinimumVersion 5.0 -Path $modulePath -Repository PSGallery -Force + Write-Verbose -Verbose "Install PSPackageProject to temp module path" + Save-Module -Name PSPackageProject -Path $modulePath -Force + displayName: Install PSPackageProject and dependencies + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + # + # First build for netstandard2.0 framework + $(Build.SourcesDirectory)/build.ps1 -Build -Clean -BuildConfiguration Release -BuildFramework 'netstandard2.0' + # Next build for net472 framework + $(Build.SourcesDirectory)/build.ps1 -Build -BuildConfiguration Release -BuildFramework 'net472' + displayName: Build and publish artifact + + - pwsh: | + $signSrcPath = "$($config.BuildOutputPath)" + $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${signSrcPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + # + $outSignPath = "$($config.BuildOutputPath)" + $vstsCommandString = "vso[task.setvariable variable=signOutPath]${outSignPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Create fake source and output variables for signing template and no signing + condition: and(succeeded(), eq(variables['SkipSigning'], 'True')) + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + + $config = Get-PSPackageProjectConfiguration + + # Created files signing directory + $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" + $createdSignSrcPath = "$($config.BuildOutputPath)\CreatedFiles" + if (! (Test-Path -Path $createdSignSrcPath)) { + $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose + } + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSModule.psm1") -Dest $createdSignSrcPath -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose + + $net472Path = Join-Path -Path $createdSignSrcPath -ChildPath "net472" + if (! (Test-Path -Path $net472Path)) { + $null = New-Item -Path $net472Path -ItemType Directory -Verbose + } + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "net472\PowerShellGet.*") -Dest $net472Path -Force -Verbose + + $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" + if (! (Test-Path -Path $netStandardPath)) { + $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose + } + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0\PowerShellGet.*") -Dest $netStandardPath -Force -Verbose + + $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $signOutPath)) { + $null = New-Item -Path $signOutPath -ItemType Directory + } + + # Set signing src path variable + $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${createdSignSrcPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + + $outSignPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $outSignPath)) { + $null = New-Item -Path $outSignPath -ItemType Directory -Verbose + } + + # Set signing out path variable + $vstsCommandString = "vso[task.setvariable variable=signOutPath]${outSignPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Set up for module created files code signing + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + + - template: EsrpSign.yml@ComplianceRepo + parameters: + buildOutputPath: $(signSrcPath) + signOutputPath: $(signOutPath) + certificateId: "CP-230012" + pattern: | + **\*.dll + **\*.psd1 + **\*.psm1 + **\*.ps1xml + **\*.mof + useMinimatch: true + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + + $config = Get-PSPackageProjectConfiguration + + $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $signOutPath)) { + $null = New-Item -Path $signOutPath -ItemType Directory + } + + # Third party files signing directory + $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" + $thirdPartySignSrcPath = "$($config.BuildOutputPath)\ThirdParty" + if (! (Test-Path -Path $thirdPartySignSrcPath)) { + $null = New-Item -Path $thirdPartySignSrcPath -ItemType Directory -Verbose + } + + # Net472 directory + $net472Path = Join-Path -Path $thirdPartySignSrcPath -ChildPath "net472" + if (! (Test-Path -Path $net472Path)) { + $null = New-Item -Path $net472Path -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { + # Copy for third party signing + Copy-Item -Path $_.FullName -Dest $net472Path -Force -Verbose + } + } + } + + # NetStandard directory + $netStandardPath = Join-Path -Path $thirdPartySignSrcPath -ChildPath "netstandard2.0" + if (! (Test-Path -Path $netStandardPath)) { + $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { + # Copy for third party signing + Copy-Item -Path $_.FullName -Dest $netStandardPath -Force -Verbose + } + } + } + + # Set signing src path variable + $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${thirdPartySignSrcPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + + # Set signing out path variable + $vstsCommandString = "vso[task.setvariable variable=signOutPath]${signOutPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Set up for module third party files code signing + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + + - template: EsrpSign.yml@ComplianceRepo + parameters: + buildOutputPath: $(signSrcPath) + signOutputPath: $(signOutPath) + certificateId: "CP-231522" + pattern: | + **\*.dll + useMinimatch: true + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + + $config = Get-PSPackageProjectConfiguration + + $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" + $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $signOutPath)) { + $null = New-Item -Path $signOutPath -ItemType Directory + } + + # en-US + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse + + # Net472 directory + $net472SignedOutPath = Join-Path -Path $signOutPath -ChildPath "net472" + if (! (Test-Path -Path $net472SignedOutPath)) { + $null = New-Item -Path $net472SignedOutPath -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { + # Copy already signed files directly to output + Copy-Item -Path $_.FullName -Dest $net472SignedOutPath -Force -Verbose + } + } + } + + # NetStandard directory + $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" + if (! (Test-Path -Path $netStandardSignedOutPath)) { + $null = New-Item -Path $netStandardSignedOutPath -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { + # Copy already signed files directly to output + Copy-Item -Path $_.FullName -Dest $netStandardSignedOutPath -Force -Verbose + } + } + } + displayName: Copy already properly signed third party files + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + # + $config = Get-PSPackageProjectConfiguration + $artifactName = "$($config.ModuleName)" + if ($env:SkipSigning -eq 'True') + { + $srcModulePath = Resolve-Path -Path "$($config.BuildOutputPath)/$($config.ModuleName)" + Get-ChildItem $srcModulePath + Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$srcModulePath" + # + $(Build.SourcesDirectory)/build.ps1 -Publish + } + else + { + $srcModulePath = Resolve-Path -Path "$($config.SignedOutputPath)/$($config.ModuleName)" + Get-ChildItem $srcModulePath + Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$srcModulePath" + # + $(Build.SourcesDirectory)/build.ps1 -Publish -Signed + } + displayName: Create module artifact + +- stage: Compliance + displayName: Compliance + dependsOn: Build + jobs: + - job: ComplianceJob + pool: + name: 1ES + demands: + - ImageOverride -equals MMS2019 + + steps: + - checkout: self + clean: true + - checkout: ComplianceRepo + clean: true + - download: current + artifact: 'PowerShellGet' + - template: assembly-module-compliance.yml@ComplianceRepo + parameters: + # binskim + AnalyzeTarget: '$(Pipeline.Workspace)/PowerShellGet/netstandard2.0/PowerShellGet.dll' + AnalyzeSymPath: 'SRV*' + # component-governance + sourceScanPath: '$(Build.SourcesDirectory)' + # credscan + suppressionsFile: '' + # TermCheck + optionsRulesDBPath: '' + optionsFTPath: '' + # tsa-upload + codeBaseName: 'PowerShellGet_210306' + # selections + APIScan: false # set to false when not using Windows APIs + +- stage: Test + displayName: Test Package + dependsOn: Build + jobs: + - template: test.yml + parameters: + jobName: TestPkgWin + displayName: PowerShell Core on Windows + imageName: windows-latest + + - template: test.yml + parameters: + jobName: TestPkgWinPS + displayName: Windows PowerShell on Windows + imageName: windows-latest + powershellExecutable: powershell + +# - template: test.yml +# parameters: +# jobName: TestPkgUbuntu16 +# displayName: PowerShell Core on Ubuntu 16.04 +# imageName: ubuntu-16.04 + +# - template: test.yml +# parameters: +# jobName: TestPkgWinMacOS +# displayName: PowerShell Core on macOS +# imageName: macOS-10.14 + +- stage: Release + displayName: Release Package + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), eq(variables['Publish'], 'True')) + jobs: + - template: release.yml diff --git a/.ci/release.yml b/.ci/release.yml new file mode 100644 index 000000000..cd925a477 --- /dev/null +++ b/.ci/release.yml @@ -0,0 +1,47 @@ +parameters: + jobName: release + imageName: windows-latest + displayName: 'Release PowerShellGet to NuGet' + +jobs: +- job: ${{ parameters.jobName }} + pool: + vmImage: ${{ parameters.imageName }} + displayName: ${{ parameters.displayName }} + + steps: + - task: NuGetToolInstaller@1 + displayName: 'Install NuGet 5.6.0' + inputs: + checkLatest: false + version: 5.6.0 + + - task: DownloadBuildArtifacts@0 + displayName: 'Download PowerShellGet module artifacts' + inputs: + buildType: current + downloadType: specific + artifactName: '**/*.nupkg' + downloadPath: '$(System.ArtifactsDirectory)' + + - powershell: | + Get-ChildItem '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' -ErrorAction SilentlyContinue + # Get-ChildItem '$(System.ArtifactsDirectory)' -Recurse + displayName: 'Capture PowerShellGet module NuGet package' + + # TODO: Need to create NuGet service connection + #- task: NuGetCommand@2 + # displayName: 'Push Microsoft.PowerShell.Store module artifacts to AzArtifactsFeed' + # inputs: + # command: push + # packagesToPush: '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' + # nuGetFeedType: external + # publishFeedCredentials: AzArtifactFeed + + #- task: NuGetCommand@2 + # displayName: 'Push Microsoft.PowerShell.Store module artifacts to PSGallery feed' + # inputs: + # command: push + # packagesToPush: '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' + # nuGetFeedType: external + # publishFeedCredentials: PHPowerShellGalleryFeed From 9d00695f2578a8354cee50e8ea0fc0dc0a3a3b54 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 9 Jun 2021 08:10:15 -0700 Subject: [PATCH 010/276] Add mirroring yaml (#375) --- .ci/mirrorTemplates/githubMirror.yml | 107 +++++++++++++++++++++++++++ .ci/powershellGetMirror.yml | 31 ++++++++ 2 files changed, 138 insertions(+) create mode 100644 .ci/mirrorTemplates/githubMirror.yml create mode 100644 .ci/powershellGetMirror.yml diff --git a/.ci/mirrorTemplates/githubMirror.yml b/.ci/mirrorTemplates/githubMirror.yml new file mode 100644 index 000000000..a0c7dae1d --- /dev/null +++ b/.ci/mirrorTemplates/githubMirror.yml @@ -0,0 +1,107 @@ +parameters: + - name: repoName + default: '' + - name: organization + default: powershell + +stages: + - stage: Mirror_${{ replace(parameters.reponame,'-','_') }} + displayName: Mirror ${{ parameters.reponame }} + jobs: + - job: Mirror_${{ replace(parameters.reponame,'-','_') }} + displayName: Mirror ${{ parameters.reponame }} + cancelTimeoutInMinutes: 1 + + pool: + name: 1ES + demands: + - ImageOverride -equals MMS2019 + + variables: + # AzDO intercepts some git cli calls and turns them into API calls + # prefer git says to always use the cli + - name: system.prefergit + value: true + # We are only mirroring and not building, so ignore nuget + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: repoFolder + value: ${{ parameters.reponame }} + - name: ghRepoFolder + value: ${{ parameters.reponame }}-gh + - name: repoPath + value: $(Agent.BuildDirectory)\$(repoFolder) + - name: ghRepoPath + value: $(Agent.BuildDirectory)\$(ghRepoFolder) + + steps: + - checkout: ${{ parameters.reponame }} + clean: true + path: $(repoFolder) + # We need the credentials to push back to the AzDO repo + persistCredentials: True + + # using multi checkout because sometimes the GitHub repo is private + # this makes the template the same, + # even if a private repo requires authentication + - checkout: ${{ parameters.reponame }}-gh + clean: true + path: $(ghRepoFolder) + + - pwsh: | + $commitId = git rev-parse --verify HEAD + + $vstsCommandString = "vso[task.setvariable variable=CommitId]$commitId" + + Write-Host "sending " + $vstsCommandString + + Write-Host "##$vstsCommandString" + displayName: Saving AzDO commitid + workingDirectory: '$(repoPath)' + + - pwsh: | + Write-verbose -message 'creating master from HEAD' -verbose + git branch master + + Write-verbose -message 'checking out master' -verbose + git checkout master + + Write-verbose -message 'getting git status' -verbose + git status + displayName: Set branch to master on GitHub repo + workingDirectory: '$(ghRepoPath)' + + - pwsh: | + Write-verbose -message 'adding github remote' -verbose + git remote add github $(ghRepoPath) + + Write-verbose -message 'listing remotes' -verbose + git remote -v + + Write-verbose -message 'fetching github master' -verbose + git fetch --quiet github master + + Write-verbose -message 'Checkout master branch as github master' -verbose + git checkout --quiet -b master github/master + displayName: Checkout GitHub master branch as master + workingDirectory: '$(repoPath)' + + - pwsh: | + $commitId = git rev-parse --verify HEAD + + Write-verbose -message "$commitId -ne $env:commitId" -verbose + + if ($commitId -ne $env:commitId) + { + Write-verbose -message 'pushing (quiet)...' -verbose + git branch + git push --quiet origin master + } + else + { + Write-verbose -message 'Nothing to update' -verbose + } + displayName: Push to AzDO if needed + workingDirectory: '$(repoPath)' + env: + MY_ACCESS_TOKEN: $(System.AccessToken) diff --git a/.ci/powershellGetMirror.yml b/.ci/powershellGetMirror.yml new file mode 100644 index 000000000..a69fbdc45 --- /dev/null +++ b/.ci/powershellGetMirror.yml @@ -0,0 +1,31 @@ +# Mirror github ThreadJob repo to this release pipeline repo at the provided schedule +# + +trigger: none +pr: none + +schedules: +# You can use https://crontab.guru/#0_8_*_*_* to figure out your crontab expression +# Mirror repo every day at 8 am +- cron: 0 8 * * * + branches: + include: + - refs/heads/master + always: true + +resources: + repositories: + - repository: PowerShellGetV3 + type: git + name: PowerShellGetV3 + ref: master + - repository: PowerShellGet-gh + ref: master + type: github + endpoint: ComplianceGHRepo + name: PowerShell/PowerShellGet + +stages: + - template: ./mirrorTemplates/githubMirror.yml + parameters: + repoName: PowerShellGet From 918621c47d7529814e5028c8177373781552f358 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 9 Jun 2021 10:49:22 -0700 Subject: [PATCH 011/276] Fix mirror repository name (#376) Co-authored-by: Anam Navied Co-authored-by: Amber Erickson --- .ci/powershellGetMirror.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/powershellGetMirror.yml b/.ci/powershellGetMirror.yml index a69fbdc45..e011439bb 100644 --- a/.ci/powershellGetMirror.yml +++ b/.ci/powershellGetMirror.yml @@ -15,7 +15,7 @@ schedules: resources: repositories: - - repository: PowerShellGetV3 + - repository: PowerShellGet type: git name: PowerShellGetV3 ref: master From f3b9a863677cb961ee16e291ce52320bbc01c557 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 9 Jun 2021 11:14:10 -0700 Subject: [PATCH 012/276] Refactor Get-InstalledPSResource cmdlet (#374) --- help/Get-InstalledPSResource.md | 136 +++++ help/Get-PSResource.md | 126 ---- help/en-US/PowerShellGet.dll-Help.xml | 4 +- src/PSGet.Format.ps1xml | 27 + src/PSModule.psm1 | 60 +- src/PowerShellGet.psd1 | 258 ++++---- src/code/GetInstalledPSResource.cs | 132 ++++ src/code/PSResourceInfo.cs | 834 +++++++++++++------------- src/code/PowerShellGet.csproj | 84 +-- src/code/Utils.cs | 8 +- test/GetInstalledPSResource.Tests.ps1 | 107 ++++ 11 files changed, 1029 insertions(+), 747 deletions(-) create mode 100644 help/Get-InstalledPSResource.md delete mode 100644 help/Get-PSResource.md create mode 100644 src/PSGet.Format.ps1xml create mode 100644 src/code/GetInstalledPSResource.cs create mode 100644 test/GetInstalledPSResource.Tests.ps1 diff --git a/help/Get-InstalledPSResource.md b/help/Get-InstalledPSResource.md new file mode 100644 index 000000000..bb3a76b17 --- /dev/null +++ b/help/Get-InstalledPSResource.md @@ -0,0 +1,136 @@ +--- +external help file: PowerShellGet.dll-Help.xml +Module Name: PowerShellGet +online version: +schema: 2.0.0 +--- + +# Get-InstalledPSResource + +## SYNOPSIS +Returns resources (modules and scripts) installed on the machine via PowerShellGet. + +## SYNTAX + +``` +Get-InstalledPSResource [[-Name] ] [-Version ] [-Path ] [] +``` + +## DESCRIPTION +The Get-InstalledPSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describe each resource item found. Other parameters allow the returned results to be filtered by version and path. + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> Get-InstalledPSResource Az +``` + +This will return versions of the Az module installed via PowerShellGet. + +### Example 2 +```powershell +PS C:\> Get-InstalledPSResource Az -version "1.0.0" +``` + +This will return version 1.0.0 of the Az module. + +### Example 3 +```powershell +PS C:\> Get-InstalledPSResource Az -version "(1.0.0, 3.0.0)" +``` + +This will return all versions of the Az module within the specified range. + +### Example 4 +```powershell +PS C:\> Get-InstalledPSResource Az -Path . +``` + +This will return all versions of the Az module that have been installed in the current directory. + +## PARAMETERS + +### -Name +Name of a resource or resources to find. Accepts wild card characters. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: 0 +Default value: None +Accept pipeline input: True (ByPropertyName, ByValue) +Accept wildcard characters: True +``` + +### -Path +Specifies the path to search in. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Version +Specifies the version of the resource to be returned. Can be an exact version or a version range. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +## OUTPUTS + +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +``` +PSRepositoryItemInfo : { + AdditionalMetadata + Author + CompanyName + Copyright + Dependencies + Description + IconUri + Includes + InstalledDate + InstalledLocation + IsPrerelease + LicenseUri + Name + PackageManagementProvider + PowerShellGetFormatVersion + ProjectUri + PublishedDate + ReleaseNotes + Repository + RepositorySourceLocation + Tags + Type + UpdatedDate + Version +} +``` + +## NOTES + +## RELATED LINKS diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md deleted file mode 100644 index 439fed776..000000000 --- a/help/Get-PSResource.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -external help file: PowerShellGet.dll-Help.xml -Module Name: PowerShellGet -online version: -schema: 2.0.0 ---- - -# Get-PSResource - -## SYNOPSIS -{{ Fill in the Synopsis }} - -## SYNTAX - -``` -Get-PSResource [[-Name] ] [-Version ] [-Path ] [-WhatIf] [-Confirm] - [] -``` - -## DESCRIPTION -{{ Fill in the Description }} - -## EXAMPLES - -### Example 1 -```powershell -PS C:\> {{ Add example code here }} -``` - -{{ Add example description here }} - -## PARAMETERS - -### -Name -{{ Fill Name Description }} - -```yaml -Type: System.String[] -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` - -### -Path -{{ Fill Path Description }} - -```yaml -Type: System.String -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Version -{{ Fill Version Description }} - -```yaml -Type: System.String -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Confirm -Prompts you for confirmation before running the cmdlet. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: cf - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: wi - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### System.String[] - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - -[]() - diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index f45d6a1d7..89cd50ebe 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -353,7 +353,7 @@ - Get-PSResource + Get-InstalledPSResource Get PSResource @@ -4038,4 +4038,4 @@ - \ No newline at end of file + diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml new file mode 100644 index 000000000..9a5833055 --- /dev/null +++ b/src/PSGet.Format.ps1xml @@ -0,0 +1,27 @@ + + + + + PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + + + + + + + + + Name + Version + Description + + + + + + + diff --git a/src/PSModule.psm1 b/src/PSModule.psm1 index 882810e54..64c9f14c9 100644 --- a/src/PSModule.psm1 +++ b/src/PSModule.psm1 @@ -1,30 +1,30 @@ -# -# Script module for module 'PowerShellGet' -# -Set-StrictMode -Version Latest - -# Summary: PowerShellGet is supported on Windows PowerShell 5.1 or later and PowerShell 6.0+ - -$isCore = ($PSVersionTable.Keys -contains "PSEdition") -and ($PSVersionTable.PSEdition -ne 'Desktop') -if ($isCore) -{ - $script:Framework = 'netstandard2.0' - $script:FrameworkToRemove = 'net472' - -} else { - $script:Framework = 'net472' - $script:FrameworkToRemove = 'netstandard2.0' -} - -# Set up some helper variables to make it easier to work with the module -$script:PSModule = $ExecutionContext.SessionState.Module -$script:PSModuleRoot = $script:PSModule.ModuleBase -$script:PSGet = 'PowerShellGet.dll' - -# CONSTRUCT A PATH TO THE CORRECT ASSEMBLY -#$pathToAssembly = [io.path]::combine($PSScriptRoot, $script:Framework, $script:PSGet) -$pathToFramework = Join-Path -Path $script:PSModuleRoot -ChildPath $script:Framework -$pathToAssembly = Join-Path -Path $pathToFramework -ChildPath $script:PSGet - -# NOW LOAD THE APPROPRIATE ASSEMBLY -Import-Module -Name $pathToAssembly +# +# Script module for module 'PowerShellGet' +# +Set-StrictMode -Version Latest + +# Summary: PowerShellGet is supported on Windows PowerShell 5.1 or later and PowerShell 6.0+ + +$isCore = ($PSVersionTable.Keys -contains "PSEdition") -and ($PSVersionTable.PSEdition -ne 'Desktop') +if ($isCore) +{ + $script:Framework = 'netstandard2.0' + $script:FrameworkToRemove = 'net472' + +} else { + $script:Framework = 'net472' + $script:FrameworkToRemove = 'netstandard2.0' +} + +# Set up some helper variables to make it easier to work with the module +$script:PSModule = $ExecutionContext.SessionState.Module +$script:PSModuleRoot = $script:PSModule.ModuleBase +$script:PSGet = 'PowerShellGet.dll' + +# CONSTRUCT A PATH TO THE CORRECT ASSEMBLY +#$pathToAssembly = [io.path]::combine($PSScriptRoot, $script:Framework, $script:PSGet) +$pathToFramework = Join-Path -Path $script:PSModuleRoot -ChildPath $script:Framework +$pathToAssembly = Join-Path -Path $pathToFramework -ChildPath $script:PSGet + +# NOW LOAD THE APPROPRIATE ASSEMBLY +Import-Module -Name $pathToAssembly diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 4bbadfbf5..0abe96264 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -1,129 +1,129 @@ -@{ - RootModule = 'PSModule.psm1' - ModuleVersion = '3.0.0' - GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' - Author = 'Microsoft Corporation' - CompanyName = 'Microsoft Corporation' - Copyright = '(c) Microsoft Corporation. All rights reserved.' - Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.' - PowerShellVersion = '3.0' - CmdletsToExport = @( - 'Find-PSResource', - 'Get-PSResourceRepository', - 'Get-PSResource', - 'Install-PSResource', - 'Register-PSResourceRepository', - 'Save-PSResource', - 'Set-PSResourceRepository', - 'Publish-PSResource', - 'Uninstall-PSResource', - 'Unregister-PSResourceRepository', - 'Update-PSResource') - - VariablesToExport = 'PSGetPath' - AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') - PrivateData = @{ - PSData = @{ - Prerelease = 'beta10' - Tags = @('PackageManagement', - 'PSEdition_Desktop', - 'PSEdition_Core', - 'Linux', - 'Mac', - 'Windows') - ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' - LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' - ReleaseNotes = @' -### 3.0.0-beta10 -# Changelog -Bug Fixes -* Bug fix for -ModuleName (used with -Version) in Find-PSResource returning incorrect resource type -* Make repositories unique by name -* Add tab completion for -Name parameter in Get-PSResource, Set-PSResource, and Unregister-PSResource -* Remove credential argument from Register-PSResourceRepository -* Change returned version type from 'NuGet.Version' to 'System.Version' -* Have Install output verbose message on successful installation (error for unsuccessful installation) -* Ensure that not passing credentials does not throw an error if searching through multiple repositories -* Remove attempt to remove loaded assemblies in psm1 - -### 3.0.0-beta9 -New Features -* Add DSCResources - -Bug Fixes -* Fix bug related to finding dependencies that do not have a specified version in Find-PSResource -* Fix bug related to parsing 'RequiredModules' in .psd1 in Publish-PSResource -* Improve error handling for when repository in Publish-PSResource does not exist -* Fix for unix paths in Get-PSResource, Install-PSResource, and Uninstall-PSResource -* Add debugging statements for Get-PSResource and Install-PSResource -* Fix bug related to paths in Uninstall-PSResource - -### 3.0.0-beta8 -New Features -* Add Type parameter to Install-PSResource -* Add 'sudo' check for admin privileges in Unix in Install-PSResource - -Bug Fixes -* Fix bug with retrieving installed scripts in Get-PSResource -* Fix bug with AllUsers scope in Windows in Install-PSResource -* Fix bug with Uninstall-PSResource sometimes not fully uninstalling -* Change installed file paths to contain original version number instead of normalized version - -### 3.0.0-beta7 -New Features -* Completed functionality for Update-PSResource -* Input-Object parameter for Install-PSResource - -Bug Fixes -* Improved experience when loading module for diffent frameworks -* Bug fix for assembly loading error in Publish-PSResource -* Allow for relative paths when registering psrepository -* Improved error handling for Install-PSResource and Update-PSResource -* Remove prerelease tag from module version directory -* Fix error getting thrown from paths with incorrectly formatted module versions -* Fix module installation paths on Linux and MacOS - -### 3.0.0-beta6 -New Feature -* Implement functionality for Publish-PSResource - -### 3.0.0-beta5 -* Note: 3.0.0-beta5 was skipped due to a packaging error - -### 3.0.0-beta4 -New Feature -* Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository - -Bug Fix -* Fix poor error handling for when repository is not accessible in Find-PSResource - -### 3.0.0-beta3 -New Features -* -RequiredResource parameter for Install-PSResource -* -RequiredResourceFile parameter for Install-PSResource -* -IncludeXML parameter in Save-PSResource - -Bug Fixes -* Resolved paths in Install-PSRsource and Save-PSResource -* Resolved issues with capitalization (for unix systems) in Install-PSResource and Save-PSResource - -### 3.0.0-beta2 -New Features -* Progress bar and -Quiet parameter for Install-PSResource -* -TrustRepository parameter for Install-PSResource -* -NoClobber parameter for Install-PSResource -* -AcceptLicense for Install-PSResource -* -Force parameter for Install-PSResource -* -Reinstall parameter for Install-PSResource -* Improved error handling - -### 3.0.0-beta1 -BREAKING CHANGE -* Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. - -'@ - } - } - - HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' -} +@{ + RootModule = 'PSModule.psm1' + ModuleVersion = '3.0.0' + GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' + Author = 'Microsoft Corporation' + CompanyName = 'Microsoft Corporation' + Copyright = '(c) Microsoft Corporation. All rights reserved.' + Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, Scripts, and DSC Resources.' + PowerShellVersion = '3.0' + CmdletsToExport = @( + 'Find-PSResource', + 'Get-PSResourceRepository', + 'Get-InstalledPSResource', + 'Install-PSResource', + 'Register-PSResourceRepository', + 'Save-PSResource', + 'Set-PSResourceRepository', + 'Publish-PSResource', + 'Uninstall-PSResource', + 'Unregister-PSResourceRepository', + 'Update-PSResource') + + VariablesToExport = 'PSGetPath' + AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') + PrivateData = @{ + PSData = @{ + Prerelease = 'beta10' + Tags = @('PackageManagement', + 'PSEdition_Desktop', + 'PSEdition_Core', + 'Linux', + 'Mac', + 'Windows') + ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' + LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' + ReleaseNotes = @' +### 3.0.0-beta10 +# Changelog +Bug Fixes +* Bug fix for -ModuleName (used with -Version) in Find-PSResource returning incorrect resource type +* Make repositories unique by name +* Add tab completion for -Name parameter in Get-PSResource, Set-PSResource, and Unregister-PSResource +* Remove credential argument from Register-PSResourceRepository +* Change returned version type from 'NuGet.Version' to 'System.Version' +* Have Install output verbose message on successful installation (error for unsuccessful installation) +* Ensure that not passing credentials does not throw an error if searching through multiple repositories +* Remove attempt to remove loaded assemblies in psm1 + +### 3.0.0-beta9 +New Features +* Add DSCResources + +Bug Fixes +* Fix bug related to finding dependencies that do not have a specified version in Find-PSResource +* Fix bug related to parsing 'RequiredModules' in .psd1 in Publish-PSResource +* Improve error handling for when repository in Publish-PSResource does not exist +* Fix for unix paths in Get-PSResource, Install-PSResource, and Uninstall-PSResource +* Add debugging statements for Get-PSResource and Install-PSResource +* Fix bug related to paths in Uninstall-PSResource + +### 3.0.0-beta8 +New Features +* Add Type parameter to Install-PSResource +* Add 'sudo' check for admin privileges in Unix in Install-PSResource + +Bug Fixes +* Fix bug with retrieving installed scripts in Get-PSResource +* Fix bug with AllUsers scope in Windows in Install-PSResource +* Fix bug with Uninstall-PSResource sometimes not fully uninstalling +* Change installed file paths to contain original version number instead of normalized version + +### 3.0.0-beta7 +New Features +* Completed functionality for Update-PSResource +* Input-Object parameter for Install-PSResource + +Bug Fixes +* Improved experience when loading module for diffent frameworks +* Bug fix for assembly loading error in Publish-PSResource +* Allow for relative paths when registering psrepository +* Improved error handling for Install-PSResource and Update-PSResource +* Remove prerelease tag from module version directory +* Fix error getting thrown from paths with incorrectly formatted module versions +* Fix module installation paths on Linux and MacOS + +### 3.0.0-beta6 +New Feature +* Implement functionality for Publish-PSResource + +### 3.0.0-beta5 +* Note: 3.0.0-beta5 was skipped due to a packaging error + +### 3.0.0-beta4 +New Feature +* Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository + +Bug Fix +* Fix poor error handling for when repository is not accessible in Find-PSResource + +### 3.0.0-beta3 +New Features +* -RequiredResource parameter for Install-PSResource +* -RequiredResourceFile parameter for Install-PSResource +* -IncludeXML parameter in Save-PSResource + +Bug Fixes +* Resolved paths in Install-PSRsource and Save-PSResource +* Resolved issues with capitalization (for unix systems) in Install-PSResource and Save-PSResource + +### 3.0.0-beta2 +New Features +* Progress bar and -Quiet parameter for Install-PSResource +* -TrustRepository parameter for Install-PSResource +* -NoClobber parameter for Install-PSResource +* -AcceptLicense for Install-PSResource +* -Force parameter for Install-PSResource +* -Reinstall parameter for Install-PSResource +* Improved error handling + +### 3.0.0-beta1 +BREAKING CHANGE +* Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. + +'@ + } + } + + HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' +} diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs new file mode 100644 index 000000000..e71356f20 --- /dev/null +++ b/src/code/GetInstalledPSResource.cs @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Management.Automation; +using System.Threading; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// It retrieves a resource that was installed with Install-PSResource + /// Returns a single resource or multiple resource. + /// + [Cmdlet(VerbsCommon.Get, "InstalledPSResource", HelpUri = "")] + public sealed + class GetInstalledPSResource : PSCmdlet + { + #region Parameters + + /// + /// Specifies the desired name for the resource to look for. + /// + [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + public string[] Name { get; set; } + + /// + /// Specifies the version of the resource to include to look for. + /// + [Parameter()] + [ValidateNotNullOrEmpty()] + public string Version { get; set; } + + /// + /// Specifies the path to look in. + /// + [Parameter()] + [ValidateNotNullOrEmpty()] + public string Path { get; set; } + + #endregion + + private CancellationTokenSource _source; + private CancellationToken _cancellationToken; + private VersionRange _versionRange; + List _pathsToSearch; + + #region Methods + + protected override void BeginProcessing() + { + _source = new CancellationTokenSource(); + _cancellationToken = _source.Token; + + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (Version == null) + { + _versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + if (Path != null) + { + this.WriteDebug(string.Format("Provided path is: '{0}'", Path)); + + var resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path).ToString(); + + try + { + _pathsToSearch.AddRange(Directory.GetDirectories(resolvedPath)); + } + catch (Exception e) + { + var exMessage = String.Format("Error retrieving directories from provided path '{0}': '{1}'.", Path, e.Message); + var ex = new ArgumentException(exMessage); + var ErrorRetrievingDirectories = new ErrorRecord(ex, "ErrorRetrievingDirectories", ErrorCategory.ResourceUnavailable, null); + ThrowTerminatingError(ErrorRetrievingDirectories); + } + } + else + { + // retrieve all possible paths + _pathsToSearch = Utils.GetAllResourcePaths(this); + } + + if (Name == null) + { + Name = new string[] { "*" }; + } + // if '*' is passed in as an argument for -Name with other -Name arguments, + // ignore all arguments except for '*' since it is the most inclusive + // eg: -Name ["TestModule, Test*, *"] will become -Name ["*"] + if (Name != null && Name.Length > 1) + { + foreach (var pkgName in Name) + { + if (pkgName.Trim().Equals("*")) + { + Name = new string[] { "*" }; + break; + } + } + } + } + + protected override void ProcessRecord() + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + + WriteDebug("Entering GetInstalledPSResource"); + + GetHelper getHelper = new GetHelper(cancellationToken, this); + foreach (PSResourceInfo pkg in getHelper.ProcessGetParams(Name, _versionRange, _pathsToSearch)) + { + WriteObject(pkg); + } + } + + #endregion + } +} diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index cdac5664a..e50264066 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -1,416 +1,418 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Management.Automation; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - #region Enums - - public enum ResourceType - { - Module, - Script - } - - public enum VersionType - { - Unknown, - MinimumVersion, - RequiredVersion, - MaximumVersion - } - - #endregion - - #region VersionInfo - - public sealed class VersionInfo - { - public VersionInfo( - VersionType versionType, - Version versionNum) - { - VersionType = versionType; - VersionNum = versionNum; - } - - public VersionType VersionType { get; } - public Version VersionNum { get; } - - public override string ToString() => $"{VersionType}: {VersionNum}"; - } - - #endregion - - #region ResourceIncludes - - public sealed class ResourceIncludes - { - #region Properties - - public string[] Cmdlet { get; } - - public string[] Command { get; } - - public string[] DscResource { get; } - - public string[] Function { get; } - - public string[] RoleCapability { get; } - - public string[] Workflow { get; } - - #endregion - - #region Constructor - - /// - /// Constructor - /// - /// Provided hashtable has form: - /// Key: Cmdlet - /// Value: ArrayList of Cmdlet name strings - /// Key: Command - /// Value: ArrayList of Command name strings - /// Key: DscResource - /// Value: ArrayList of DscResource name strings - /// Key: Function - /// Value: ArrayList of Function name strings - /// Key: RoleCapability (deprecated for PSGetV3) - /// Value: ArrayList of RoleCapability name strings - /// Key: Workflow (deprecated for PSGetV3) - /// Value: ArrayList of Workflow name strings - /// - /// Hashtable of PSGet includes - public ResourceIncludes(Hashtable includes) - { - if (includes == null) { return; } - - Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); - Command = GetHashTableItem(includes, nameof(Command)); - DscResource = GetHashTableItem(includes, nameof(DscResource)); - Function = GetHashTableItem(includes, nameof(Function)); - RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); - Workflow = GetHashTableItem(includes, nameof(Workflow)); - } - - #endregion - - #region Public methods - - public Hashtable ConvertToHashtable() - { - var hashtable = new Hashtable - { - { nameof(Cmdlet), Cmdlet }, - { nameof(Command), Command }, - { nameof(DscResource), DscResource }, - { nameof(Function), Function }, - { nameof(RoleCapability), RoleCapability }, - { nameof(Workflow), Workflow } - }; - - return hashtable; - } - - #endregion - - #region Private methods - - private string[] GetHashTableItem( - Hashtable table, - string name) - { - if (table.ContainsKey(name) && - table[name] is PSObject psObjectItem) - { - return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); - } - - return null; - } - - #endregion - } - - #endregion - - #region PSResourceInfo - - public sealed class PSResourceInfo - { - #region Properties - - public Dictionary AdditionalMetadata { get; set; } - public string Author { get; set; } - public string CompanyName { get; set; } - public string Copyright { get; set; } - public string[] Dependencies { get; set; } - public string Description { get; set; } - public Uri IconUri { get; set; } - public ResourceIncludes Includes { get; set; } - public DateTime? InstalledDate { get; set; } - public string InstalledLocation { get; set; } - public Uri LicenseUri { get; set; } - public string Name { get; set; } - public string PackageManagementProvider { get; set; } - public string PowerShellGetFormatVersion { get; set; } - public Uri ProjectUri { get; set; } - public DateTime? PublishedDate { get; set; } - public string ReleaseNotes { get; set; } - public string Repository { get; set; } - public string RepositorySourceLocation { get; set; } - public string[] Tags { get; set; } - public string Type { get; set; } - public DateTime? UpdatedDate { get; set; } - public Version Version { get; set; } - - #endregion - - #region Public static methods - - /// - /// Writes the PSGetResourceInfo properties to the specified file path as a - /// PowerShell serialized xml file, maintaining compatibility with - /// PowerShellGet v2 file format. - /// - public bool TryWrite( - string filePath, - out string errorMsg) - { - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - var infoXml = PSSerializer.Serialize( - source: ConvertToCustomObject(), - depth: 5); - - System.IO.File.WriteAllText( - path: filePath, - contents: infoXml); - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", - ex.Message); - - return false; - } - } - - /// - /// Reads a PSGet resource xml (PowerShell serialized) file and returns - /// a PSGetResourceInfo object containing the file contents. - /// - public static bool TryRead( - string filePath, - out PSResourceInfo psGetInfo, - out string errorMsg) - { - psGetInfo = null; - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - // Read and deserialize information xml file. - var psObjectInfo = (PSObject) PSSerializer.Deserialize( - System.IO.File.ReadAllText( - filePath)); - - psGetInfo = new PSResourceInfo - { - AdditionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo), - Author = GetProperty(nameof(PSResourceInfo.Author), psObjectInfo), - CompanyName = GetProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), - Copyright = GetProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), - Dependencies = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), - Description = GetProperty(nameof(PSResourceInfo.Description), psObjectInfo), - IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), - Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), - InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), - InstalledLocation = GetProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), - LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), - Name = GetProperty(nameof(PSResourceInfo.Name), psObjectInfo), - PackageManagementProvider = GetProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), - PowerShellGetFormatVersion = GetProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), - ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), - PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), - ReleaseNotes = GetProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), - Repository = GetProperty(nameof(PSResourceInfo.Repository), psObjectInfo), - RepositorySourceLocation = GetProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), - Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), - Type = GetProperty(nameof(PSResourceInfo.Type), psObjectInfo), - UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), - Version = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo) - }; - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", - ex.Message); - - return false; - } - } - - #endregion - - #region Private static methods - - private static T ConvertToType(PSObject psObject) - { - // We only convert Dictionary types. - if (typeof(T) != typeof(Dictionary)) - { - return default(T); - } - - var dict = new Dictionary(); - foreach (var prop in psObject.Properties) - { - dict.Add(prop.Name, prop.Value.ToString()); - } - - return (T)Convert.ChangeType(dict, typeof(T)); - } - - private static T GetProperty( - string Name, - PSObject psObjectInfo) - { - var val = psObjectInfo.Properties[Name]?.Value; - if (val == null) - { - return default(T); - } - - switch (val) - { - case T valType: - return valType; - - case PSObject valPSObject: - switch (valPSObject.BaseObject) - { - case T valBase: - return valBase; - - case PSCustomObject _: - // A base object of PSCustomObject means this is additional metadata - // and type T should be Dictionary. - return ConvertToType(valPSObject); - - default: - return default(T); - } - - default: - return default(T); - } - } - - #endregion - - #region Private methods - - private PSObject ConvertToCustomObject() - { - var additionalMetadata = new PSObject(); - foreach (var item in AdditionalMetadata) - { - additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); - } - - var psObject = new PSObject(); - psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); - psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); - psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); - psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); - psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); - psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); - psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); - psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); - psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); - psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); - psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); - psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); - psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); - psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(Version), Version)); - - return psObject; - } - - #endregion - } - - #endregion - - #region Test Hooks - - public static class TestHooks - { - public static PSObject ReadPSGetResourceInfo(string filePath) - { - if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - return PSObject.AsPSObject(psGetInfo); - } - - throw new PSInvalidOperationException(errorMsg); - } - - public static void WritePSGetResourceInfo( - string filePath, - PSObject psObjectGetInfo) - { - if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) - { - if (! psGetInfo.TryWrite(filePath, out string errorMsg)) - { - throw new PSInvalidOperationException(errorMsg); - } - - return; - } - - throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); - } - } - - #endregion -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + #region Enums + + public enum ResourceType + { + Module, + Script + } + + public enum VersionType + { + Unknown, + MinimumVersion, + RequiredVersion, + MaximumVersion + } + + #endregion + + #region VersionInfo + + public sealed class VersionInfo + { + public VersionInfo( + VersionType versionType, + Version versionNum) + { + VersionType = versionType; + VersionNum = versionNum; + } + + public VersionType VersionType { get; } + public Version VersionNum { get; } + + public override string ToString() => $"{VersionType}: {VersionNum}"; + } + + #endregion + + #region ResourceIncludes + + public sealed class ResourceIncludes + { + #region Properties + + public string[] Cmdlet { get; } + + public string[] Command { get; } + + public string[] DscResource { get; } + + public string[] Function { get; } + + public string[] RoleCapability { get; } + + public string[] Workflow { get; } + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// Provided hashtable has form: + /// Key: Cmdlet + /// Value: ArrayList of Cmdlet name strings + /// Key: Command + /// Value: ArrayList of Command name strings + /// Key: DscResource + /// Value: ArrayList of DscResource name strings + /// Key: Function + /// Value: ArrayList of Function name strings + /// Key: RoleCapability (deprecated for PSGetV3) + /// Value: ArrayList of RoleCapability name strings + /// Key: Workflow (deprecated for PSGetV3) + /// Value: ArrayList of Workflow name strings + /// + /// Hashtable of PSGet includes + public ResourceIncludes(Hashtable includes) + { + if (includes == null) { return; } + + Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); + Command = GetHashTableItem(includes, nameof(Command)); + DscResource = GetHashTableItem(includes, nameof(DscResource)); + Function = GetHashTableItem(includes, nameof(Function)); + RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); + Workflow = GetHashTableItem(includes, nameof(Workflow)); + } + + #endregion + + #region Public methods + + public Hashtable ConvertToHashtable() + { + var hashtable = new Hashtable + { + { nameof(Cmdlet), Cmdlet }, + { nameof(Command), Command }, + { nameof(DscResource), DscResource }, + { nameof(Function), Function }, + { nameof(RoleCapability), RoleCapability }, + { nameof(Workflow), Workflow } + }; + + return hashtable; + } + + #endregion + + #region Private methods + + private string[] GetHashTableItem( + Hashtable table, + string name) + { + if (table.ContainsKey(name) && + table[name] is PSObject psObjectItem) + { + return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); + } + + return null; + } + + #endregion + } + + #endregion + + #region PSResourceInfo + + public sealed class PSResourceInfo + { + #region Properties + + public Dictionary AdditionalMetadata { get; set; } + public string Author { get; set; } + public string CompanyName { get; set; } + public string Copyright { get; set; } + public string[] Dependencies { get; set; } + public string Description { get; set; } + public Uri IconUri { get; set; } + public ResourceIncludes Includes { get; set; } + public DateTime? InstalledDate { get; set; } + public string InstalledLocation { get; set; } + public bool IsPrerelease { get; set; } + public Uri LicenseUri { get; set; } + public string Name { get; set; } + public string PackageManagementProvider { get; set; } + public string PowerShellGetFormatVersion { get; set; } + public Uri ProjectUri { get; set; } + public DateTime? PublishedDate { get; set; } + public string ReleaseNotes { get; set; } + public string Repository { get; set; } + public string RepositorySourceLocation { get; set; } + public string[] Tags { get; set; } + public string Type { get; set; } + public DateTime? UpdatedDate { get; set; } + public Version Version { get; set; } + + #endregion + + #region Public static methods + + /// + /// Writes the PSGetResourceInfo properties to the specified file path as a + /// PowerShell serialized xml file, maintaining compatibility with + /// PowerShellGet v2 file format. + /// + public bool TryWrite( + string filePath, + out string errorMsg) + { + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + var infoXml = PSSerializer.Serialize( + source: ConvertToCustomObject(), + depth: 5); + + System.IO.File.WriteAllText( + path: filePath, + contents: infoXml); + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", + ex.Message); + + return false; + } + } + + /// + /// Reads a PSGet resource xml (PowerShell serialized) file and returns + /// a PSGetResourceInfo object containing the file contents. + /// + public static bool TryRead( + string filePath, + out PSResourceInfo psGetInfo, + out string errorMsg) + { + psGetInfo = null; + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + // Read and deserialize information xml file. + var psObjectInfo = (PSObject) PSSerializer.Deserialize( + System.IO.File.ReadAllText( + filePath)); + + psGetInfo = new PSResourceInfo + { + AdditionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo), + Author = GetProperty(nameof(PSResourceInfo.Author), psObjectInfo), + CompanyName = GetProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), + Copyright = GetProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), + Dependencies = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), + Description = GetProperty(nameof(PSResourceInfo.Description), psObjectInfo), + IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), + Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), + InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), + InstalledLocation = GetProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), + IsPrerelease = GetProperty(nameof(PSResourceInfo.IsPrerelease), psObjectInfo), + LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), + Name = GetProperty(nameof(PSResourceInfo.Name), psObjectInfo), + PackageManagementProvider = GetProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), + PowerShellGetFormatVersion = GetProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), + ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), + PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), + ReleaseNotes = GetProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), + Repository = GetProperty(nameof(PSResourceInfo.Repository), psObjectInfo), + RepositorySourceLocation = GetProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), + Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), + Type = GetProperty(nameof(PSResourceInfo.Type), psObjectInfo), + UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), + Version = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo) + }; + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", + ex.Message); + + return false; + } + } + + #endregion + + #region Private static methods + + private static T ConvertToType(PSObject psObject) + { + // We only convert Dictionary types. + if (typeof(T) != typeof(Dictionary)) + { + return default(T); + } + + var dict = new Dictionary(); + foreach (var prop in psObject.Properties) + { + dict.Add(prop.Name, prop.Value.ToString()); + } + + return (T)Convert.ChangeType(dict, typeof(T)); + } + + private static T GetProperty( + string Name, + PSObject psObjectInfo) + { + var val = psObjectInfo.Properties[Name]?.Value; + if (val == null) + { + return default(T); + } + + switch (val) + { + case T valType: + return valType; + + case PSObject valPSObject: + switch (valPSObject.BaseObject) + { + case T valBase: + return valBase; + + case PSCustomObject _: + // A base object of PSCustomObject means this is additional metadata + // and type T should be Dictionary. + return ConvertToType(valPSObject); + + default: + return default(T); + } + + default: + return default(T); + } + } + + #endregion + + #region Private methods + + private PSObject ConvertToCustomObject() + { + var additionalMetadata = new PSObject(); + foreach (var item in AdditionalMetadata) + { + additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); + } + + var psObject = new PSObject(); + psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); + psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); + psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); + psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); + psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); + psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); + psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); + psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); + psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); + psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); + psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); + psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); + psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); + psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(Version), Version)); + + return psObject; + } + + #endregion + } + + #endregion + + #region Test Hooks + + public static class TestHooks + { + public static PSObject ReadPSGetResourceInfo(string filePath) + { + if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + return PSObject.AsPSObject(psGetInfo); + } + + throw new PSInvalidOperationException(errorMsg); + } + + public static void WritePSGetResourceInfo( + string filePath, + PSObject psObjectGetInfo) + { + if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) + { + if (! psGetInfo.TryWrite(filePath, out string errorMsg)) + { + throw new PSInvalidOperationException(errorMsg); + } + + return; + } + + throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); + } + } + + #endregion +} diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index b82551231..2a1f3e63e 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -1,42 +1,42 @@ - - - - - Library - PowerShellGet - PowerShellGet - 3.0.0.0 - 3.0.0 - 3.0.0 - netstandard2.0;net472; - - - - - - - - - - - - - - - - - - - - - - - - - - CoreTypes - - - - - + + + + + Library + PowerShellGet + PowerShellGet + 3.0.0.0 + 3.0.0 + 3.0.0 + netstandard2.0;net472; + + + + + + + + + + + + + + + + + + + + + + + + + + CoreTypes + + + + + diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 7f90bf7c6..2ef46c5de 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -25,13 +25,17 @@ public static string GetInstalledPackageName(string pkgPath) { return string.Empty; } + if (File.Exists(pkgPath)) { + // ex: ./PowerShell/Scripts/TestScript.ps1 return System.IO.Path.GetFileNameWithoutExtension(pkgPath); } else - { - return new DirectoryInfo(pkgPath).Parent.ToString(); + { + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; } } diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 new file mode 100644 index 000000000..3b9665a46 --- /dev/null +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -0,0 +1,107 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# // Temporarily commenting out until Install-PSResource is complete +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Get-InstalledPSResource for Module' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + Get-NewPSResourceRepositoryFile + + Register-PSRepository $TestGalleryName -SourceLocation "https://www.poshtestgallery.com/api/v2" + Install-Module ContosoServer -Repository $TestGalleryName + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Get resources without any parameter values" { + $pkgs = Get-InstalledPSResource + $pkgs.Count | Should -BeGreaterThan 1 + } + + It "Get specific module resource by name" { + $pkg = Get-InstalledPSResource -Name ContosoServer + $pkg.Name | Should -Be "ContosoServer" + } + + It "Get specific script resource by name" { + $pkg = Get-InstalledPSResource -Name adsql + $pkg.Name | Should -Be "adsql" + } + + It "Get resource when given Name to " -TestCases @( + @{Name="*ShellG*"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard at beginning and end of name: *ShellG*"}, + @{Name="PowerShell*"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard at end of name: PowerShellG*"}, + @{Name="*ShellGet"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard at beginning of name: *ShellGet"}, + @{Name="Power*Get"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard in middle of name: Power*Get"} + ) { + param($Version, $ExpectedVersion) + $pkgs = Get-InstalledPSResource -Name $Name + $pkgs.Name | Should -Be "PowerShellGet" + } + + It "Get resource when given Name to " -TestCases @( + @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, + @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, + @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + ) { + param($Version, $ExpectedVersion) + $pkgs = Get-InstalledPSResource -Name "ContosoServer" -Version $Version + $pkgs.Name | Should -Be "ContosoServer" + $pkgs.Version | Should -Be $ExpectedVersion + } + + It "Throw invalid version error when passing incorrectly formatted version such as " -TestCases @( + @{Version='[1.*.0]'; Description="version with wilcard in middle"}, + @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, + @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.5.0.*'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.5.0.]'; Description="version with missing digit at end"}, + @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + ) { + param($Version, $Description) + + $res = $null + try { + $res = Find-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore + } + catch {} + + $res | Should -BeNullOrEmpty + } + + # These versions technically parse into proper NuGet versions, but will not return the version expected + It "Does not return resource when passing incorrectly formatted version such as , does not throw error" -TestCases @( + @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, + @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"} + + ) { + param($Version, $Description) + + $res = $null + try { + $res = Find-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore + } + catch {} + + $res | Should -BeNullOrEmpty + } + + It "Get resources when given Name, and Version is '*'" { + $pkgs = Get-InstalledPSResource -Name Carbon -Version "*" + $pkgs.Count | Should -BeGreaterOrEqual 2 + } +} +#> \ No newline at end of file From 39f1718d6f2bd735e11cbca46b20f0d7405aafd6 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 10 Jun 2021 15:23:07 -0700 Subject: [PATCH 013/276] Remove unneeded files (#377) --- .ci/mirrorTemplates/githubMirror.yml | 107 --------------------------- .ci/powershellGetMirror.yml | 31 -------- 2 files changed, 138 deletions(-) delete mode 100644 .ci/mirrorTemplates/githubMirror.yml delete mode 100644 .ci/powershellGetMirror.yml diff --git a/.ci/mirrorTemplates/githubMirror.yml b/.ci/mirrorTemplates/githubMirror.yml deleted file mode 100644 index a0c7dae1d..000000000 --- a/.ci/mirrorTemplates/githubMirror.yml +++ /dev/null @@ -1,107 +0,0 @@ -parameters: - - name: repoName - default: '' - - name: organization - default: powershell - -stages: - - stage: Mirror_${{ replace(parameters.reponame,'-','_') }} - displayName: Mirror ${{ parameters.reponame }} - jobs: - - job: Mirror_${{ replace(parameters.reponame,'-','_') }} - displayName: Mirror ${{ parameters.reponame }} - cancelTimeoutInMinutes: 1 - - pool: - name: 1ES - demands: - - ImageOverride -equals MMS2019 - - variables: - # AzDO intercepts some git cli calls and turns them into API calls - # prefer git says to always use the cli - - name: system.prefergit - value: true - # We are only mirroring and not building, so ignore nuget - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: ${{ parameters.reponame }} - - name: ghRepoFolder - value: ${{ parameters.reponame }}-gh - - name: repoPath - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: ghRepoPath - value: $(Agent.BuildDirectory)\$(ghRepoFolder) - - steps: - - checkout: ${{ parameters.reponame }} - clean: true - path: $(repoFolder) - # We need the credentials to push back to the AzDO repo - persistCredentials: True - - # using multi checkout because sometimes the GitHub repo is private - # this makes the template the same, - # even if a private repo requires authentication - - checkout: ${{ parameters.reponame }}-gh - clean: true - path: $(ghRepoFolder) - - - pwsh: | - $commitId = git rev-parse --verify HEAD - - $vstsCommandString = "vso[task.setvariable variable=CommitId]$commitId" - - Write-Host "sending " + $vstsCommandString - - Write-Host "##$vstsCommandString" - displayName: Saving AzDO commitid - workingDirectory: '$(repoPath)' - - - pwsh: | - Write-verbose -message 'creating master from HEAD' -verbose - git branch master - - Write-verbose -message 'checking out master' -verbose - git checkout master - - Write-verbose -message 'getting git status' -verbose - git status - displayName: Set branch to master on GitHub repo - workingDirectory: '$(ghRepoPath)' - - - pwsh: | - Write-verbose -message 'adding github remote' -verbose - git remote add github $(ghRepoPath) - - Write-verbose -message 'listing remotes' -verbose - git remote -v - - Write-verbose -message 'fetching github master' -verbose - git fetch --quiet github master - - Write-verbose -message 'Checkout master branch as github master' -verbose - git checkout --quiet -b master github/master - displayName: Checkout GitHub master branch as master - workingDirectory: '$(repoPath)' - - - pwsh: | - $commitId = git rev-parse --verify HEAD - - Write-verbose -message "$commitId -ne $env:commitId" -verbose - - if ($commitId -ne $env:commitId) - { - Write-verbose -message 'pushing (quiet)...' -verbose - git branch - git push --quiet origin master - } - else - { - Write-verbose -message 'Nothing to update' -verbose - } - displayName: Push to AzDO if needed - workingDirectory: '$(repoPath)' - env: - MY_ACCESS_TOKEN: $(System.AccessToken) diff --git a/.ci/powershellGetMirror.yml b/.ci/powershellGetMirror.yml deleted file mode 100644 index e011439bb..000000000 --- a/.ci/powershellGetMirror.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Mirror github ThreadJob repo to this release pipeline repo at the provided schedule -# - -trigger: none -pr: none - -schedules: -# You can use https://crontab.guru/#0_8_*_*_* to figure out your crontab expression -# Mirror repo every day at 8 am -- cron: 0 8 * * * - branches: - include: - - refs/heads/master - always: true - -resources: - repositories: - - repository: PowerShellGet - type: git - name: PowerShellGetV3 - ref: master - - repository: PowerShellGet-gh - ref: master - type: github - endpoint: ComplianceGHRepo - name: PowerShell/PowerShellGet - -stages: - - template: ./mirrorTemplates/githubMirror.yml - parameters: - repoName: PowerShellGet From d370779ad875928251fa741a554ab299133e0ed7 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 17 Jun 2021 11:00:32 -0700 Subject: [PATCH 014/276] Add auto yaml (#380) --- .ci/ci.yml | 21 +-- .ci/ci_auto.yml | 368 +++++++++++++++++++++++++++++++++++++++++++++ .ci/ci_release.yml | 27 +--- 3 files changed, 376 insertions(+), 40 deletions(-) create mode 100644 .ci/ci_auto.yml diff --git a/.ci/ci.yml b/.ci/ci.yml index 2a1576951..1ca4269ea 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -29,29 +29,10 @@ stages: vmImage: windows-latest steps: - - powershell: | - $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' - Invoke-WebRequest -Uri https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.ps1 -outfile ./install-powershell.ps1 - ./install-powershell.ps1 -Destination $powerShellPath - $vstsCommandString = "vso[task.setvariable variable=PATH]$powerShellPath;$env:PATH" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install PowerShell Core - - - task: UseDotNet@2 - displayName: 'Install .NET Core 3.1.401 sdk' - inputs: - packageType: sdk - version: 3.1.401 - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet 5.6.0' - inputs: - checkLatest: false - version: 5.6.0 - pwsh: | Get-ChildItem -Path env: + Get-ChildItem -Path env: displayName: Capture environment for build condition: succeededOrFailed() diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml new file mode 100644 index 000000000..4549378c0 --- /dev/null +++ b/.ci/ci_auto.yml @@ -0,0 +1,368 @@ +name: $(BuildDefinitionName)-$(date:yyMM).$(date:dd)$(rev:rrr) +trigger: none +pr: none + +schedules: +# Use https://crontab.guru/#0_8_*_*_* to compute crontab expression +# Run signed build, with limited signing cert, every day at 9 am +- cron: 0 9 * * * + branches: + include: + - refs/heads/master + always: true + +variables: + - group: ESRP + +resources: + repositories: + - repository: ComplianceRepo + type: github + endpoint: ComplianceGHRepo + name: PowerShell/compliance + +stages: +- stage: Build + displayName: Build PowerShellGet Module Package + jobs: + - job: BuildPkg + displayName: Build Package + pool: + name: 1ES + demands: + - ImageOverride -equals MMS2019 + + steps: + + - pwsh: | + Get-ChildItem -Path env: + Get-ChildItem -Path env: + displayName: Capture environment for build + condition: succeededOrFailed() + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + if (Test-Path -Path $modulePath) { + Write-Verbose -Verbose "Deleting existing temp module path: $modulePath" + Remove-Item -Path $modulePath -Recurse -Force -ErrorAction Ignore + } + if (! (Test-Path -Path $modulePath)) { + Write-Verbose -Verbose "Creating new temp module path: $modulePath" + $null = New-Item -Path $modulePath -ItemType Directory + } + displayName: Create temporary module path + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + Write-Verbose -Verbose "Install PowerShellGet V3 to temp module path" + Save-Module -Name PowerShellGet -Path $modulePath -MinimumVersion 3.0.0-beta10 -AllowPrerelease -Force + Write-Verbose -Verbose "Install PlatyPS to temp module path" + Save-Module -Name "platyPS" -Path $modulePath -Force + Write-Verbose -Verbose "Install PSScriptAnalyzer to temp module path" + Save-Module -Name "PSScriptAnalyzer" -Path $modulePath -RequiredVersion 1.18.0 -Force + Write-Verbose -Verbose "Install Pester 5.X to temp module path" + Save-Module -Name "Pester" -MinimumVersion 5.0 -Path $modulePath -Repository PSGallery -Force + Write-Verbose -Verbose "Install PSPackageProject to temp module path" + Save-Module -Name PSPackageProject -Path $modulePath -Force + displayName: Install PSPackageProject and dependencies + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + # + # First build for netstandard2.0 framework + $(Build.SourcesDirectory)/build.ps1 -Build -Clean -BuildConfiguration Release -BuildFramework 'netstandard2.0' + # Next build for net472 framework + $(Build.SourcesDirectory)/build.ps1 -Build -BuildConfiguration Release -BuildFramework 'net472' + displayName: Build and publish artifact + + - pwsh: | + $signSrcPath = "$($config.BuildOutputPath)" + $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${signSrcPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + # + $outSignPath = "$($config.BuildOutputPath)" + $vstsCommandString = "vso[task.setvariable variable=signOutPath]${outSignPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Create fake source and output variables for signing template and no signing + condition: succeeded() + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + + $config = Get-PSPackageProjectConfiguration + + # Created files signing directory + $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" + $createdSignSrcPath = "$($config.BuildOutputPath)\CreatedFiles" + if (! (Test-Path -Path $createdSignSrcPath)) { + $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose + } + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSModule.psm1") -Dest $createdSignSrcPath -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose + + $net472Path = Join-Path -Path $createdSignSrcPath -ChildPath "net472" + if (! (Test-Path -Path $net472Path)) { + $null = New-Item -Path $net472Path -ItemType Directory -Verbose + } + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "net472\PowerShellGet.*") -Dest $net472Path -Force -Verbose + + $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" + if (! (Test-Path -Path $netStandardPath)) { + $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose + } + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0\PowerShellGet.*") -Dest $netStandardPath -Force -Verbose + + $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $signOutPath)) { + $null = New-Item -Path $signOutPath -ItemType Directory + } + + # Set signing src path variable + $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${createdSignSrcPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + + $outSignPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $outSignPath)) { + $null = New-Item -Path $outSignPath -ItemType Directory -Verbose + } + + # Set signing out path variable + $vstsCommandString = "vso[task.setvariable variable=signOutPath]${outSignPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Set up for module created files code signing + condition: succeeded() + + - pwsh: | + Get-ChildItem -Path env: + Get-ChildItem -Path . -Recurse -Directory + displayName: Capture environment for code signing + condition: succeededOrFailed() + + - template: EsrpSign.yml@ComplianceRepo + parameters: + buildOutputPath: $(signSrcPath) + signOutputPath: $(signOutPath) + certificateId: "CP-460906" + shouldSign: $(ShouldSign) + pattern: | + **\*.dll + **\*.psd1 + **\*.psm1 + **\*.ps1xml + **\*.mof + useMinimatch: true + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + + $config = Get-PSPackageProjectConfiguration + + $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $signOutPath)) { + $null = New-Item -Path $signOutPath -ItemType Directory + } + + # Third party files signing directory + $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" + $thirdPartySignSrcPath = "$($config.BuildOutputPath)\ThirdParty" + if (! (Test-Path -Path $thirdPartySignSrcPath)) { + $null = New-Item -Path $thirdPartySignSrcPath -ItemType Directory -Verbose + } + + # Net472 directory + $net472Path = Join-Path -Path $thirdPartySignSrcPath -ChildPath "net472" + if (! (Test-Path -Path $net472Path)) { + $null = New-Item -Path $net472Path -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { + # Copy for third party signing + Copy-Item -Path $_.FullName -Dest $net472Path -Force -Verbose + } + } + } + + # NetStandard directory + $netStandardPath = Join-Path -Path $thirdPartySignSrcPath -ChildPath "netstandard2.0" + if (! (Test-Path -Path $netStandardPath)) { + $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { + # Copy for third party signing + Copy-Item -Path $_.FullName -Dest $netStandardPath -Force -Verbose + } + } + } + + # Set signing src path variable + $vstsCommandString = "vso[task.setvariable variable=signSrcPath]${thirdPartySignSrcPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + + # Set signing out path variable + $vstsCommandString = "vso[task.setvariable variable=signOutPath]${signOutPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Set up for module third party files code signing + condition: succeeded() + + - template: EsrpSign.yml@ComplianceRepo + parameters: + buildOutputPath: $(signSrcPath) + signOutputPath: $(signOutPath) + certificateId: "CP-231522" + pattern: | + **\*.dll + useMinimatch: true + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + + $config = Get-PSPackageProjectConfiguration + + $srcPath = "$($config.BuildOutputPath)\$($config.ModuleName)" + $signOutPath = "$($config.SignedOutputPath)\$($config.ModuleName)" + if (! (Test-Path -Path $signOutPath)) { + $null = New-Item -Path $signOutPath -ItemType Directory + } + + # en-US + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse + + # Net472 directory + $net472SignedOutPath = Join-Path -Path $signOutPath -ChildPath "net472" + if (! (Test-Path -Path $net472SignedOutPath)) { + $null = New-Item -Path $net472SignedOutPath -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { + # Copy already signed files directly to output + Copy-Item -Path $_.FullName -Dest $net472SignedOutPath -Force -Verbose + } + } + } + + # NetStandard directory + $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" + if (! (Test-Path -Path $netStandardSignedOutPath)) { + $null = New-Item -Path $netStandardSignedOutPath -ItemType Directory -Verbose + } + Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "netstandard2.0") -Filter '*.dll' | Foreach-Object { + if ($_.Name -ne 'PowerShellGet.dll') { + $sig = Get-AuthenticodeSignature -FilePath $_.FullName + if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { + # Copy already signed files directly to output + Copy-Item -Path $_.FullName -Dest $netStandardSignedOutPath -Force -Verbose + } + } + } + displayName: Copy already properly signed third party files + condition: succeeded() + + - pwsh: | + $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' + $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath + $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject + Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" + Import-Module -Name $modPath -Force + # + $config = Get-PSPackageProjectConfiguration + $artifactName = "$($config.ModuleName)" + $srcModulePath = Resolve-Path -Path "$($config.SignedOutputPath)/$($config.ModuleName)" + Get-ChildItem $srcModulePath + Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$srcModulePath" + # + $(Build.SourcesDirectory)/build.ps1 -Publish -Signed + displayName: Create signed module artifact + +- stage: Compliance + displayName: Compliance + dependsOn: Build + jobs: + - job: ComplianceJob + pool: + name: 1ES + demands: + - ImageOverride -equals MMS2019 + + steps: + - checkout: self + clean: true + - checkout: ComplianceRepo + clean: true + - download: current + artifact: 'PowerShellGet' + - template: assembly-module-compliance.yml@ComplianceRepo + parameters: + # binskim + AnalyzeTarget: '$(Pipeline.Workspace)/PowerShellGet/netstandard2.0/PowerShellGet.dll' + AnalyzeSymPath: 'SRV*' + # component-governance + sourceScanPath: '$(Build.SourcesDirectory)' + # credscan + suppressionsFile: '' + # TermCheck + optionsRulesDBPath: '' + optionsFTPath: '' + # tsa-upload + codeBaseName: 'PowerShellGet_210306' + # selections + APIScan: false # set to false when not using Windows APIs + +- stage: Test + displayName: Test Package + dependsOn: Build + jobs: + - template: test.yml + parameters: + jobName: TestPkgWin + displayName: PowerShell Core on Windows + imageName: windows-latest + + - template: test.yml + parameters: + jobName: TestPkgWinPS + displayName: Windows PowerShell on Windows + imageName: windows-latest + powershellExecutable: powershell + +# - template: test.yml +# parameters: +# jobName: TestPkgUbuntu16 +# displayName: PowerShell Core on Ubuntu 16.04 +# imageName: ubuntu-16.04 + +# - template: test.yml +# parameters: +# jobName: TestPkgWinMacOS +# displayName: PowerShell Core on macOS +# imageName: macOS-10.14 diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index ecacfaf8b..01b468471 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -32,29 +32,10 @@ stages: - ImageOverride -equals MMS2019 steps: - - powershell: | - $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' - Invoke-WebRequest -Uri https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.ps1 -outfile ./install-powershell.ps1 - ./install-powershell.ps1 -Destination $powerShellPath - $vstsCommandString = "vso[task.setvariable variable=PATH]$powerShellPath;$env:PATH" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install PowerShell Core - - - task: UseDotNet@2 - displayName: 'Install .NET Core 3.1.401 sdk' - inputs: - packageType: sdk - version: 3.1.401 - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet 5.6.0' - inputs: - checkLatest: false - version: 5.6.0 - pwsh: | Get-ChildItem -Path env: + Get-ChildItem -Path env: displayName: Capture environment for build condition: succeededOrFailed() @@ -164,6 +145,12 @@ stages: displayName: Set up for module created files code signing condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + - pwsh: | + Get-ChildItem -Path env: + Get-ChildItem -Path . -Recurse -Directory + displayName: Capture environment for code signing + condition: succeededOrFailed() + - template: EsrpSign.yml@ComplianceRepo parameters: buildOutputPath: $(signSrcPath) From 07ac5ff20a99ee17e099d92ddfb011ea5189949b Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 21 Jun 2021 19:11:56 -0400 Subject: [PATCH 015/276] WIP: Refactor Find-PSResource cmdlet (#363) refactor Find-PSResource with core functionality --- Docs/FindPSResource.md | 117 +-- build.ps1 | 1 + doBuild.ps1 | 4 + help/Find-PSResource.md | 116 ++- pspackageproject.json | 1 + src/PSGet.Format.ps1xml | 2 + src/PowerShellGet.psd1 | 13 +- src/code/FindHelper.cs | 573 +++++++++++++++ src/code/FindPSResource.cs | 224 ++++++ src/code/PSResourceInfo.cs | 1263 ++++++++++++++++++++++----------- src/code/Utils.cs | 411 ++++++----- test/FindPSResource.Tests.ps1 | 206 ++++++ test/PSGetTestUtils.psm1 | 73 +- test/testRepositories.xml | 4 +- 14 files changed, 2308 insertions(+), 700 deletions(-) create mode 100644 src/code/FindHelper.cs create mode 100644 src/code/FindPSResource.cs create mode 100644 test/FindPSResource.Tests.ps1 diff --git a/Docs/FindPSResource.md b/Docs/FindPSResource.md index 368c3b7f2..aebf29349 100644 --- a/Docs/FindPSResource.md +++ b/Docs/FindPSResource.md @@ -2,29 +2,40 @@ The `Find-PSResource` cmdlet combines the `Find-Module, Find-Script, Find-DscResource, Find-Command` cmdlets from V2. It performs a search on a repository (local or remote) based on the `-Name` parameter argument. -It returns `PSRepositoryItemInfo` objects which describe each resource item found. -Other parameters allow the returned results to be filtered by item type and tags. +It returns `PSResourceInfo` objects which describe each resource item found (with Name, Version, Prerelease and Description information displayed, but other properties available too). +Other parameters allow the returned results to be filtered by item Type, Tag, Version and IncludeDependencies. -Alternatively, a `-CommandName` or `-DscResourceName` can be provided and resource packages having those commands or Dsc resources will be returned. -The `-ModuleName` parameter allows the command or dsc resource name search to be limited to a subset of module packages. +Alternatively, a `-CommandName` or `-DscResourceName` can be provided and resource packages having those commands or Dsc resources will be returned. This has not been implemented yet. +The `-ModuleName` parameter allows the command or dsc resource name search to be limited to a subset of module packages. This has not been implemented yet. ## Syntax ### ResourceNameParameterSet (Default) ``` PowerShell -[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tags ] +[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` ### CommandNameParameterSet ``` PowerShell -[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tags ] +[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` ### DscResourceNameParameterSet ``` PowerShell -[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tags ] +[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +``` +### TagParameterSet +``` PowerShell +[[-Name ][-Tag ] [-Prerelease] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +``` + +### TypeParameterSet +``` PowerShell +[[Name ] [-Prerelease] [-Type ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` @@ -33,7 +44,7 @@ The `-ModuleName` parameter allows the command or dsc resource name search to be ### -Name Name of a resource or resources to find. -Accepts wild card characters. +Accepts wild card character '*'. ```yml Type: string[] @@ -43,10 +54,10 @@ Parameter Sets: ResourceNameParameterSet ### -Type Specifies one or more resource types to find. -Two resource types are supported: Module and Script. +Resource types supported are: Module, Script, Command, DscResource. ```yml -Type: string[] +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] Parameter Sets: ResourceNameParameterSet AllowedValues: 'Module','Script','DscResource','Command' ``` @@ -62,14 +73,14 @@ Parameter Sets: (All) ### -Prerelease -When specified, includes prerelease versions in search. +When specified, includes prerelease versions in search results returned. ```yml Type: SwitchParameter Parameter Sets: (All) ``` -### -Tags +### -Tag Filters search results for resources that include one or more of the specified tags. @@ -81,7 +92,7 @@ Parameter Sets: (All) ### -Repository Specifies one or more repository names to search. -If not specified, search will include all currently registered repositories. +If not specified, search will include all currently registered repositories, in order of highest priority, til first repository package is found in. ```yml Type: string[] @@ -100,6 +111,7 @@ Parameter Sets: (All) ### -IncludeDependencies When specified, search will return all matched resources along with any resources the matched resources depends on. +Dependencies are deduplicated. ```yml Type: SwitchParameter @@ -109,7 +121,8 @@ Parameter Sets: (All) ### -CommandName Specifies a list of command names that searched module packages will provide. -Wildcards are supported. +Wildcards are supported. +Not yet implemented. ```yml Type: string[] @@ -119,7 +132,8 @@ Parameter Sets: CommandNameParameterSet ### -DscResourceName Specifies a list of dsc resource names that searched module packages will provide. -Wildcards are supported. +Wildcards are supported. +Not yet implemented. ```yml Type: string[] @@ -129,7 +143,8 @@ Parameter Sets: DscResourceNameParameterSet ### -ModuleName Specifies a module resource package name type to search for. -Wildcards are supported. +Wildcards are supported. +Not yet implemented. ```yml Type: string @@ -139,29 +154,31 @@ Parameter Sets: CommandNameParameterSet, DscResourceParameterSet ### Outputs ```json -"PSRepositoryItemInfo" : { - "Name", - "Version", - "Type", - "Description", +"PSResourceInfo" : { "Author", "CompanyName", "Copyright", - "PublishedDate", - "InstalledDate", - "UpdatedDate", - "LicenseUri", - "ProjectUri", + "Dependencies", + "Description", "IconUri", - "Tags", "Includes", + "InstalledDate", + "InstalledLocation", + "IsPrerelease", + "LicenseUri", + "Name", + "PackageManagementProvider", "PowerShellGetFormatVersion", + "PrereleaseLabel", + "ProjectUri", + "PublishedDate", "ReleaseNotes", - "Dependencies", - "RepositorySourceLocation", "Repository", - "PackageManagementProvider", - "AdditionalMetadata" + "RepositorySourceLocation", + "Tags", + "Type", + "UpdatedDate", + "Version" } ``` @@ -171,33 +188,33 @@ Search strategy will depend on what NuGet APIs support on the server. PowerShell has its own wildcard behavior that may not be compatible with the NuGet APIs. The V2 APIs do provide property filtering and some limited wildcard support. It is not yet clear if V2 or V3 APIs should be used. -Need benefit cost analysis. +Need benefit cost analysis. -Search can be performed on remote or local (file based) repositories, depending on the repository Url. +Search can be performed on remote or local (file based) repositories, depending on the repository Url. Does the `-Credential` parameter apply to all repositories being searched? If so, can that result in an error for repositories that do not require credentials? How are multiple repository searches that require different credentials handled? -Should searches with credential be limited to a single repository? +Should searches with credential be limited to a single repository? Should search results be cached locally on the client machine? If so, should the cache be per PowerShell session or file based? At what point should the local cache be updated from the server? Should there be a parameter switch that forces the search to go directly to the server and skip the local cache? -Should the cache be used if a specific repository is specified? -We should assume that a specific resource package version is identical over any repository from which it is retrieved. +Should the cache be used if a specific repository is specified? +We should assume that a specific resource package version is identical over any repository from which it is retrieved. Should a search with no name or 'all' wildcard result in all repository items returned? -Should there be a default limit for number of items returned, and if so can it be bypassed? +Should there be a default limit for number of items returned, and if so can it be bypassed? The V2 `Find-Command, Find-DscResource` will be combined into `Find-PSResource`. -The `Find-RoleCapability` cmdlet will be dropped for the first release of V3. +The `Find-RoleCapability` cmdlet will be dropped for the first release of V3. ## Tests -Most search tests can be performed on a local repository. +Most search tests can be performed on a local repository. -Some tests should be performed on remote repository (PSGallery) to verify remote operation, but can be limited. +Some tests should be performed on remote repository (PSGallery) to verify remote operation, but can be limited. ### -Name param @@ -247,42 +264,42 @@ Some tests should be performed on remote repository (PSGallery) to verify remote ### Create cmdlet and parameter sets -Create cmdlet class, parameters, and functional stubs +Create cmdlet class, parameters, and functional stubs 1 day ### Implement package search helpers -Create helper functions that support all search functions -Use existing code as starting point +Create helper functions that support all search functions +Use existing code as starting point 4 days ### Investigate V3 API wildcard support -Look into how V3 APIs can be used to reduce what is returned from the server +Look into how V3 APIs can be used to reduce what is returned from the server 7 days ### Implement package filtering functions -Create helper functions to provide filtering of search results +Create helper functions to provide filtering of search results 3 days ### Investigate and implement local cache -Write mini-design document on local caching strategy -Implement local cache +Write mini-design document on local caching strategy +Implement local cache 10 days ### Create test support -Create any test repositories and mocks for tests +Create any test repositories and mocks for tests 4 days ### Write cmdlet tests -Create all functional tests to validate cmdlet +Create all functional tests to validate cmdlet 5 days ### Write support function tests -Create all needed tests to validate caching and search helpers +Create all needed tests to validate caching and search helpers 5 days diff --git a/build.ps1 b/build.ps1 index 4b2284051..ebada6148 100644 --- a/build.ps1 +++ b/build.ps1 @@ -47,6 +47,7 @@ if ( ! ( Get-Module -ErrorAction SilentlyContinue PSPackageProject) ) { $config = Get-PSPackageProjectConfiguration -ConfigPath $PSScriptRoot $script:ModuleName = $config.ModuleName +$script:FormatFileName = $config.FormatFileName $script:SrcPath = $config.SourcePath $script:OutDirectory = $config.BuildOutputPath $script:SignedDirectory = $config.SignedOutputPath diff --git a/doBuild.ps1 b/doBuild.ps1 index 0478fd99f..bc864f1fe 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -23,6 +23,10 @@ function DoBuild Write-Verbose -Verbose "Copy Item ${SrcPath}/PSModule.psm1 to $BuildOutPath" Copy-Item -Path "${SrcPath}/PSModule.psm1" -Dest "$BuildOutPath" -Force + #Copy module format ps1xml file + Write-Verbose -Verbose -Message "Copy-Item ${SrcPath}/${FormatFileName}.ps1xml to $BuildOutPath" + Copy-Item -Path "${SrcPath}/${FormatFileName}.ps1xml" -Dest "$BuildOutPath" -Force + # Create BuildFramework directory for binary location $BuildOutputBin = Join-Path -Path $BuildOutPath -ChildPath $BuildFramework if (! (Test-Path -Path $BuildOutputBin)) { diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index aa3c888f7..a29c9bb27 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -8,32 +8,81 @@ schema: 2.0.0 # Find-PSResource ## SYNOPSIS -{{ Fill in the Synopsis }} +Searches for packages from a repository (local or remote), based on Name or other package properties. + ## SYNTAX +### ResourceNameParameterSet (Default) +``` PowerShell +[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tag ] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +``` + +### CommandNameParameterSet +``` PowerShell +[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +``` + +### DscResourceNameParameterSet +``` PowerShell +[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +``` + +### TagParameterSet +``` PowerShell +[[-Name ][-Tag ] [-Prerelease] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` -Find-PSResource [[-Name] ] [-Type ] [-Version ] [-Prerelease] - [-ModuleName ] [-Tags ] [-Repository ] [-Credential ] - [-IncludeDependencies] [-WhatIf] [-Confirm] [] + +### TypeParameterSet +``` PowerShell +[[Name ] [-Prerelease] [-Type ] +[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -{{ Fill in the Description }} +The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on Name or other package properties. ## EXAMPLES - +These examples assume that the PSGallery repository is registered and contains the packages we are searching for. ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... ``` -{{ Add example description here }} +This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". + +### Example 2 +```powershell +PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... +``` + +This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". + +### Example 3 +```powershell +PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... +``` + +This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". ## PARAMETERS ### -Credential -{{ Fill Credential Description }} +Optional credentials to be used when accessing a repository. ```yaml Type: System.Management.Automation.PSCredential @@ -43,12 +92,13 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` ### -IncludeDependencies -{{ Fill IncludeDependencies Description }} +When specified, search will return all matched resources along with any resources the matched resources depends on. +Dependencies are deduplicated. ```yaml Type: System.Management.Automation.SwitchParameter @@ -58,12 +108,14 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` ### -ModuleName -{{ Fill ModuleName Description }} +Specifies a module resource package name type to search for. +Wildcards are supported. +Not yet implemented. ```yaml Type: System.String @@ -73,27 +125,28 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` ### -Name -{{ Fill Name Description }} +Name of a resource or resources to find. +Accepts wild card character '*'. ```yaml Type: System.String[] Parameter Sets: (All) Aliases: -Required: False +Required: True Position: 0 Default value: None Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -Prerelease -{{ Fill Prerelease Description }} +When specified, includes prerelease versions in search results returned. ```yaml Type: System.Management.Automation.SwitchParameter @@ -108,7 +161,8 @@ Accept wildcard characters: False ``` ### -Repository -{{ Fill Repository Description }} +Specifies one or more repository names to search. +If not specified, search will include all currently registered repositories, in order of highest priority, til first repository package is found in. ```yaml Type: System.String[] @@ -118,12 +172,12 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` -### -Tags -{{ Fill Tags Description }} +### -Tag +Filters search results for resources that include one or more of the specified tags. ```yaml Type: System.String[] @@ -133,28 +187,29 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` ### -Type -{{ Fill Type Description }} +Specifies one or more resource types to find. +Resource types supported are: Module, Script, Command, DscResource. ```yaml -Type: System.String[] +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] Parameter Sets: (All) Aliases: -Accepted values: Module, Script, DscResource, RoleCapability, Command +Accepted values: Module, Script, DscResource, Command Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` ### -Version -{{ Fill Version Description }} +Specifies the version of the resource to be returned. ```yaml Type: System.String @@ -212,13 +267,14 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.Management.Automation.SwitchParameter +### Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + ## OUTPUTS -### System.Object +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo ## NOTES ## RELATED LINKS []() - diff --git a/pspackageproject.json b/pspackageproject.json index 59515fe27..1f2eec33e 100644 --- a/pspackageproject.json +++ b/pspackageproject.json @@ -1,5 +1,6 @@ { "ModuleName": "PowerShellGet", + "FormatFileName": "PSGet.Format", "Culture": "en-US", "BuildOutputPath": "out", "SignedOutputPath": "signed", diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml index 9a5833055..80decb5de 100644 --- a/src/PSGet.Format.ps1xml +++ b/src/PSGet.Format.ps1xml @@ -10,6 +10,7 @@ + @@ -17,6 +18,7 @@ Name Version + PrereleaseLabel Description diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 0abe96264..1b138d65e 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -7,6 +7,7 @@ Copyright = '(c) Microsoft Corporation. All rights reserved.' Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, Scripts, and DSC Resources.' PowerShellVersion = '3.0' + FormatsToProcess = 'PSGet.Format.ps1xml' CmdletsToExport = @( 'Find-PSResource', 'Get-PSResourceRepository', @@ -59,7 +60,7 @@ Bug Fixes * Fix bug related to paths in Uninstall-PSResource ### 3.0.0-beta8 -New Features +New Features * Add Type parameter to Install-PSResource * Add 'sudo' check for admin privileges in Unix in Install-PSResource @@ -70,7 +71,7 @@ Bug Fixes * Change installed file paths to contain original version number instead of normalized version ### 3.0.0-beta7 -New Features +New Features * Completed functionality for Update-PSResource * Input-Object parameter for Install-PSResource @@ -84,7 +85,7 @@ Bug Fixes * Fix module installation paths on Linux and MacOS ### 3.0.0-beta6 -New Feature +New Feature * Implement functionality for Publish-PSResource ### 3.0.0-beta5 @@ -92,19 +93,19 @@ New Feature ### 3.0.0-beta4 New Feature -* Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository +* Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository Bug Fix * Fix poor error handling for when repository is not accessible in Find-PSResource ### 3.0.0-beta3 New Features -* -RequiredResource parameter for Install-PSResource +* -RequiredResource parameter for Install-PSResource * -RequiredResourceFile parameter for Install-PSResource * -IncludeXML parameter in Save-PSResource Bug Fixes -* Resolved paths in Install-PSRsource and Save-PSResource +* Resolved paths in Install-PSRsource and Save-PSResource * Resolved issues with capitalization (for unix systems) in Install-PSResource and Save-PSResource ### 3.0.0-beta2 diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs new file mode 100644 index 000000000..7a100edcf --- /dev/null +++ b/src/code/FindHelper.cs @@ -0,0 +1,573 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Data; +using Dbg = System.Diagnostics.Debug; +using System.Linq; +using System.Management.Automation; +using System.Net; +using System.Net.Http; +using System.Threading; +using MoreLinq.Extensions; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using static Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Find helper class provides the core functionality for FindPSResource. + /// + internal class FindHelper + { + private CancellationToken _cancellationToken; + private readonly PSCmdlet _cmdletPassedIn; + private List _pkgsLeftToFind; + private ResourceType _type; + private string _version; + private SwitchParameter _prerelease = false; + private PSCredential _credential; + private string[] _tag; + private SwitchParameter _includeDependencies = false; + private readonly string _psGalleryRepoName = "PSGallery"; + private readonly string _psGalleryScriptsRepoName = "PSGalleryScripts"; + private bool _isADOFeedRepository; + + // 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 + private const int SearchAsyncMaxTake = 6000; + private const int SearchAsyncMaxReturned = 5990; + private const int GalleryMax = 12000; + + public FindHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) + { + _cancellationToken = cancellationToken; + _cmdletPassedIn = cmdletPassedIn; + } + + public IEnumerable FindByResourceName( + string[] name, + ResourceType type, + string version, + SwitchParameter prerelease, + string[] tag, + string[] repository, + PSCredential credential, + SwitchParameter includeDependencies) + { + _type = type; + _version = version; + _prerelease = prerelease; + _tag = tag; + _credential = credential; + _includeDependencies = includeDependencies; + + Dbg.Assert(name.Length != 0, "Name length cannot be 0"); + + _pkgsLeftToFind = name.ToList(); + + List repositoriesToSearch; + + try + { + repositoriesToSearch = RepositorySettings.Read(repository, out string[] errorList); + + foreach (string error in errorList) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorGettingSpecifiedRepo", + ErrorCategory.InvalidOperation, + this)); + } + } + catch (Exception e) + { + _cmdletPassedIn.ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(e.Message), + "ErrorLoadingRepositoryStoreFile", + ErrorCategory.InvalidArgument, + this)); + yield break; + } + + // loop through repositoriesToSearch and if PSGallery add it to list with same priority as PSGallery repo + for (int i = 0; i < repositoriesToSearch.Count; i++) + { + if (String.Equals(repositoriesToSearch[i].Name, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase)) + { + // 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 + Uri psGalleryScriptsUrl = new Uri("http://www.powershellgallery.com/api/v2/items/psscript/"); + PSRepositoryInfo psGalleryScripts = new PSRepositoryInfo(_psGalleryScriptsRepoName, psGalleryScriptsUrl, repositoriesToSearch[i].Priority, false); + if (_type == ResourceType.None) + { + _cmdletPassedIn.WriteDebug("Null Type provided, so add PSGalleryScripts repository"); + repositoriesToSearch.Insert(i + 1, psGalleryScripts); + } + else if (_type != ResourceType.None && _type == ResourceType.Script) + { + _cmdletPassedIn.WriteDebug("Type Script provided, so add PSGalleryScripts and remove PSGallery (Modules only)"); + repositoriesToSearch.Insert(i + 1, psGalleryScripts); + repositoriesToSearch.RemoveAt(i); // remove PSGallery + } + } + } + + for (int i = 0; i < repositoriesToSearch.Count && _pkgsLeftToFind.Any(); i++) + { + _cmdletPassedIn.WriteDebug(string.Format("Searching in repository {0}", repositoriesToSearch[i].Name)); + foreach (var pkg in SearchFromRepository( + repositoryName: repositoriesToSearch[i].Name, + repositoryUrl: repositoriesToSearch[i].Url)) + { + yield return pkg; + } + } + } + + public IEnumerable SearchFromRepository( + string repositoryName, + Uri repositoryUrl) + { + PackageSearchResource resourceSearch; + PackageMetadataResource resourceMetadata; + SearchFilter filter; + SourceCacheContext context; + + // file based Uri scheme + if (repositoryUrl.Scheme == Uri.UriSchemeFile) + { + FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(repositoryUrl.ToString()); + resourceSearch = new LocalPackageSearchResource(localResource); + resourceMetadata = new LocalPackageMetadataResource(localResource); + filter = new SearchFilter(_prerelease); + context = new SourceCacheContext(); + + foreach(PSResourceInfo pkg in SearchAcrossNamesInRepository( + repositoryName: repositoryName, + pkgSearchResource: resourceSearch, + pkgMetadataResource: resourceMetadata, + searchFilter: filter, + sourceContext: context)) + { + yield return pkg; + } + yield break; + } + + // check if ADOFeed- for which searching for Name with wildcard has a different logic flow + if (repositoryUrl.ToString().Contains("pkgs.visualstudio.com")) + { + _isADOFeedRepository = true; + } + + // HTTP, HTTPS, FTP Uri schemes (only other Uri schemes allowed by RepositorySettings.Read() API) + PackageSource source = new PackageSource(repositoryUrl.ToString()); + if (_credential != null) + { + string password = new NetworkCredential(string.Empty, _credential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl.ToString(), _credential.UserName, password, true, null); + _cmdletPassedIn.WriteVerbose("credential successfully set for repository: " + repositoryName); + } + + // GetCoreV3() API is able to handle V2 and V3 repository endpoints + var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); + SourceRepository repository = new SourceRepository(source, provider); + resourceSearch = null; + resourceMetadata = null; + + try + { + resourceSearch = repository.GetResourceAsync().GetAwaiter().GetResult(); + resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); + } + catch (Exception e){ + _cmdletPassedIn.WriteDebug("Error retrieving resource from repository: " + e.Message); + } + + if (resourceSearch == null || resourceMetadata == null) + { + yield break; + } + + filter = new SearchFilter(_prerelease); + context = new SourceCacheContext(); + + foreach(PSResourceInfo pkg in SearchAcrossNamesInRepository( + repositoryName: repositoryName, + pkgSearchResource: resourceSearch, + pkgMetadataResource: resourceMetadata, + searchFilter: filter, + sourceContext: context)) + { + yield return pkg; + } + } + + public IEnumerable SearchAcrossNamesInRepository( + string repositoryName, + PackageSearchResource pkgSearchResource, + PackageMetadataResource pkgMetadataResource, + SearchFilter searchFilter, + SourceCacheContext sourceContext) + { + foreach (string pkgName in _pkgsLeftToFind.ToArray()) + { + if (String.IsNullOrWhiteSpace(pkgName)) + { + _cmdletPassedIn.WriteDebug(String.Format("Package name: {0} provided was null or whitespace, so name was skipped in search.", + pkgName == null ? "null string" : pkgName)); + continue; + } + + foreach (PSResourceInfo pkg in FindFromPackageSourceSearchAPI( + repositoryName: repositoryName, + pkgName: pkgName, + pkgSearchResource: pkgSearchResource, + pkgMetadataResource: pkgMetadataResource, + searchFilter: searchFilter, + sourceContext: sourceContext)) + { + yield return pkg; + } + } + } + + private IEnumerable FindFromPackageSourceSearchAPI( + string repositoryName, + string pkgName, + PackageSearchResource pkgSearchResource, + PackageMetadataResource pkgMetadataResource, + SearchFilter searchFilter, + SourceCacheContext sourceContext) + { + List foundPackagesMetadata = new List(); + + // filter by param: Name + if (!pkgName.Contains("*")) + { + // case: searching for specific package name i.e "Carbon" + IEnumerable retrievedPkgs = null; + try + { + // GetMetadataAsync() API returns all versions for a specific non-wildcard package name + // For PSGallery GetMetadataAsync() API returns both Script and Module resources by checking only the Modules endpoint + retrievedPkgs = pkgMetadataResource.GetMetadataAsync( + packageId: pkgName, + includePrerelease: _prerelease, + includeUnlisted: false, + sourceCacheContext: sourceContext, + log: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + } + catch (HttpRequestException ex) + { + if ((String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || + String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) + { + _cmdletPassedIn.WriteDebug(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); + yield break; + } + } + catch (Exception e) + { + _cmdletPassedIn.WriteDebug(String.Format("Exception retrieving package {0} due to {1}.", pkgName, e.Message)); + } + + if (retrievedPkgs == null || retrievedPkgs.Count() == 0) + { + _cmdletPassedIn.WriteVerbose(string.Format("'{0}' could not be found in repository '{1}'", pkgName, repositoryName)); + yield break; + } + + foundPackagesMetadata.AddRange(retrievedPkgs.ToList()); + _pkgsLeftToFind.Remove(pkgName); + } + else + { + if (_isADOFeedRepository) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new ArgumentException(String.Format("Searching through ADOFeed with wildcard in Name is not supported, so {0} repository will be skipped.", repositoryName)), + "CannotSearchADOFeedWithWildcardName", + ErrorCategory.InvalidArgument, + this)); + yield break; + } + // case: searching for name containing wildcard i.e "Carbon.*" + 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, + filters: searchFilter, + skip: 0, + take: SearchAsyncMaxTake, + log: NullLogger.Instance, + cancellationToken: _cancellationToken).GetAwaiter().GetResult(); + if (wildcardPkgs.Count() > SearchAsyncMaxReturned) + { + // get the rest of the packages + wildcardPkgs = wildcardPkgs.Concat(pkgSearchResource.SearchAsync( + searchTerm: pkgName, + filters: searchFilter, + skip: SearchAsyncMaxTake, + take: GalleryMax, + log: NullLogger.Instance, + cancellationToken: _cancellationToken).GetAwaiter().GetResult()); + } + } + catch (HttpRequestException ex) + { + if ((String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || + String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) + { + _cmdletPassedIn.WriteDebug(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); + yield break; + } + } + catch (Exception e) + { + _cmdletPassedIn.WriteDebug(String.Format("Exception retrieving package {0} due to {1}.", pkgName, e.Message)); + } + + // filter additionally because NuGet wildcard search API returns more than we need + // perhaps validate in Find-PSResource, and use debugassert here? + WildcardPattern nameWildcardPattern = new WildcardPattern(pkgName, WildcardOptions.IgnoreCase); + 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) + { + _pkgsLeftToFind.Remove(pkgName); + } + } + + if (foundPackagesMetadata.Count == 0) + { + // no need to attempt to filter further + _cmdletPassedIn.WriteVerbose("no packages found"); + yield break; + } + + // filter by param: Version + if (_version == null) + { + // return latest version for each package + foundPackagesMetadata = foundPackagesMetadata.GroupBy( + p => p.Identity.Id, StringComparer.InvariantCultureIgnoreCase).Select( + x => x.OrderByDescending( + p => p.Identity.Version, VersionComparer.VersionRelease).FirstOrDefault()).ToList(); + } + else + { + if (!Utils.TryParseVersionOrVersionRange(_version, out VersionRange versionRange)) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new ArgumentException("Argument for -Version parameter is not in the proper format"), + "IncorrectVersionFormat", + ErrorCategory.InvalidArgument, + this)); + yield break; + } + + // at this point, version should be parsed successfully, into allVersions (null or "*") or versionRange (specific or range) + if (pkgName.Contains("*")) + { + // -Name containing wc with Version "*", or specific range + // at this point foundPackagesMetadata contains latest version for each package, get list of distinct + // package names and get all versions for each name, this is due to the SearchAsync and GetMetadataAsync() API restrictions ! + List allPkgsAllVersions = new List(); + foreach (string n in foundPackagesMetadata.Select(p => p.Identity.Id).Distinct(StringComparer.InvariantCultureIgnoreCase)) + { + // get all versions for this package + allPkgsAllVersions.AddRange(pkgMetadataResource.GetMetadataAsync(n, _prerelease, false, sourceContext, NullLogger.Instance, _cancellationToken).GetAwaiter().GetResult().ToList()); + } + + foundPackagesMetadata = allPkgsAllVersions; + if (versionRange == VersionRange.All) // Version = "*" + { + foundPackagesMetadata = foundPackagesMetadata.GroupBy( + p => p.Identity.Id, StringComparer.InvariantCultureIgnoreCase).SelectMany( + x => x.OrderByDescending( + p => p.Identity.Version, VersionComparer.VersionRelease)).ToList(); + } + else // Version range + { + foundPackagesMetadata = foundPackagesMetadata.Where( + p => versionRange.Satisfies(p.Identity.Version)).GroupBy( + p => p.Identity.Id, StringComparer.InvariantCultureIgnoreCase).SelectMany( + x => x.OrderByDescending( + p => p.Identity.Version, VersionComparer.VersionRelease)).ToList(); + } + } + else // name doesn't contain wildcards + { + // for non wildcard names, NuGet GetMetadataAsync() API is which returns all versions for that package ordered descendingly + if (versionRange != VersionRange.All) // Version range + { + foundPackagesMetadata = foundPackagesMetadata.Where( + p => versionRange.Satisfies( + p.Identity.Version, VersionComparer.VersionRelease)).OrderByDescending( + p => p.Identity.Version).ToList(); + } + } + } + + foreach (IPackageSearchMetadata pkg in foundPackagesMetadata) + { + if (!PSResourceInfo.TryConvert( + metadataToParse: pkg, + psGetInfo: out PSResourceInfo currentPkg, + repositoryName: repositoryName, + type: _type, + errorMsg: out string errorMsg)) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new PSInvalidOperationException("Error parsing IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), + "IPackageSearchMetadataToPSResourceInfoParsingError", + ErrorCategory.InvalidResult, + this)); + yield break; + } + + if (_type != ResourceType.None) + { + if (_type == ResourceType.Command && !currentPkg.Type.HasFlag(ResourceType.Command)) + { + continue; + } + if (_type == ResourceType.DscResource && !currentPkg.Type.HasFlag(ResourceType.DscResource)) + { + continue; + } + } + + // Only going to go in here for the main package, resolve Type and Tag requirements if any, and then find dependencies + if (_tag == null || (_tag != null && IsTagMatch(currentPkg))) + { + yield return currentPkg; + + if (_includeDependencies) + { + foreach (PSResourceInfo pkgDep in FindDependencyPackages(currentPkg, pkgMetadataResource, sourceContext)) + { + yield return pkgDep; + } + } + } + } + } + + private bool IsTagMatch(PSResourceInfo pkg) + { + return _tag.Intersect(pkg.Tags, StringComparer.InvariantCultureIgnoreCase).ToList().Count > 0; + } + + private List FindDependencyPackages( + PSResourceInfo currentPkg, + PackageMetadataResource packageMetadataResource, + SourceCacheContext sourceCacheContext + ) + { + List thoseToAdd = new List(); + FindDependencyPackagesHelper(currentPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); + return thoseToAdd; + } + + private void FindDependencyPackagesHelper( + PSResourceInfo currentPkg, + List thoseToAdd, + PackageMetadataResource packageMetadataResource, + SourceCacheContext sourceCacheContext + ) + { + foreach(var dep in currentPkg.Dependencies) + { + IEnumerable depPkgs = packageMetadataResource.GetMetadataAsync( + packageId: dep.Name, + includePrerelease: _prerelease, + includeUnlisted: false, + sourceCacheContext: sourceCacheContext, + log: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + + if (depPkgs.Count() > 0) + { + if (dep.VersionRange == VersionRange.All) + { + // return latest version + IPackageSearchMetadata depPkgLatestVersion = depPkgs.First(); + + if (!PSResourceInfo.TryConvert( + metadataToParse: depPkgLatestVersion, + psGetInfo: out PSResourceInfo depPSResourceInfoPkg, + repositoryName: currentPkg.Repository, + type: currentPkg.Type, + errorMsg: out string errorMsg)) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new PSInvalidOperationException("Error parsing dependency IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), + "DependencyIPackageSearchMetadataToPSResourceInfoParsingError", + ErrorCategory.InvalidResult, + this)); + } + + thoseToAdd.Add(depPSResourceInfoPkg); + FindDependencyPackagesHelper(depPSResourceInfoPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); + } + else + { + List pkgVersionsInRange = depPkgs.Where( + p => dep.VersionRange.Satisfies( + p.Identity.Version, VersionComparer.VersionRelease)).OrderByDescending( + p => p.Identity.Version).ToList(); + + if (pkgVersionsInRange.Count() > 0) + { + IPackageSearchMetadata depPkgLatestInRange = pkgVersionsInRange.First(); + if (depPkgLatestInRange != null) + { + if (!PSResourceInfo.TryConvert( + metadataToParse: depPkgLatestInRange, + psGetInfo: out PSResourceInfo depPSResourceInfoPkg, + repositoryName: currentPkg.Repository, + type: currentPkg.Type, + errorMsg: out string errorMsg)) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new PSInvalidOperationException("Error parsing dependency range IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), + "DependencyRangeIPackageSearchMetadataToPSResourceInfoParsingError", + ErrorCategory.InvalidResult, + this)); + } + + thoseToAdd.Add(depPSResourceInfoPkg); + FindDependencyPackagesHelper(depPSResourceInfoPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs new file mode 100644 index 000000000..a44a5624c --- /dev/null +++ b/src/code/FindPSResource.cs @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.Linq; +using System.Management.Automation; +using System.Threading; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Find-PSResource cmdlet combines the Find-Module, Find-Script, Find-DscResource, Find-Command cmdlets from V2. + /// It performs a search on a repository (local or remote) based on the -Name parameter argument. + /// It returns PSResourceInfo objects which describe each resource item found. + /// Other parameters allow the returned results to be filtered by item Type and Tag. + /// + + [Cmdlet(VerbsCommon.Find, + "PSResource", + DefaultParameterSetName = ResourceNameParameterSet, + SupportsShouldProcess = true, + HelpUri = "")] + [OutputType(typeof(PSResourceInfo))] + public sealed + class FindPSResource : PSCmdlet + { + #region Members + private const string ResourceNameParameterSet = "ResourceNameParameterSet"; + private const string CommandNameParameterSet = "CommandNameParameterSet"; + private const string DscResourceNameParameterSet = "DscResourceNameParameterSet"; + private const string TagParameterSet = "TagParameterSet"; + private const string TypeParameterSet = "TypeParameterSet"; + private CancellationTokenSource _source; + private CancellationToken _cancellationToken; + + #endregion + + #region Parameters + + /// + /// Specifies name of a resource or resources to find. Accepts wild card characters. + /// + [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ResourceNameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies one or more resource types to find. + /// Resource types supported are: Module, Script, Command, DscResource + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(Mandatory = true, ParameterSetName = TypeParameterSet)] + public ResourceType Type { get; set; } + + /// + /// Specifies the version of the resource to be found and returned. + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// When specified, includes prerelease versions in search. + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies a module resource package name type to search for. Wildcards are supported. + /// + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [ValidateNotNullOrEmpty] + public string ModuleName { get; set; } + + /// + /// Specifies a list of command names that searched module packages will provide. Wildcards are supported. + /// + [Parameter(ParameterSetName = CommandNameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] CommandName { get; set; } + + /// + /// Specifies a list of dsc resource names that searched module packages will provide. Wildcards are supported. + /// + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] DscResourceName { get; set; } + + /// + /// Filters search results for resources that include one or more of the specified tags. + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [Parameter(Mandatory = true, ParameterSetName = TagParameterSet)] + [ValidateNotNull] + public string[] Tag { get; set; } + + /// + /// Specifies one or more repository names to search. If not specified, search will include all currently registered repositories. + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies optional credentials to be used when accessing a repository. + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + public PSCredential Credential { get; set; } + + /// + /// When specified, search will return all matched resources along with any resources the matched resources depends on. + /// + [Parameter(ParameterSetName = ResourceNameParameterSet)] + [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(ParameterSetName = DscResourceNameParameterSet)] + public SwitchParameter IncludeDependencies { get; set; } + + #endregion + + #region Methods + + protected override void BeginProcessing() + { + _source = new CancellationTokenSource(); + _cancellationToken = _source.Token; + } + + protected override void StopProcessing() + { + _source.Cancel(); + } + + protected override void ProcessRecord() + { + Name = Utils.FilterOutWildcardNames(Name, out string[] errorMsgs); + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + if (Name.Length == 0) + { + return; + } + + switch (ParameterSetName) + { + case ResourceNameParameterSet: + FindHelper findHelper = new FindHelper(_cancellationToken, this); + List foundPackages = new List(); + + foreach (PSResourceInfo package in findHelper.FindByResourceName(Name, Type, Version, Prerelease, Tag, Repository, Credential, IncludeDependencies)) + { + foundPackages.Add(package); + } + + foreach (var uniquePackageVersion in foundPackages.GroupBy( + m => new {m.Name, m.Version}).Select( + group => group.First()).ToList()) + { + WriteObject(uniquePackageVersion); + } + + break; + + case CommandNameParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("CommandNameParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "CommandParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + case DscResourceNameParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("DscResourceNameParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "DscResourceParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + case TagParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("DscResourceNameParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "TagParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + case TypeParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("TypeParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "TypeParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + } + + #endregion + } +} diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index e50264066..286627d73 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -1,418 +1,845 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Management.Automation; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - #region Enums - - public enum ResourceType - { - Module, - Script - } - - public enum VersionType - { - Unknown, - MinimumVersion, - RequiredVersion, - MaximumVersion - } - - #endregion - - #region VersionInfo - - public sealed class VersionInfo - { - public VersionInfo( - VersionType versionType, - Version versionNum) - { - VersionType = versionType; - VersionNum = versionNum; - } - - public VersionType VersionType { get; } - public Version VersionNum { get; } - - public override string ToString() => $"{VersionType}: {VersionNum}"; - } - - #endregion - - #region ResourceIncludes - - public sealed class ResourceIncludes - { - #region Properties - - public string[] Cmdlet { get; } - - public string[] Command { get; } - - public string[] DscResource { get; } - - public string[] Function { get; } - - public string[] RoleCapability { get; } - - public string[] Workflow { get; } - - #endregion - - #region Constructor - - /// - /// Constructor - /// - /// Provided hashtable has form: - /// Key: Cmdlet - /// Value: ArrayList of Cmdlet name strings - /// Key: Command - /// Value: ArrayList of Command name strings - /// Key: DscResource - /// Value: ArrayList of DscResource name strings - /// Key: Function - /// Value: ArrayList of Function name strings - /// Key: RoleCapability (deprecated for PSGetV3) - /// Value: ArrayList of RoleCapability name strings - /// Key: Workflow (deprecated for PSGetV3) - /// Value: ArrayList of Workflow name strings - /// - /// Hashtable of PSGet includes - public ResourceIncludes(Hashtable includes) - { - if (includes == null) { return; } - - Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); - Command = GetHashTableItem(includes, nameof(Command)); - DscResource = GetHashTableItem(includes, nameof(DscResource)); - Function = GetHashTableItem(includes, nameof(Function)); - RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); - Workflow = GetHashTableItem(includes, nameof(Workflow)); - } - - #endregion - - #region Public methods - - public Hashtable ConvertToHashtable() - { - var hashtable = new Hashtable - { - { nameof(Cmdlet), Cmdlet }, - { nameof(Command), Command }, - { nameof(DscResource), DscResource }, - { nameof(Function), Function }, - { nameof(RoleCapability), RoleCapability }, - { nameof(Workflow), Workflow } - }; - - return hashtable; - } - - #endregion - - #region Private methods - - private string[] GetHashTableItem( - Hashtable table, - string name) - { - if (table.ContainsKey(name) && - table[name] is PSObject psObjectItem) - { - return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); - } - - return null; - } - - #endregion - } - - #endregion - - #region PSResourceInfo - - public sealed class PSResourceInfo - { - #region Properties - - public Dictionary AdditionalMetadata { get; set; } - public string Author { get; set; } - public string CompanyName { get; set; } - public string Copyright { get; set; } - public string[] Dependencies { get; set; } - public string Description { get; set; } - public Uri IconUri { get; set; } - public ResourceIncludes Includes { get; set; } - public DateTime? InstalledDate { get; set; } - public string InstalledLocation { get; set; } - public bool IsPrerelease { get; set; } - public Uri LicenseUri { get; set; } - public string Name { get; set; } - public string PackageManagementProvider { get; set; } - public string PowerShellGetFormatVersion { get; set; } - public Uri ProjectUri { get; set; } - public DateTime? PublishedDate { get; set; } - public string ReleaseNotes { get; set; } - public string Repository { get; set; } - public string RepositorySourceLocation { get; set; } - public string[] Tags { get; set; } - public string Type { get; set; } - public DateTime? UpdatedDate { get; set; } - public Version Version { get; set; } - - #endregion - - #region Public static methods - - /// - /// Writes the PSGetResourceInfo properties to the specified file path as a - /// PowerShell serialized xml file, maintaining compatibility with - /// PowerShellGet v2 file format. - /// - public bool TryWrite( - string filePath, - out string errorMsg) - { - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - var infoXml = PSSerializer.Serialize( - source: ConvertToCustomObject(), - depth: 5); - - System.IO.File.WriteAllText( - path: filePath, - contents: infoXml); - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", - ex.Message); - - return false; - } - } - - /// - /// Reads a PSGet resource xml (PowerShell serialized) file and returns - /// a PSGetResourceInfo object containing the file contents. - /// - public static bool TryRead( - string filePath, - out PSResourceInfo psGetInfo, - out string errorMsg) - { - psGetInfo = null; - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - // Read and deserialize information xml file. - var psObjectInfo = (PSObject) PSSerializer.Deserialize( - System.IO.File.ReadAllText( - filePath)); - - psGetInfo = new PSResourceInfo - { - AdditionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo), - Author = GetProperty(nameof(PSResourceInfo.Author), psObjectInfo), - CompanyName = GetProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), - Copyright = GetProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), - Dependencies = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), - Description = GetProperty(nameof(PSResourceInfo.Description), psObjectInfo), - IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), - Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), - InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), - InstalledLocation = GetProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), - IsPrerelease = GetProperty(nameof(PSResourceInfo.IsPrerelease), psObjectInfo), - LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), - Name = GetProperty(nameof(PSResourceInfo.Name), psObjectInfo), - PackageManagementProvider = GetProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), - PowerShellGetFormatVersion = GetProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), - ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), - PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), - ReleaseNotes = GetProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), - Repository = GetProperty(nameof(PSResourceInfo.Repository), psObjectInfo), - RepositorySourceLocation = GetProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), - Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), - Type = GetProperty(nameof(PSResourceInfo.Type), psObjectInfo), - UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), - Version = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo) - }; - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", - ex.Message); - - return false; - } - } - - #endregion - - #region Private static methods - - private static T ConvertToType(PSObject psObject) - { - // We only convert Dictionary types. - if (typeof(T) != typeof(Dictionary)) - { - return default(T); - } - - var dict = new Dictionary(); - foreach (var prop in psObject.Properties) - { - dict.Add(prop.Name, prop.Value.ToString()); - } - - return (T)Convert.ChangeType(dict, typeof(T)); - } - - private static T GetProperty( - string Name, - PSObject psObjectInfo) - { - var val = psObjectInfo.Properties[Name]?.Value; - if (val == null) - { - return default(T); - } - - switch (val) - { - case T valType: - return valType; - - case PSObject valPSObject: - switch (valPSObject.BaseObject) - { - case T valBase: - return valBase; - - case PSCustomObject _: - // A base object of PSCustomObject means this is additional metadata - // and type T should be Dictionary. - return ConvertToType(valPSObject); - - default: - return default(T); - } - - default: - return default(T); - } - } - - #endregion - - #region Private methods - - private PSObject ConvertToCustomObject() - { - var additionalMetadata = new PSObject(); - foreach (var item in AdditionalMetadata) - { - additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); - } - - var psObject = new PSObject(); - psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); - psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); - psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); - psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); - psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); - psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); - psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); - psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); - psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); - psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); - psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); - psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); - psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); - psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(Version), Version)); - - return psObject; - } - - #endregion - } - - #endregion - - #region Test Hooks - - public static class TestHooks - { - public static PSObject ReadPSGetResourceInfo(string filePath) - { - if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - return PSObject.AsPSObject(psGetInfo); - } - - throw new PSInvalidOperationException(errorMsg); - } - - public static void WritePSGetResourceInfo( - string filePath, - PSObject psObjectGetInfo) - { - if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) - { - if (! psGetInfo.TryWrite(filePath, out string errorMsg)) - { - throw new PSInvalidOperationException(errorMsg); - } - - return; - } - - throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); - } - } - - #endregion -} +using System.Text.RegularExpressions; +using System.Linq; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.Globalization; +using System.Management.Automation; +using NuGet.Packaging; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + #region Enums + + [Flags] + public enum ResourceType + { + // 00001 -> M + // 00100 -> C + // 00101 -> M, C + None = 0x0, + Module = 0x1, + Script = 0x2, + Command = 0x4, + DscResource = 0x8 + } + + public enum VersionType + { + Unknown, + MinimumVersion, + RequiredVersion, + MaximumVersion + } + + #endregion + + #region VersionInfo + + public sealed class VersionInfo + { + public VersionInfo( + VersionType versionType, + Version versionNum) + { + VersionType = versionType; + VersionNum = versionNum; + } + + public VersionType VersionType { get; } + public Version VersionNum { get; } + + public override string ToString() => $"{VersionType}: {VersionNum}"; + } + + #endregion + + #region ResourceIncludes + + public sealed class ResourceIncludes + { + #region Properties + + public string[] Cmdlet { get; } + + public string[] Command { get; } + + public string[] DscResource { get; } + + public string[] Function { get; } + + public string[] RoleCapability { get; } + + public string[] Workflow { get; } + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// Provided hashtable has form: + /// Key: Cmdlet + /// Value: ArrayList of Cmdlet name strings + /// Key: Command + /// Value: ArrayList of Command name strings + /// Key: DscResource + /// Value: ArrayList of DscResource name strings + /// Key: Function + /// Value: ArrayList of Function name strings + /// Key: RoleCapability (deprecated for PSGetV3) + /// Value: ArrayList of RoleCapability name strings + /// Key: Workflow (deprecated for PSGetV3) + /// Value: ArrayList of Workflow name strings + /// + /// Hashtable of PSGet includes + public ResourceIncludes(Hashtable includes) + { + if (includes == null) { return; } + + Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); + Command = GetHashTableItem(includes, nameof(Command)); + DscResource = GetHashTableItem(includes, nameof(DscResource)); + Function = GetHashTableItem(includes, nameof(Function)); + RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); + Workflow = GetHashTableItem(includes, nameof(Workflow)); + } + + #endregion + + #region Public methods + + public Hashtable ConvertToHashtable() + { + var hashtable = new Hashtable + { + { nameof(Cmdlet), Cmdlet }, + { nameof(Command), Command }, + { nameof(DscResource), DscResource }, + { nameof(Function), Function }, + { nameof(RoleCapability), RoleCapability }, + { nameof(Workflow), Workflow } + }; + + return hashtable; + } + + #endregion + + #region Private methods + + private string[] GetHashTableItem( + Hashtable table, + string name) + { + if (table.ContainsKey(name) && + table[name] is PSObject psObjectItem) + { + return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); + } + + return null; + } + + #endregion + } + + #endregion + + + #region Dependency + + public sealed class Dependency + { + #region Properties + + public string Name { get; } + + public VersionRange VersionRange { get; } + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// + /// Hashtable of PSGet includes + public Dependency(string dependencyName, VersionRange dependencyVersionRange) + { + Name = dependencyName; + VersionRange = dependencyVersionRange; + } + + #endregion + } + + #endregion + + #region PSResourceInfo + + public sealed class PSResourceInfo + { + #region Properties + + public Dictionary AdditionalMetadata { get; set; } + public string Author { get; set; } + public string CompanyName { get; set; } + public string Copyright { get; set; } + public Dependency[] Dependencies { get; set; } + public string Description { get; set; } + public Uri IconUri { get; set; } + public ResourceIncludes Includes { get; set; } + public DateTime? InstalledDate { get; set; } + public string InstalledLocation { get; set; } + public bool IsPrerelease { get; set; } + public Uri LicenseUri { get; set; } + public string Name { get; set; } + public string PackageManagementProvider { get; set; } + public string PowerShellGetFormatVersion { get; set; } + public string PrereleaseLabel { get; set; } + public Uri ProjectUri { get; set; } + public DateTime? PublishedDate { get; set; } + public string ReleaseNotes { get; set; } + public string Repository { get; set; } + public string RepositorySourceLocation { get; set; } + public string[] Tags { get; set; } + public ResourceType Type { get; set; } + public DateTime? UpdatedDate { get; set; } + public Version Version { get; set; } + + #endregion + + #region Private fields + private static readonly char[] Delimeter = {' ', ','}; + + #endregion + + #region Public static methods + + /// + /// Writes the PSGetResourceInfo properties to the specified file path as a + /// PowerShell serialized xml file, maintaining compatibility with + /// PowerShellGet v2 file format. + /// + public bool TryWrite( + string filePath, + out string errorMsg) + { + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + var infoXml = PSSerializer.Serialize( + source: ConvertToCustomObject(), + depth: 5); + + System.IO.File.WriteAllText( + path: filePath, + contents: infoXml); + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", + ex.Message); + + return false; + } + } + + /// + /// Reads a PSGet resource xml (PowerShell serialized) file and returns + /// a PSResourceInfo object containing the file contents. + /// + public static bool TryRead( + string filePath, + out PSResourceInfo psGetInfo, + out string errorMsg) + { + psGetInfo = null; + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + // Read and deserialize information xml file. + var psObjectInfo = (PSObject) PSSerializer.Deserialize( + System.IO.File.ReadAllText( + filePath)); + + + var additionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo); + Version version = GetVersionInfo(psObjectInfo, additionalMetadata, out string prereleaseLabel); + + psGetInfo = new PSResourceInfo + { + AdditionalMetadata = additionalMetadata, + Author = GetProperty(nameof(PSResourceInfo.Author), psObjectInfo), + CompanyName = GetProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), + Copyright = GetProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), + Dependencies = GetDependencies(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), + Description = GetProperty(nameof(PSResourceInfo.Description), psObjectInfo), + IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), + Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), + InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), + InstalledLocation = GetProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), + IsPrerelease = GetProperty(nameof(PSResourceInfo.IsPrerelease), psObjectInfo), + LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), + Name = GetProperty(nameof(PSResourceInfo.Name), psObjectInfo), + PackageManagementProvider = GetProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), + PowerShellGetFormatVersion = GetProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), + PrereleaseLabel = prereleaseLabel, + ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), + PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), + ReleaseNotes = GetProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), + Repository = GetProperty(nameof(PSResourceInfo.Repository), psObjectInfo), + RepositorySourceLocation = GetProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), + Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), + // try to get the value of PSResourceInfo.Type property, if the value is null use ResourceType.Module as value + // this value will be used in Enum.TryParse. If Enum.TryParse returns false, use ResourceType.Module to set Type instead. + Type = Enum.TryParse( + GetProperty(nameof(PSResourceInfo.Type), psObjectInfo) ?? nameof(ResourceType.Module), + out ResourceType currentReadType) + ? currentReadType : ResourceType.Module, + UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), + Version = version + }; + + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", + ex.Message); + + return false; + } + } + + private static Version GetVersionInfo( + PSObject psObjectInfo, + Dictionary additionalMetadata, + out string prereleaseLabel) + { + string versionString = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); + prereleaseLabel = String.Empty; + + if (!String.IsNullOrEmpty(versionString) || + additionalMetadata.TryGetValue("NormalizedVersion", out versionString)) + { + string pkgVersion = versionString; + if (versionString.Contains("-")) + { + string[] versionStringParsed = versionString.Split('-'); + if (versionStringParsed.Length == 1) + { + pkgVersion = versionStringParsed[0]; + } + else + { + // versionStringParsed.Length > 1 (because string contained '-' so couldn't be 0) + pkgVersion = versionStringParsed[0]; + prereleaseLabel = versionStringParsed[1]; + } + } + + if (!Version.TryParse(pkgVersion, out Version parsedVersion)) + { + prereleaseLabel = String.Empty; + return null; + } + else + { + return parsedVersion; + } + } + + prereleaseLabel = String.Empty; + return GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); + } + + + public static bool TryConvert( + IPackageSearchMetadata metadataToParse, + out PSResourceInfo psGetInfo, + string repositoryName, + ResourceType? type, + out string errorMsg) + { + psGetInfo = null; + errorMsg = String.Empty; + + if (metadataToParse == null) + { + errorMsg = "TryConvertPSResourceInfo: Invalid IPackageSearchMetadata object. Object cannot be null."; + return false; + } + + try + { + psGetInfo = new PSResourceInfo + { + // not all of the properties of PSResourceInfo are filled as they are not there in metadata returned for Find-PSResource. + Author = ParseMetadataAuthor(metadataToParse), + Dependencies = ParseMetadataDependencies(metadataToParse), + Description = ParseMetadataDescription(metadataToParse), + IconUri = ParseMetadataIconUri(metadataToParse), + LicenseUri = ParseMetadataLicenseUri(metadataToParse), + Name = ParseMetadataName(metadataToParse), + PrereleaseLabel = ParsePrerelease(metadataToParse), + ProjectUri = ParseMetadataProjectUri(metadataToParse), + PublishedDate = ParseMetadataPublishedDate(metadataToParse), + Repository = repositoryName, + Tags = ParseMetadataTags(metadataToParse), + Type = ParseMetadataType(metadataToParse, repositoryName, type), + Version = ParseMetadataVersion(metadataToParse) + }; + + return true; + } + catch (Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot parse PSResourceInfo from IPackageSearchMetadata with error: {0}", + ex.Message); + return false; + } + } + + #endregion + + #region Private static methods + + private static T ConvertToType(PSObject psObject) + { + // We only convert Dictionary types. + if (typeof(T) != typeof(Dictionary)) + { + return default(T); + } + + var dict = new Dictionary(); + foreach (var prop in psObject.Properties) + { + dict.Add(prop.Name, prop.Value.ToString()); + } + + return (T)Convert.ChangeType(dict, typeof(T)); + } + + private static T GetProperty( + string Name, + PSObject psObjectInfo) + { + var val = psObjectInfo.Properties[Name]?.Value; + if (val == null) + { + return default(T); + } + + switch (val) + { + case T valType: + return valType; + + case PSObject valPSObject: + switch (valPSObject.BaseObject) + { + case T valBase: + return valBase; + + case PSCustomObject _: + // A base object of PSCustomObject means this is additional metadata + // and type T should be Dictionary. + return ConvertToType(valPSObject); + + default: + return default(T); + } + + default: + return default(T); + } + } + + private static string GetPrereleaseLabel(Version version) + { + string versionAsString = version.ToString(); + + if (!versionAsString.Contains("-")) + { + // no prerelease label present + return String.Empty; + } + + string[] prereleaseParsed = versionAsString.Split('-'); + if (prereleaseParsed.Length <= 1) + { + return String.Empty; + } + + string prereleaseString = prereleaseParsed[1]; + Regex prereleasePattern = new Regex("^[a-zA-Z0-9]+$"); + if (!prereleasePattern.IsMatch(prereleaseString)) + { + return String.Empty; + } + + return prereleaseString; + } + + private static Dependency[] GetDependencies(ArrayList dependencyInfos) + { + List dependenciesFound = new List(); + if (dependencyInfos == null) { return dependenciesFound.ToArray(); } + + + foreach(PSObject dependencyObj in dependencyInfos) + { + if (!(dependencyObj.BaseObject is Hashtable dependencyInfo)) + { + Dbg.Assert(false, "Dependencies BaseObject must be a Hashtable"); + continue; + } + + if (!dependencyInfo.ContainsKey("Name")) + { + Dbg.Assert(false, "Derived dependencies Hashtable must contain a Name key"); + continue; + } + + string dependencyName = (string) dependencyInfo["Name"]; + if (String.IsNullOrEmpty(dependencyName)) + { + Dbg.Assert(false, "Dependency Name must not be null or empty"); + continue; + } + + if (dependencyInfo.ContainsKey("RequiredVersion")) + { + if (!Utils.TryParseVersionOrVersionRange((string) dependencyInfo["RequiredVersion"], out VersionRange dependencyVersion)) + { + dependencyVersion = VersionRange.All; + } + + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersion)); + continue; + } + + if (dependencyInfo.ContainsKey("MinimumVersion") || dependencyInfo.ContainsKey("MaximumVersion")) + { + NuGetVersion minimumVersion = null; + NuGetVersion maximumVersion = null; + bool includeMin = false; + bool includeMax = false; + + if (dependencyInfo.ContainsKey("MinimumVersion") && + !NuGetVersion.TryParse((string) dependencyInfo["MinimumVersion"], out minimumVersion)) + { + VersionRange dependencyAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + continue; + } + + if (dependencyInfo.ContainsKey("MaximumVersion") && + !NuGetVersion.TryParse((string) dependencyInfo["MaximumVersion"], out maximumVersion)) + { + VersionRange dependencyAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + continue; + } + + if (minimumVersion != null) + { + includeMin = true; + } + + if (maximumVersion != null) + { + includeMax = true; + } + + VersionRange dependencyVersionRange = new VersionRange( + minVersion: minimumVersion, + includeMinVersion: includeMin, + maxVersion: maximumVersion, + includeMaxVersion: includeMax); + + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRange)); + continue; + } + + // neither Required, Minimum or Maximum Version provided + VersionRange dependencyVersionRangeAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRangeAll)); + } + + return dependenciesFound.ToArray(); + } + + private static string ConcatenateVersionWithPrerelease(string version, string prerelease) + { + // if no prerelease, just version suffices + if (String.IsNullOrEmpty(prerelease)) + { + return version; + } + + int numVersionDigits = version.Split('.').Count(); + if (numVersionDigits == 3) + { + // 0.5.3 -> version string , preview4 -> prerelease string , return: 5.3.0-preview4 + return version + "-" + prerelease; + } + + + // number of digits not equivalent to 3 was not supported in V2 + return version; + } + + + #region Parse Metadata private static methods + + private static string ParseMetadataAuthor(IPackageSearchMetadata pkg) + { + return pkg.Authors; + } + + private static Dependency[] ParseMetadataDependencies(IPackageSearchMetadata pkg) + { + List dependencies = new List(); + foreach(var pkgDependencyGroup in pkg.DependencySets) + { + foreach(var pkgDependencyItem in pkgDependencyGroup.Packages) + { + // check if version range is not null. In case we have package with dependency but no version specified + VersionRange depVersionRange; + if (pkgDependencyItem.VersionRange == null) + { + depVersionRange = VersionRange.All; + } + else + { + depVersionRange = pkgDependencyItem.VersionRange; + } + + Dependency currentDependency = new Dependency(pkgDependencyItem.Id, depVersionRange); + dependencies.Add(currentDependency); + } + } + return dependencies.ToArray(); + } + + private static string ParseMetadataDescription(IPackageSearchMetadata pkg) + { + return pkg.Description; + } + + private static Uri ParseMetadataIconUri(IPackageSearchMetadata pkg) + { + return pkg.IconUrl; + } + + private static Uri ParseMetadataLicenseUri(IPackageSearchMetadata pkg) + { + return pkg.LicenseUrl; + } + + private static string ParseMetadataName(IPackageSearchMetadata pkg) + { + return pkg.Identity?.Id ?? string.Empty; + } + + private static string ParsePrerelease(IPackageSearchMetadata pkg) + { + return pkg.Identity.Version.ReleaseLabels.Count() == 0 ? + String.Empty : + pkg.Identity.Version.ReleaseLabels.FirstOrDefault(); + } + + private static Uri ParseMetadataProjectUri(IPackageSearchMetadata pkg) + { + return pkg.ProjectUrl; + } + + private static DateTime? ParseMetadataPublishedDate(IPackageSearchMetadata pkg) + { + DateTime? publishDate = null; + DateTimeOffset? pkgPublishedDate = pkg.Published; + if (pkgPublishedDate.HasValue) + { + publishDate = pkgPublishedDate.Value.DateTime; + } + return publishDate; + } + + private static string[] ParseMetadataTags(IPackageSearchMetadata pkg) + { + return pkg.Tags.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + } + + private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, string repoName, ResourceType? pkgType) + { + // possible type combinations: + // M, C + // M, D + // M + // S + + string[] tags = ParseMetadataTags(pkg); + ResourceType currentPkgType = ResourceType.Module; + + // Check if package came from PSGalleryScripts repo- this indicates that it should have a PSScript tag + // (however some packages that had a wildcard in their name are missing PSScript or PSModule tags) + // but we were able to get the packages by using SearchAsync() with the appropriate Script or Module repository endpoint + // and can check repository endpoint to determine Type. + // Module packages missing tags are accounted for as the default case, and we account for scripts with the following check: + if ((pkgType == null && String.Equals("PSGalleryScripts", repoName, StringComparison.InvariantCultureIgnoreCase)) || + (pkgType != null && pkgType == ResourceType.Script)) + { + // it's a Script resource, so clear default Module tag because a Script resource cannot also be a Module resource + currentPkgType &= ~ResourceType.Module; + currentPkgType |= ResourceType.Script; + } + + // if Name contains wildcard, currently Script and Module tags should be set properly, but need to account for Command and DscResource types too + // if Name does not contain wildcard, GetMetadataAsync() was used, PSGallery only is searched (and pkg will successfully be found + // and returned from there) before PSGalleryScripts can be searched + foreach(string tag in tags) + { + if(String.Equals(tag, "PSScript", StringComparison.InvariantCultureIgnoreCase)) + { + // clear default Module tag, because a Script resource cannot be a Module resource also + currentPkgType &= ~ResourceType.Module; + currentPkgType |= ResourceType.Script; + } + if (tag.StartsWith("PSCommand_")) + { + currentPkgType |= ResourceType.Command; + } + if (String.Equals(tag, "PSIncludes_DscResource", StringComparison.InvariantCultureIgnoreCase)) + { + currentPkgType |= ResourceType.DscResource; + } + } + return currentPkgType; + } + + private static Version ParseMetadataVersion(IPackageSearchMetadata pkg) + { + if (pkg.Identity != null) + { + return pkg.Identity.Version.Version; + } + return null; + } + + #endregion + + #endregion + + + #region Private methods + + private PSObject ConvertToCustomObject() + { + var additionalMetadata = new PSObject(); + foreach (var item in AdditionalMetadata) + { + additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); + } + + var psObject = new PSObject(); + psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); + psObject.Properties.Add(new PSNoteProperty(nameof(Version), ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel))); + psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); + psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); + psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); + psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); + psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); + psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); + psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); + psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); + psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); + psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); + psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); + psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); + psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); + + return psObject; + } + + #endregion + } + + #endregion + + #region Test Hooks + + public static class TestHooks + { + public static PSObject ReadPSGetResourceInfo(string filePath) + { + if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + return PSObject.AsPSObject(psGetInfo); + } + + throw new PSInvalidOperationException(errorMsg); + } + + public static void WritePSGetResourceInfo( + string filePath, + PSObject psObjectGetInfo) + { + if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) + { + if (! psGetInfo.TryWrite(filePath, out string errorMsg)) + { + throw new PSInvalidOperationException(errorMsg); + } + + return; + } + + throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); + } + } + + #endregion +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 2ef46c5de..5715958f5 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,187 +1,224 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Management.Automation; -using System.Collections; -using System.Management.Automation.Language; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using static System.Environment; -using System.IO; -using System.Linq; -using NuGet.Versioning; - - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - internal static class Utils - { - #region Public methods - - public static string GetInstalledPackageName(string pkgPath) - { - if (string.IsNullOrEmpty(pkgPath)) - { - return string.Empty; - } - - if (File.Exists(pkgPath)) - { - // ex: ./PowerShell/Scripts/TestScript.ps1 - return System.IO.Path.GetFileNameWithoutExtension(pkgPath); - } - else - { - // expecting the full version module path - // ex: ./PowerShell/Modules/TestModule/1.0.0 - return new DirectoryInfo(pkgPath).Parent.Name; - } - } - - public static string TrimQuotes(string name) - { - return name.Trim('\'', '"'); - } - - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) - { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } - } - - if (!quotesNeeded) - { - return name; - } - - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - public static bool TryParseVersionOrVersionRange(string Version, out VersionRange versionRange) - { - var successfullyParsed = false; - NuGetVersion nugetVersion = null; - versionRange = null; - - if (Version != null) - { - if (Version.Trim().Equals("*")) - { - successfullyParsed = true; - versionRange = VersionRange.All; - } - else - { - successfullyParsed = NuGetVersion.TryParse(Version, out nugetVersion); - if (successfullyParsed) - { - versionRange = new VersionRange(nugetVersion, true, nugetVersion, true, null, null); - - } - else - { - successfullyParsed = VersionRange.TryParse(Version, out versionRange); - } - } - } - return successfullyParsed; - } - - public static List GetAllResourcePaths(PSCmdlet psCmdlet) - { - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - List resourcePaths = psModulePath.Split(';').ToList(); - List pathsToSearch = new List(); - var PSVersion6 = new Version(6, 0); - var isCorePS = psCmdlet.Host.Version >= PSVersion6; - string myDocumentsPath; - string programFilesPath; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and MacOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); - programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); - } - - // will search first in PSModulePath, then will search in default paths - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); - - // resourcePaths should now contain, eg: - // ./PowerShell/Scripts - // ./PowerShell/Modules - // add all module directories or script files - foreach (string path in resourcePaths) - { - psCmdlet.WriteDebug(string.Format("Retrieving directories in the path '{0}'", path)); - - if (path.EndsWith("Scripts")) - { - try - { - pathsToSearch.AddRange(Directory.GetFiles(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); - } - } - else - { - try - { - pathsToSearch.AddRange(Directory.GetDirectories(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); - } - } - } - - // resourcePaths should now contain eg: - // ./PowerShell/Scripts/Test-Script.ps1 - // ./PowerShell/Modules/TestModule - // need to use .ToList() to cast the IEnumerable to type List - pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - pathsToSearch.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); - - return pathsToSearch; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i < list.Count; i++) - { - strArray[i] = list[i] as string; - } - - return strArray; - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using static System.Environment; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Runtime.InteropServices; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + internal static class Utils + { + public static string[] FilterOutWildcardNames( + string[] pkgNames, + out string[] errorMsgs) + { + List errorFreeNames = new List(); + List errorMsgList = new List(); + + foreach (string n in pkgNames) + { + bool isNameErrorProne = false; + if (WildcardPattern.ContainsWildcardCharacters(n)) + { + if (String.Equals(n, "*", StringComparison.InvariantCultureIgnoreCase)) + { + errorMsgList = new List(); // clear prior error messages + errorMsgList.Add("-Name '*' is not supported for Find-PSResource so all Name entries will be discarded."); + errorFreeNames = new List(); + break; + } + else if (n.Contains("?") || n.Contains("[")) + { + errorMsgList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for Find-PSResource so Name entry: {0} will be discarded.", n)); + isNameErrorProne = true; + } + } + + if (!isNameErrorProne) + { + errorFreeNames.Add(n); + } + } + + errorMsgs = errorMsgList.ToArray(); + return errorFreeNames.ToArray(); + } + + #region Public methods + + public static string TrimQuotes(string name) + { + return name.Trim('\'', '"'); + } + + public static string QuoteName(string name) + { + bool quotesNeeded = false; + foreach (var c in name) + { + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } + } + + if (!quotesNeeded) + { + return name; + } + + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) + { + strArray[i] = list[i] as string; + } + + return strArray; + } + + public static bool TryParseVersionOrVersionRange( + string version, + out VersionRange versionRange) + { + versionRange = null; + + if (version == null) { return false; } + + + if (version.Trim().Equals("*")) + { + versionRange = VersionRange.All; + return true; + } + + // parse as NuGetVersion + if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) + { + versionRange = new VersionRange( + minVersion: nugetVersion, + includeMinVersion: true, + maxVersion: nugetVersion, + includeMaxVersion: true, + floatRange: null, + originalString: null); + return true; + } + + // parse as Version range + return VersionRange.TryParse(version, out versionRange); + } + + public static string GetInstalledPackageName(string pkgPath) + { + if (string.IsNullOrEmpty(pkgPath)) + { + return string.Empty; + } + + if (File.Exists(pkgPath)) + { + // ex: ./PowerShell/Scripts/TestScript.ps1 + return System.IO.Path.GetFileNameWithoutExtension(pkgPath); + } + else + { + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; + } + } + + public static List GetAllResourcePaths(PSCmdlet psCmdlet) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + List resourcePaths = psModulePath.Split(';').ToList(); + List pathsToSearch = new List(); + var PSVersion6 = new Version(6, 0); + var isCorePS = psCmdlet.Host.Version >= PSVersion6; + string myDocumentsPath; + string programFilesPath; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; + + myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and MacOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); + programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); + } + + // will search first in PSModulePath, then will search in default paths + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); + + // resourcePaths should now contain, eg: + // ./PowerShell/Scripts + // ./PowerShell/Modules + // add all module directories or script files + foreach (string path in resourcePaths) + { + psCmdlet.WriteDebug(string.Format("Retrieving directories in the path '{0}'", path)); + + if (path.EndsWith("Scripts")) + { + try + { + pathsToSearch.AddRange(Directory.GetFiles(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); + } + } + else + { + try + { + pathsToSearch.AddRange(Directory.GetDirectories(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); + } + } + } + + // resourcePaths should now contain eg: + // ./PowerShell/Scripts/Test-Script.ps1 + // ./PowerShell/Modules/TestModule + // need to use .ToList() to cast the IEnumerable to type List + pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + pathsToSearch.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); + + return pathsToSearch; + } + + #endregion + } +} diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 new file mode 100644 index 000000000..fd24878e3 --- /dev/null +++ b/test/FindPSResource.Tests.ps1 @@ -0,0 +1,206 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Find-PSResource for Module' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + $NuGetGalleryName = Get-NuGetGalleryName + Get-NewPSResourceRepositoryFile + Register-LocalRepos + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "find Specific Module Resource by Name" { + $specItem = Find-PSResource -Name "Carbon" + $specItem.Name | Should -Be "Carbon" + } + + It "should not find resource given nonexistant name" { + $res = Find-PSResource -Name NonExistantModule + $res | Should -BeNullOrEmpty + } + + It "find resources when Name contains * from V2 endpoint repository (PowerShellGallery))" { + $foundScript = $False + $res = Find-PSResource -Name "AzureS*" -Repository $PSGalleryName + $res.Count | Should -BeGreaterThan 1 + # should find Module and Script resources + foreach ($item in $res) { + if ($item.Type -eq "Script") + { + $foundScript = $true + } + } + + $foundScript | Should -BeTrue + } + + It "find resource given Name from V3 endpoint repository (NuGetGallery)" { + $res = Find-PSResource -Name "Serilog" -Repository $NuGetGalleryName + $res.Count | Should -Be 1 + $res.Name | Should -Be "Serilog" + $res.Repository | Should -Be $NuGetGalleryName + } + + It "find resources when Name contains wildcard * from V3 endpoint repository" { + $res = Find-PSResource -Name "Serilog*" -Repository $NuGetGalleryName + $res.Count | Should -BeGreaterThan 1 + } + + $testCases2 = @{Version="[2.10.0.0]"; ExpectedVersions=@("2.10.0.0"); Reason="validate version, exact match"}, + @{Version="2.10.0.0"; ExpectedVersions=@("2.10.0.0"); Reason="validate version, exact match without bracket syntax"}, + @{Version="[2.5.0.0, 2.8.0.0]"; ExpectedVersions=@("2.5.0.0", "2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0", "2.8.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(2.5.0.0, 2.8.0.0)"; ExpectedVersions=@("2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(2.9.4.0,)"; ExpectedVersions=@("2.10.0.0", "2.10.1.0", "2.10.2.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[2.9.4.0,)"; ExpectedVersions=@("2.9.4.0", "2.10.0.0", "2.10.1.0", "2.10.2.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,2.0.0.0)"; ExpectedVersions=@("1.9.0.0"); Reason="validate version, maximum version exclusive"}, + @{Version="(,2.0.0.0]"; ExpectedVersions=@("1.9.0.0", "2.0.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[2.5.0.0, 2.8.0.0)"; ExpectedVersions=@("2.5.0.0", "2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0", "2.8.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + @{Version="(2.5.0.0, 2.8.0.0]"; ExpectedVersions=@("2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0", "2.8.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} + + It "find resource when given Name to " -TestCases $testCases2{ + param($Version, $ExpectedVersions) + $res = Find-PSResource -Name "Carbon" -Version $Version -Repository $PSGalleryName + foreach ($item in $res) { + $item.Name | Should -Be "Carbon" + $ExpectedVersions | Should -Contain $item.Version + } + } + + It "not find resource with incorrectly formatted version such as " -TestCases @( + @{Version='(2.10.0.0)'; Description="exclusive version (2.10.0.0)"}, + @{Version='[2-10-0-0]'; Description="version formatted with invalid delimiter"} + ) { + param($Version, $Description) + + $res = Find-PSResource -Name "Carbon" -Version $Version -Repository $PSGalleryName + $res | Should -BeNullOrEmpty + } + + $testCases = @{Version='[2.*.0.0]'; Description="version with wilcard in middle"}, + @{Version='[*.10.0.0]'; Description="version with wilcard at start"}, + @{Version='[2.10.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.5.0.*'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.5.0.]'; Description="version with missing digit at end"}, + @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + + It "not find resource and throw exception with incorrectly formatted version such as " -TestCases $testCases { + param($Version, $Description) + + Find-PSResource -Name "Carbon" -Version $Version -Repository $PSGalleryName -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "IncorrectVersionFormat,Microsoft.PowerShell.PowerShellGet.Cmdlets.FindPSResource" + } + + It "find resources when given Name, Version not null --> '*'" { + $res = Find-PSResource -Name "Carbon" -Version "*" -Repository $PSGalleryName + $res | ForEach-Object { + $_.Name | Should -Be "Carbon" + } + $res.Count | Should -BeGreaterOrEqual 1 + } + + It "find resource when given Name, Version param null" { + $res = Find-PSResource -Name "Carbon" -Repository $PSGalleryName + $res.Name | Should -Be "Carbon" + $res.Version | Should -Be "2.10.2.0" + } + + It "find resource with latest (including prerelease) version given Prerelease parameter" { + # test_module resource's latest version is a prerelease version, before that it has a non-prerelease version + $res = Find-PSResource -Name "test_module" -Repository $TestGalleryName + $res.Version | Should -Be "5.0.0.0" + + $resPrerelease = Find-PSResource -Name "test_module" -Prerelease -Repository $TestGalleryName + $resPrerelease.Version | Should -Be "5.2.5.0" + } + + It "find resources, including Prerelease version resources, when given Prerelease parameter" { + $resWithoutPrerelease = Find-PSResource -Name "Carbon" -Version "*" -Repository $PSGalleryName + $resWithPrerelease = Find-PSResource -Name "Carbon" -Version "*" -Repository $PSGalleryName + $resWithPrerelease.Count | Should -BeGreaterOrEqual $resWithoutPrerelease.Count + } + + It "find resource of Type script or module from PSGallery, when no Type parameter provided" { + $resScript = Find-PSResource -Name "AzureSqlScale" -Repository $PSGalleryName + $resScript.Name | Should -Be "AzureSqlScale" + $resScript.Type | Should -Be "Script" + + $resModule = Find-PSResource -Name "Carbon" -Repository $PSGalleryName + $resModule.Name | Should -Be "Carbon" + $resModuleType = Out-String -InputObject $resModule.Type + $resModuleType.Replace(",", " ").Split() | Should -Contain "Module" + } + + It "find resource of Type Script from PSGallery, when Type Script specified" { + $resScript = Find-PSResource -Name "AzureSqlScale" -Repository $PSGalleryName -Type "Script" + $resScript.Name | Should -Be "AzureSqlScale" + $resScript.Repository | Should -Be "PSGalleryScripts" + $resScript.Type | Should -Be "Script" + } + + It "find resource of Type Command from PSGallery, when Type Command specified" { + $resources = Find-PSResource -Name "AzureS*" -Repository $PSGalleryName -Type "Command" + foreach ($item in $resources) { + $resType = Out-String -InputObject $item.Type + $resType.Replace(",", " ").Split() | Should -Contain "Command" + } + } + + It "find resuources 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) { + $resWithEitherExpectedTag | Should -Contain $item.Name + } + } + + It "find resource with IncludeDependencies parameter" { + $res = Find-PSResource -Name "Az.Compute" -IncludeDependencies -Repository $PSGalleryName + $isDependencyNamePresent = $False + $isDependencyVersionCorrect = $False + foreach ($item in $res) { + if ($item.Name -eq "Az.Accounts") + { + $isDependencyNamePresent = $True + $isDependencyVersionCorrect = [System.Version]$item.Version -ge [System.Version]"2.2.8.0" + } + } + $isDependencyNamePresent | Should -BeTrue + $isDependencyVersionCorrect | Should -BeTrue + } + + It "find resource in local repository given Repository parameter" { + $publishModuleName = "TestFindModule" + $repoName = "psgettestlocal" + Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName $repoName + + $res = Find-PSResource -Name $publishModuleName -Repository $repoName + $res | Should -Not -BeNullOrEmpty + $res.Name | Should -Be $publishModuleName + $res.Repository | Should -Be $repoName + } + + It "find Resource given repository parameter, where resource exists in multiple local repos" { + $moduleName = "test_local_mod" + $repoHigherPriorityRanking = "psgettestlocal" + $repoLowerPriorityRanking = "psgettestlocal2" + + Get-ModuleResourcePublishedToLocalRepoTestDrive $moduleName $repoHigherPriorityRanking + Get-ModuleResourcePublishedToLocalRepoTestDrive $moduleName $repoLowerPriorityRanking + + $res = Find-PSResource -Name $moduleName + $res.Repository | Should -Be $repoHigherPriorityRanking + + $resNonDefault = Find-PSResource -Name $moduleName -Repository $repoLowerPriorityRanking + $resNonDefault.Repository | Should -Be $repoLowerPriorityRanking + } +} diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index bfeaea5a2..dc9223c10 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -25,6 +25,8 @@ $script:PSGalleryLocation = 'https://www.powershellgallery.com/api/v2' $script:PoshTestGalleryName = 'PoshTestGallery' $script:PostTestGalleryLocation = 'https://www.poshtestgallery.com/api/v2' +$script:NuGetGalleryName = 'NuGetGallery' + if($script:IsInbox) { $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell" @@ -125,6 +127,10 @@ function Get-PSGetLocalAppDataPath { return $script:PSGetAppLocalPath } +function Get-NuGetGalleryName +{ + return $script:NuGetGalleryName +} function Get-PSGalleryName { return $script:PSGalleryName @@ -166,6 +172,7 @@ function Get-RemoveTestDirs { } } } + function Get-NewPSResourceRepositoryFile { # register our own repositories with desired priority $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" @@ -197,13 +204,39 @@ function Get-RevertPSResourceRepositoryFile { } } -function Get-TestDriveSetUp -{ +function Register-LocalRepos { $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" $null = New-Item $repoURLAddress -ItemType Directory -Force + $localRepoParams = @{ + Name = "psgettestlocal" + URL = $repoURLAddress + Priority = 40 + Trusted = $false + } + Register-PSResourceRepository @localRepoParams + + $repoURLAddress2 = Join-Path -Path $TestDrive -ChildPath "testdir2" + $null = New-Item $repoURLAddress2 -ItemType Directory -Force + $localRepoParams2 = @{ + Name = "psgettestlocal2" + URL = $repoURLAddress2 + Priority = 50 + Trusted = $false + } + Register-PSResourceRepository @localRepoParams2 + Write-Verbose("registered psgettestlocal, psgettestlocal2") +} - Set-PSResourceRepository -Name "psgettestlocal" -URL $repoURLAddress - +function Unregister-LocalRepos { + if(Get-PSResourceRepository -Name "psgettestlocal"){ + Unregister-PSResourceRepository -Name "psgettestlocal" + } + if(Get-PSResourceRepository -Name "psgettestlocal2"){ + Unregister-PSResourceRepository -Name "psgettestlocal2" + } +} +function Get-TestDriveSetUp +{ $testResourcesFolder = Join-Path $TestDrive -ChildPath "TestLocalDirectory" $script:testIndividualResourceFolder = Join-Path -Path $testResourcesFolder -ChildPath "PSGet_$(Get-Random)" @@ -304,7 +337,10 @@ function Get-ModuleResourcePublishedToLocalRepoTestDrive { Param( [string] - $moduleName + $moduleName, + + [string] + $repoName ) Get-TestDriveSetUp @@ -313,11 +349,34 @@ function Get-ModuleResourcePublishedToLocalRepoTestDrive $null = New-Item -Path $publishModuleBase -ItemType Directory -Force $version = "1.0" - New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" + New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" - Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal + Publish-PSResource -Path $publishModuleBase -Repository $repoName } +function Register-LocalRepos { + $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" + $null = New-Item $repoURLAddress -ItemType Directory -Force + $localRepoParams = @{ + Name = "psgettestlocal" + URL = $repoURLAddress + Priority = 40 + Trusted = $false + } + + Register-PSResourceRepository @localRepoParams + + $repoURLAddress2 = Join-Path -Path $TestDrive -ChildPath "testdir2" + $null = New-Item $repoURLAddress2 -ItemType Directory -Force + $localRepoParams2 = @{ + Name = "psgettestlocal2" + URL = $repoURLAddress2 + Priority = 50 + Trusted = $false + } + + Register-PSResourceRepository @localRepoParams2 +} function RemoveItem { Param( diff --git a/test/testRepositories.xml b/test/testRepositories.xml index 5f186d004..b84e90f9d 100644 --- a/test/testRepositories.xml +++ b/test/testRepositories.xml @@ -1,6 +1,6 @@ - - + + From 7559b8be07d74ccf588b2fe68b39ccc8ccf6fd66 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 22 Jun 2021 13:13:19 -0700 Subject: [PATCH 016/276] Update build files to build only netstandard2.0, and remove old source and test directories (#382) --- build.ps1 | 2 +- doBuild.ps1 | 1 + src/PSModule.psm1 | 30 - src/PowerShellGet.psd1 | 116 +- src/code/FindHelper.cs | 3 +- src/code/PowerShellGet.csproj | 2 +- srcOld/PSModule.psm1 | 30 - srcOld/PowerShellGet.psd1 | 129 -- srcOld/code/ArgumentCompleter.cs | 39 - srcOld/code/CacheSettings.cs | 289 ---- srcOld/code/FindHelper.cs | 1323 --------------- srcOld/code/FindPSResource.cs | 1495 ----------------- srcOld/code/GetHelper.cs | 389 ----- srcOld/code/GetPSResource.cs | 117 -- srcOld/code/GetPSResourceRepository.cs | 54 - srcOld/code/InstallHelper.cs | 1105 ------------ srcOld/code/InstallPSResource.cs | 288 ---- srcOld/code/InstallPkgParams.cs | 18 - srcOld/code/LoggerCatalogLeafProcessor.cs | 63 - srcOld/code/NuGetLogger.cs | 196 --- srcOld/code/PackageMetadata.cs | 81 - srcOld/code/PackageMetadataAllTables.cs | 30 - srcOld/code/PowerShellGet.csproj | 42 - srcOld/code/PublishPSResource.cs | 907 ---------- srcOld/code/RegisterPSResourceRepository.cs | 263 --- srcOld/code/RepositorySettings.cs | 296 ---- srcOld/code/ResourceSettings.cs | 24 - srcOld/code/SavePSResource.cs | 222 --- srcOld/code/SetPSResourceRepository.cs | 263 --- srcOld/code/UnregisterPSResourceRepository.cs | 65 - srcOld/code/UpdatePSResource.cs | 181 -- srcOld/code/Utilities.cs | 158 -- testOld/FindResource.Command.Tests.ps1 | 234 --- testOld/FindResource.DSCResource.Tests.ps1 | 245 --- testOld/FindResource.Module.Tests.ps1 | 263 --- testOld/FindResource.RoleCapability.Tests.ps1 | 179 -- testOld/FindResource.Script.Tests.ps1 | 234 --- testOld/PSGetTestUtils.psm1 | 428 ----- testOld/PSRepository.Tests.ps1 | 619 ------- testOld/PublishResource.Tests.ps1 | 98 -- testOld/RequiredResource.Tests.ps1 | 147 -- testOld/testRepositories.xml | 6 - 42 files changed, 21 insertions(+), 10653 deletions(-) delete mode 100644 src/PSModule.psm1 delete mode 100644 srcOld/PSModule.psm1 delete mode 100644 srcOld/PowerShellGet.psd1 delete mode 100644 srcOld/code/ArgumentCompleter.cs delete mode 100644 srcOld/code/CacheSettings.cs delete mode 100644 srcOld/code/FindHelper.cs delete mode 100644 srcOld/code/FindPSResource.cs delete mode 100644 srcOld/code/GetHelper.cs delete mode 100644 srcOld/code/GetPSResource.cs delete mode 100644 srcOld/code/GetPSResourceRepository.cs delete mode 100644 srcOld/code/InstallHelper.cs delete mode 100644 srcOld/code/InstallPSResource.cs delete mode 100644 srcOld/code/InstallPkgParams.cs delete mode 100644 srcOld/code/LoggerCatalogLeafProcessor.cs delete mode 100644 srcOld/code/NuGetLogger.cs delete mode 100644 srcOld/code/PackageMetadata.cs delete mode 100644 srcOld/code/PackageMetadataAllTables.cs delete mode 100644 srcOld/code/PowerShellGet.csproj delete mode 100644 srcOld/code/PublishPSResource.cs delete mode 100644 srcOld/code/RegisterPSResourceRepository.cs delete mode 100644 srcOld/code/RepositorySettings.cs delete mode 100644 srcOld/code/ResourceSettings.cs delete mode 100644 srcOld/code/SavePSResource.cs delete mode 100644 srcOld/code/SetPSResourceRepository.cs delete mode 100644 srcOld/code/UnregisterPSResourceRepository.cs delete mode 100644 srcOld/code/UpdatePSResource.cs delete mode 100644 srcOld/code/Utilities.cs delete mode 100644 testOld/FindResource.Command.Tests.ps1 delete mode 100644 testOld/FindResource.DSCResource.Tests.ps1 delete mode 100644 testOld/FindResource.Module.Tests.ps1 delete mode 100644 testOld/FindResource.RoleCapability.Tests.ps1 delete mode 100644 testOld/FindResource.Script.Tests.ps1 delete mode 100644 testOld/PSGetTestUtils.psm1 delete mode 100644 testOld/PSRepository.Tests.ps1 delete mode 100644 testOld/PublishResource.Tests.ps1 delete mode 100644 testOld/RequiredResource.Tests.ps1 delete mode 100644 testOld/testRepositories.xml diff --git a/build.ps1 b/build.ps1 index ebada6148..ff1f68b1a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -36,7 +36,7 @@ param ( [ValidateSet("Debug", "Release")] [string] $BuildConfiguration = "Debug", - [ValidateSet("netstandard2.0","net472")] + [ValidateSet("netstandard2.0")] [string] $BuildFramework = "netstandard2.0" ) diff --git a/doBuild.ps1 b/doBuild.ps1 index bc864f1fe..c6ae2a80c 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -81,6 +81,7 @@ function DoBuild 'NuGet.Protocol' 'NuGet.Repositories' 'NuGet.Versioning' + 'Newtonsoft.Json' ) } elseif ($BuildFramework -eq 'net472') { $assemblyNames = @( diff --git a/src/PSModule.psm1 b/src/PSModule.psm1 deleted file mode 100644 index 64c9f14c9..000000000 --- a/src/PSModule.psm1 +++ /dev/null @@ -1,30 +0,0 @@ -# -# Script module for module 'PowerShellGet' -# -Set-StrictMode -Version Latest - -# Summary: PowerShellGet is supported on Windows PowerShell 5.1 or later and PowerShell 6.0+ - -$isCore = ($PSVersionTable.Keys -contains "PSEdition") -and ($PSVersionTable.PSEdition -ne 'Desktop') -if ($isCore) -{ - $script:Framework = 'netstandard2.0' - $script:FrameworkToRemove = 'net472' - -} else { - $script:Framework = 'net472' - $script:FrameworkToRemove = 'netstandard2.0' -} - -# Set up some helper variables to make it easier to work with the module -$script:PSModule = $ExecutionContext.SessionState.Module -$script:PSModuleRoot = $script:PSModule.ModuleBase -$script:PSGet = 'PowerShellGet.dll' - -# CONSTRUCT A PATH TO THE CORRECT ASSEMBLY -#$pathToAssembly = [io.path]::combine($PSScriptRoot, $script:Framework, $script:PSGet) -$pathToFramework = Join-Path -Path $script:PSModuleRoot -ChildPath $script:Framework -$pathToAssembly = Join-Path -Path $pathToFramework -ChildPath $script:PSGet - -# NOW LOAD THE APPROPRIATE ASSEMBLY -Import-Module -Name $pathToAssembly diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 1b138d65e..0ce94ad9a 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -1,127 +1,43 @@ @{ - RootModule = 'PSModule.psm1' + RootModule = './netstandard2.0/PowerShellGet.dll' ModuleVersion = '3.0.0' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' Copyright = '(c) Microsoft Corporation. All rights reserved.' Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, Scripts, and DSC Resources.' - PowerShellVersion = '3.0' + PowerShellVersion = '5.1' + DotNetFrameworkVersion = '2.0' + CLRVersion = '4.0.0' FormatsToProcess = 'PSGet.Format.ps1xml' CmdletsToExport = @( 'Find-PSResource', - 'Get-PSResourceRepository', 'Get-InstalledPSResource', - 'Install-PSResource', + 'Get-PSResourceRepository', + # 'Install-PSResource', 'Register-PSResourceRepository', - 'Save-PSResource', + # 'Save-PSResource', 'Set-PSResourceRepository', 'Publish-PSResource', 'Uninstall-PSResource', - 'Unregister-PSResourceRepository', - 'Update-PSResource') + 'Unregister-PSResourceRepository') + # 'Update-PSResource') VariablesToExport = 'PSGetPath' - AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') - PrivateData = @{ - PSData = @{ + AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') + PrivateData = @{ + PSData = @{ Prerelease = 'beta10' - Tags = @('PackageManagement', + Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', 'Linux', 'Mac', 'Windows') - ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' - LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' + ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' + LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' -### 3.0.0-beta10 -# Changelog -Bug Fixes -* Bug fix for -ModuleName (used with -Version) in Find-PSResource returning incorrect resource type -* Make repositories unique by name -* Add tab completion for -Name parameter in Get-PSResource, Set-PSResource, and Unregister-PSResource -* Remove credential argument from Register-PSResourceRepository -* Change returned version type from 'NuGet.Version' to 'System.Version' -* Have Install output verbose message on successful installation (error for unsuccessful installation) -* Ensure that not passing credentials does not throw an error if searching through multiple repositories -* Remove attempt to remove loaded assemblies in psm1 - -### 3.0.0-beta9 -New Features -* Add DSCResources - -Bug Fixes -* Fix bug related to finding dependencies that do not have a specified version in Find-PSResource -* Fix bug related to parsing 'RequiredModules' in .psd1 in Publish-PSResource -* Improve error handling for when repository in Publish-PSResource does not exist -* Fix for unix paths in Get-PSResource, Install-PSResource, and Uninstall-PSResource -* Add debugging statements for Get-PSResource and Install-PSResource -* Fix bug related to paths in Uninstall-PSResource - -### 3.0.0-beta8 -New Features -* Add Type parameter to Install-PSResource -* Add 'sudo' check for admin privileges in Unix in Install-PSResource - -Bug Fixes -* Fix bug with retrieving installed scripts in Get-PSResource -* Fix bug with AllUsers scope in Windows in Install-PSResource -* Fix bug with Uninstall-PSResource sometimes not fully uninstalling -* Change installed file paths to contain original version number instead of normalized version - -### 3.0.0-beta7 -New Features -* Completed functionality for Update-PSResource -* Input-Object parameter for Install-PSResource - -Bug Fixes -* Improved experience when loading module for diffent frameworks -* Bug fix for assembly loading error in Publish-PSResource -* Allow for relative paths when registering psrepository -* Improved error handling for Install-PSResource and Update-PSResource -* Remove prerelease tag from module version directory -* Fix error getting thrown from paths with incorrectly formatted module versions -* Fix module installation paths on Linux and MacOS - -### 3.0.0-beta6 -New Feature -* Implement functionality for Publish-PSResource - -### 3.0.0-beta5 -* Note: 3.0.0-beta5 was skipped due to a packaging error - -### 3.0.0-beta4 -New Feature -* Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository - -Bug Fix -* Fix poor error handling for when repository is not accessible in Find-PSResource - -### 3.0.0-beta3 -New Features -* -RequiredResource parameter for Install-PSResource -* -RequiredResourceFile parameter for Install-PSResource -* -IncludeXML parameter in Save-PSResource - -Bug Fixes -* Resolved paths in Install-PSRsource and Save-PSResource -* Resolved issues with capitalization (for unix systems) in Install-PSResource and Save-PSResource - -### 3.0.0-beta2 -New Features -* Progress bar and -Quiet parameter for Install-PSResource -* -TrustRepository parameter for Install-PSResource -* -NoClobber parameter for Install-PSResource -* -AcceptLicense for Install-PSResource -* -Force parameter for Install-PSResource -* -Reinstall parameter for Install-PSResource -* Improved error handling - -### 3.0.0-beta1 -BREAKING CHANGE -* Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. - +### 3.0.0-beta11 '@ } } diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 7a100edcf..20403865a 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -334,12 +334,13 @@ private IEnumerable FindFromPackageSourceSearchAPI( String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) { _cmdletPassedIn.WriteDebug(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); - yield break; } + yield break; } catch (Exception e) { _cmdletPassedIn.WriteDebug(String.Format("Exception retrieving package {0} due to {1}.", pkgName, e.Message)); + yield break; } // filter additionally because NuGet wildcard search API returns more than we need diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 2a1f3e63e..92dd42f81 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -8,7 +8,7 @@ 3.0.0.0 3.0.0 3.0.0 - netstandard2.0;net472; + netstandard2.0 diff --git a/srcOld/PSModule.psm1 b/srcOld/PSModule.psm1 deleted file mode 100644 index 882810e54..000000000 --- a/srcOld/PSModule.psm1 +++ /dev/null @@ -1,30 +0,0 @@ -# -# Script module for module 'PowerShellGet' -# -Set-StrictMode -Version Latest - -# Summary: PowerShellGet is supported on Windows PowerShell 5.1 or later and PowerShell 6.0+ - -$isCore = ($PSVersionTable.Keys -contains "PSEdition") -and ($PSVersionTable.PSEdition -ne 'Desktop') -if ($isCore) -{ - $script:Framework = 'netstandard2.0' - $script:FrameworkToRemove = 'net472' - -} else { - $script:Framework = 'net472' - $script:FrameworkToRemove = 'netstandard2.0' -} - -# Set up some helper variables to make it easier to work with the module -$script:PSModule = $ExecutionContext.SessionState.Module -$script:PSModuleRoot = $script:PSModule.ModuleBase -$script:PSGet = 'PowerShellGet.dll' - -# CONSTRUCT A PATH TO THE CORRECT ASSEMBLY -#$pathToAssembly = [io.path]::combine($PSScriptRoot, $script:Framework, $script:PSGet) -$pathToFramework = Join-Path -Path $script:PSModuleRoot -ChildPath $script:Framework -$pathToAssembly = Join-Path -Path $pathToFramework -ChildPath $script:PSGet - -# NOW LOAD THE APPROPRIATE ASSEMBLY -Import-Module -Name $pathToAssembly diff --git a/srcOld/PowerShellGet.psd1 b/srcOld/PowerShellGet.psd1 deleted file mode 100644 index 4bbadfbf5..000000000 --- a/srcOld/PowerShellGet.psd1 +++ /dev/null @@ -1,129 +0,0 @@ -@{ - RootModule = 'PSModule.psm1' - ModuleVersion = '3.0.0' - GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' - Author = 'Microsoft Corporation' - CompanyName = 'Microsoft Corporation' - Copyright = '(c) Microsoft Corporation. All rights reserved.' - Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.' - PowerShellVersion = '3.0' - CmdletsToExport = @( - 'Find-PSResource', - 'Get-PSResourceRepository', - 'Get-PSResource', - 'Install-PSResource', - 'Register-PSResourceRepository', - 'Save-PSResource', - 'Set-PSResourceRepository', - 'Publish-PSResource', - 'Uninstall-PSResource', - 'Unregister-PSResourceRepository', - 'Update-PSResource') - - VariablesToExport = 'PSGetPath' - AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') - PrivateData = @{ - PSData = @{ - Prerelease = 'beta10' - Tags = @('PackageManagement', - 'PSEdition_Desktop', - 'PSEdition_Core', - 'Linux', - 'Mac', - 'Windows') - ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' - LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' - ReleaseNotes = @' -### 3.0.0-beta10 -# Changelog -Bug Fixes -* Bug fix for -ModuleName (used with -Version) in Find-PSResource returning incorrect resource type -* Make repositories unique by name -* Add tab completion for -Name parameter in Get-PSResource, Set-PSResource, and Unregister-PSResource -* Remove credential argument from Register-PSResourceRepository -* Change returned version type from 'NuGet.Version' to 'System.Version' -* Have Install output verbose message on successful installation (error for unsuccessful installation) -* Ensure that not passing credentials does not throw an error if searching through multiple repositories -* Remove attempt to remove loaded assemblies in psm1 - -### 3.0.0-beta9 -New Features -* Add DSCResources - -Bug Fixes -* Fix bug related to finding dependencies that do not have a specified version in Find-PSResource -* Fix bug related to parsing 'RequiredModules' in .psd1 in Publish-PSResource -* Improve error handling for when repository in Publish-PSResource does not exist -* Fix for unix paths in Get-PSResource, Install-PSResource, and Uninstall-PSResource -* Add debugging statements for Get-PSResource and Install-PSResource -* Fix bug related to paths in Uninstall-PSResource - -### 3.0.0-beta8 -New Features -* Add Type parameter to Install-PSResource -* Add 'sudo' check for admin privileges in Unix in Install-PSResource - -Bug Fixes -* Fix bug with retrieving installed scripts in Get-PSResource -* Fix bug with AllUsers scope in Windows in Install-PSResource -* Fix bug with Uninstall-PSResource sometimes not fully uninstalling -* Change installed file paths to contain original version number instead of normalized version - -### 3.0.0-beta7 -New Features -* Completed functionality for Update-PSResource -* Input-Object parameter for Install-PSResource - -Bug Fixes -* Improved experience when loading module for diffent frameworks -* Bug fix for assembly loading error in Publish-PSResource -* Allow for relative paths when registering psrepository -* Improved error handling for Install-PSResource and Update-PSResource -* Remove prerelease tag from module version directory -* Fix error getting thrown from paths with incorrectly formatted module versions -* Fix module installation paths on Linux and MacOS - -### 3.0.0-beta6 -New Feature -* Implement functionality for Publish-PSResource - -### 3.0.0-beta5 -* Note: 3.0.0-beta5 was skipped due to a packaging error - -### 3.0.0-beta4 -New Feature -* Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository - -Bug Fix -* Fix poor error handling for when repository is not accessible in Find-PSResource - -### 3.0.0-beta3 -New Features -* -RequiredResource parameter for Install-PSResource -* -RequiredResourceFile parameter for Install-PSResource -* -IncludeXML parameter in Save-PSResource - -Bug Fixes -* Resolved paths in Install-PSRsource and Save-PSResource -* Resolved issues with capitalization (for unix systems) in Install-PSResource and Save-PSResource - -### 3.0.0-beta2 -New Features -* Progress bar and -Quiet parameter for Install-PSResource -* -TrustRepository parameter for Install-PSResource -* -NoClobber parameter for Install-PSResource -* -AcceptLicense for Install-PSResource -* -Force parameter for Install-PSResource -* -Reinstall parameter for Install-PSResource -* Improved error handling - -### 3.0.0-beta1 -BREAKING CHANGE -* Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. - -'@ - } - } - - HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' -} diff --git a/srcOld/code/ArgumentCompleter.cs b/srcOld/code/ArgumentCompleter.cs deleted file mode 100644 index 6ce89390a..000000000 --- a/srcOld/code/ArgumentCompleter.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Management.Automation; -using System.Management.Automation.Language; - -internal class RepositoryNameCompleter : IArgumentCompleter -{ - public IEnumerable CompleteArgument( - string commandName, // For cmdlets Get-PSResource, Set-PSResource, and Unregister-PSResource - string parameterName, // For -Name parameter - string wordToComplete, - CommandAst commandAst, - IDictionary fakeBoundParameters) - { - return CompleteRepositoryName(wordToComplete); - } - - - private IEnumerable CompleteRepositoryName(string wordToComplete) - { - List res = new List(); - - RespositorySettings repositorySettings = new RespositorySettings(); - IReadOnlyList listOfRepositories = repositorySettings.Read(null); - - foreach (PSObject repo in listOfRepositories) - { - string repoName = repo.Properties["Name"].Value.ToString(); - if (repoName.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase)) - { - res.Add(new CompletionResult(repoName)); - } - } - - return res; - } -} \ No newline at end of file diff --git a/srcOld/code/CacheSettings.cs b/srcOld/code/CacheSettings.cs deleted file mode 100644 index 52d4a787b..000000000 --- a/srcOld/code/CacheSettings.cs +++ /dev/null @@ -1,289 +0,0 @@ - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using System; -using System.IO; -using System.Collections.Generic; -using Newtonsoft.Json; -using System.Data; -using static System.Environment; -//using Microsoft.Extensions.DependencyModel; - -namespace Microsoft.PowerShell.PowerShellGet -{ - /// - /// Cache settings - /// - - class CacheSettings - { - /// - /// Default file name for a settings file is 'psresourcerepository.config' - /// Also, the user level setting file at '%APPDATA%\NuGet' always uses this name - /// -// public static readonly string DefaultCacheFileName = "PSResourceRepository.xml"; - public static readonly string DefaultCachePath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet", "RepositoryCache"); - //public static readonly string DefaultCachePath = @"%APPDATA%/PowerShellGet/repositorycache"; //@"%APPDTA%\NuGet"; // c:\code\temp\repositorycache - // public static readonly string DefaultFullCachePath = Path.Combine(DefaultCachePath, DefaultCacheFileName); - - public static string DefaultFullCachePath = ""; - - public CacheSettings() { } - - - /// - /// Find a repository cache - /// Returns: bool - /// - /// - public bool CacheExists(string repositoryName) - { - // Search in the designated location for the cache - DefaultFullCachePath = Path.Combine(DefaultCachePath, repositoryName + ".json"); - - if (File.Exists(DefaultFullCachePath)) - { - return true; - } - - return false; - } - - - /// - /// For any repository that is not the PSGallery, - /// create a cache by essentially calling find * - /// - /// - public void CreateCache(string repositoryName) - { - // TODO - } - - - - - public void Read(string repositoryName) - { - // Call CacheExists() - if (!CacheExists(repositoryName)) - { - // user should not receive this error--- just for me :) - throw new ArgumentException("Was not able to successfully find cache"); - //return; - } - } - - - - - public DataSet CreateDataTable(string repositoryName) - { - // Call CacheExists() - if (!CacheExists(repositoryName)) - { - // user should not receive this error--- just for me :) - throw new ArgumentException("Was not able to successfully find cache"); - //return; - } - - // Open file - List repoCache = null; - using (StreamReader r = new StreamReader(DefaultFullCachePath)) - { - string json = r.ReadToEnd(); - - try - { - repoCache = JsonConvert.DeserializeObject>(json, new JsonSerializerSettings() { MaxDepth = 6 }); - } - catch (Exception e) - { - // throw error - Console.WriteLine("EXCEPTION: " + e); - } - } - - DataSet dataSet = new DataSet("CacheDataSet"); - // Create new DataTable. - DataTable table = dataSet.Tables.Add("CacheDataTable"); - - - string[] stringProperties = new string[] { "Key", "Name", "Version", "Type", "Description", "Author", "Copyright", "PublishedDate", "InstalledDate", "UpdatedDate", "LicenseUri", "ProjectUri", "IconUri", "PowerShellGetFormatVersion", "ReleaseNotes", "RepositorySourceLocation", "Repository", "PackageManagementProvider", "IsPrerelease" }; - - // Declare DataColumn and DataRow variables. - DataRow row, tagsRow, dependenciesRow, commandsRow, dscResoureRow, roleCapabilityRow; - DataColumn column, tagsColumn, dependenciesColumn, commandsColumn, dscResourceColumn, roleCapabilityColumn; - - - /* Create Main Metadata Table */ - // Create the column for all properties - foreach (var property in stringProperties) - { - // Add column to datatable - column = new DataColumn(property, typeof(System.String)); - table.Columns.Add(column); - } - - - /* Create Tags Table */ - DataTable tagsTable = dataSet.Tables.Add("TagsTable"); - tagsColumn = new DataColumn("Key", typeof(System.String)); - tagsTable.Columns.Add(tagsColumn); - tagsColumn = new DataColumn("Tags", typeof(System.String)); - tagsTable.Columns.Add(tagsColumn); - - - /* Create Dependencies Table */ - DataTable dependenciesTable = dataSet.Tables.Add("DependenciesTable"); - dependenciesColumn = new DataColumn("Key", typeof(System.String)); - dependenciesTable.Columns.Add(dependenciesColumn); - dependenciesColumn = new DataColumn("Dependencies", typeof(Dependency)); - dependenciesTable.Columns.Add(dependenciesColumn); - - - /* Create Commands Table */ - DataTable commandsTable = dataSet.Tables.Add("CommandsTable"); - commandsColumn = new DataColumn("Key", typeof(System.String)); - commandsTable.Columns.Add(commandsColumn); - commandsColumn = new DataColumn("Commands", typeof(System.String)); - commandsTable.Columns.Add(commandsColumn); - - - /* Create DscResource Table */ - DataTable dscResourceTable = dataSet.Tables.Add("DscResourceTable"); - dscResourceColumn = new DataColumn("Key", typeof(System.String)); - dscResourceTable.Columns.Add(dscResourceColumn); - dscResourceColumn = new DataColumn("DscResources", typeof(System.String)); - dscResourceTable.Columns.Add(dscResourceColumn); - - /* Create RoleCapability Table */ - DataTable roleCapabilityTable = dataSet.Tables.Add("RoleCapabilityTable"); - roleCapabilityColumn = new DataColumn("Key", typeof(System.String)); - roleCapabilityTable.Columns.Add(roleCapabilityColumn); - roleCapabilityColumn = new DataColumn("RoleCapability", typeof(System.String)); - roleCapabilityTable.Columns.Add(roleCapabilityColumn); - - - foreach (PackageMetadata pkg in repoCache) - { - - // Console.WriteLine(pkg.Name); - var pkgKey = pkg.Name + pkg.Version + pkg.Repository; - - // Create new DataRow objects and add to DataTable. - row = table.NewRow(); - row["Key"] = pkgKey; - row["Name"] = pkg.Name; - row["Version"] = pkg.Version; - row["Type"] = pkg.Type; - row["Description"] = pkg.Description; - // row["Author"] = pkg.Author; - row["Copyright"] = pkg.Copyright; - row["PublishedDate"] = pkg.PublishedDate; - row["InstalledDate"] = pkg.InstalledDate; - row["UpdatedDate"] = pkg.UpdatedDate; - row["LicenseUri"] = pkg.LicenseUri; - row["ProjectUri"] = pkg.ProjectUri; - row["IconUri"] = pkg.IconUri; - row["PowerShellGetFormatVersion"] = pkg.PowerShellGetFormatVersion; - row["ReleaseNotes"] = pkg.ReleaseNotes; - row["RepositorySourceLocation"] = pkg.RepositorySourceLocation; - row["Repository"] = pkg.Repository; - row["PackageManagementProvider"] = pkg.PackageManagementProvider; - row["IsPrerelease"] = pkg.AdditionalMetadata.IsPrerelease; - - table.Rows.Add(row); - - if (pkg.Tags.Length == 0) - { - tagsRow = tagsTable.NewRow(); - tagsRow["Key"] = pkgKey; - tagsRow["Tags"] = ""; - tagsTable.Rows.Add(tagsRow); - } - foreach (var tag in pkg.Tags) - { - tagsRow = tagsTable.NewRow(); - tagsRow["Key"] = pkgKey; - tagsRow["Tags"] = tag; - tagsTable.Rows.Add(tagsRow); - } - - if (pkg.Dependencies.Length == 0) - { - dependenciesRow = dependenciesTable.NewRow(); - dependenciesRow["Key"] = pkgKey; - - var dep = new Dependency(); - - dependenciesRow["Dependencies"] = dep; - dependenciesTable.Rows.Add(dependenciesRow); - } - foreach (var dependency in pkg.Dependencies) - { - dependenciesRow = dependenciesTable.NewRow(); - dependenciesRow["Key"] = pkgKey; - - var dep = new Dependency(); - dep.Name = dependency.Name; - dep.MinimumVersion = dependency.MinimumVersion; - dep.MaximumVersion = dependency.MaximumVersion; - dependenciesRow["Dependencies"] = dep; - - dependenciesTable.Rows.Add(dependenciesRow); - } - - if (pkg.Includes.Command.Length == 0) - { - commandsRow = commandsTable.NewRow(); - commandsRow["Key"] = pkgKey; - commandsRow["Commands"] = ""; - commandsTable.Rows.Add(commandsRow); - } - foreach (var command in pkg.Includes.Command) - { - commandsRow = commandsTable.NewRow(); - commandsRow["Key"] = pkgKey; - commandsRow["Commands"] = command; - commandsTable.Rows.Add(commandsRow); - } - - if (pkg.Includes.DscResource.Length == 0) - { - dscResoureRow = dscResourceTable.NewRow(); - dscResoureRow["Key"] = pkgKey; - dscResoureRow["DscResources"] = ""; - dscResourceTable.Rows.Add(dscResoureRow); - } - foreach (var dscResource in pkg.Includes.DscResource) - { - dscResoureRow = dscResourceTable.NewRow(); - dscResoureRow["Key"] = pkgKey; - dscResoureRow["DscResources"] = dscResource; - dscResourceTable.Rows.Add(dscResoureRow); - } - - if (pkg.Includes.RoleCapability.Length == 0) - { - roleCapabilityRow = roleCapabilityTable.NewRow(); - roleCapabilityRow["Key"] = pkgKey; - roleCapabilityRow["RoleCapability"] = ""; - roleCapabilityTable.Rows.Add(roleCapabilityRow); - } - foreach (var roleCapbility in pkg.Includes.RoleCapability) - { - roleCapabilityRow = roleCapabilityTable.NewRow(); - roleCapabilityRow["Key"] = pkgKey; - roleCapabilityRow["RoleCapability"] = roleCapbility; - roleCapabilityTable.Rows.Add(roleCapabilityRow); - } - } - - return dataSet; - } - - } -} diff --git a/srcOld/code/FindHelper.cs b/srcOld/code/FindHelper.cs deleted file mode 100644 index d581d602e..000000000 --- a/srcOld/code/FindHelper.cs +++ /dev/null @@ -1,1323 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using System; -using System.Management.Automation; -using System.Collections.Generic; -using NuGet.Configuration; -using NuGet.Common; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using System.Threading; -using LinqKit; -using MoreLinq.Extensions; -using NuGet.Versioning; -using System.Data; -using System.Linq; -using System.Net; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using System.Net.Http; -using System.IO; -using System.Threading.Tasks; -using Newtonsoft.Json; -using static System.Environment; - - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - - /// - /// Find helper class - /// - class FindHelper : PSCmdlet - { - // This will be a list of all the repository caches - public static readonly List RepoCacheFileName = new List(); - // Temporarily store cache in this path for testing purposes - public static readonly string RepositoryCacheDir = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet", "RepositoryCache"); - //public static readonly string RepositoryCacheDir = @"%APPDATA%/PowerShellGet/repositorycache";//@"%APPDTA%\NuGet"; - //private readonly object p; - - // Define the cancellation token. - CancellationTokenSource source; - CancellationToken cancellationToken; - List pkgsLeftToFind; - private const string CursorFileName = "cursor.json"; - - string[] _name; - string[] _type; - string _version; - bool _prerelease = false; - string _moduleName; - string[] _tags; - string[] _repository; - PSCredential _credential; - SwitchParameter _includeDependencies; - - public FindHelper() - { } - - /// - /// - public List beginFindHelper(string[] _name, string[] _type, string _version, bool _prerelease, string _moduleName, string[] _tags, string[] _repository, PSCredential _credential, SwitchParameter _includeDependencies, bool writeToConsole) - { - this._name = _name; - this._type = _type; - this._version = _version; - this._prerelease = _prerelease; - this._moduleName = _moduleName; - this._tags = _tags; - this._repository = _repository; - this._credential = _credential; - this._includeDependencies = _includeDependencies; - - - source = new CancellationTokenSource(); - cancellationToken = source.Token; - - - - var r = new RespositorySettings(); - var listOfRepositories = r.Read(_repository); - - var returnedPkgsFound = new List>(); - pkgsLeftToFind = _name.ToList(); - List returnedPSObjects = new List(); - foreach (var repoName in listOfRepositories) - { - - // We'll need to use the catalog reader when enumerating through all packages under v3 protocol. - // if using v3 endpoint and there's no exact name specified (ie no name specified or a name with a wildcard is specified) - if (repoName.Properties["Url"].Value.ToString().EndsWith("/v3/index.json") && - (_name.Length == 0 || _name.Any(n => n.Contains("*"))))//_name.Contains("*"))) /// TEST THIS!!!!!!! - { - // right now you can use wildcards with an array of names, ie -name "Az*", "PS*", "*Get", will take a hit performance wise, though. - // TODO: add wildcard condition here - /*** ProcessCatalogReader(repoName.Properties["Name"].Value.ToString(), repoName.Properties["Url"].Value.ToString()); */ - } - - - - // if it can't find the pkg in one repository, it'll look in the next one in the list - // returns any pkgs found, and any pkgs that weren't found - returnedPkgsFound.AddRange(FindPackagesFromSource(repoName.Properties["Url"].Value.ToString(), cancellationToken)); - - - // Flatten returned pkgs before displaying output returnedPkgsFound.Flatten().ToList()[0] - var flattenedPkgs = returnedPkgsFound.Flatten(); - // flattenedPkgs.ToList(); - - - if (flattenedPkgs.Any() && flattenedPkgs.First() != null) - { - foreach (IPackageSearchMetadata pkg in flattenedPkgs) - { - //WriteObject(pkg); - - - PSObject pkgAsPSObject = new PSObject(); - pkgAsPSObject.Members.Add(new PSNoteProperty("Name", pkg.Identity.Id)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Version", pkg.Identity.Version)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repoName.Properties["Name"].Value.ToString())); - pkgAsPSObject.Members.Add(new PSNoteProperty("Description", pkg.Description)); - - if (writeToConsole) - { - WriteObject(pkgAsPSObject); - } - else { - returnedPSObjects.Add(pkgAsPSObject); - } - } - } - - // reset found packages - returnedPkgsFound.Clear(); - - // if we need to search all repositories, we'll continue, otherwise we'll just return - if (!pkgsLeftToFind.Any()) - { - break; - } - - - - } // end of foreach - - return returnedPSObjects; - - } - -/*** - public void ProcessCatalogReader(string repoName, string sourceUrl) - { - - // test initalizing a cursor see: https://docs.microsoft.com/en-us/nuget/guides/api/query-for-all-published-packages - // we want all packages published from the beginning of time - // DateTime cursor = DateTime.MinValue; - - - - // Define a lower time bound for leaves to fetch. This exclusive minimum time bound is called the cursor. - //var cursor = DateTime.MinValue; /// come back to this GetCursor(); - var cursor = GetCursor(); // come back to this - - // Discover the catalog index URL from the service index. - var catalogIndexUrl = GetCatalogIndexUrlAsync(sourceUrl).GetAwaiter().GetResult(); - - - var httpClient = new HttpClient(); - - // Download the catalog index and deserialize it. - var indexString = httpClient.GetStringAsync(catalogIndexUrl).GetAwaiter().GetResult(); - Console.WriteLine($"Fetched catalog index {catalogIndexUrl}."); - var index = JsonConvert.DeserializeObject(indexString); - - // Find all pages in the catalog index that meet the time bound. - - var pageItems = index - .Items - .Where(x => x.CommitTimestamp > cursor); - - var allLeafItems = new List(); - - - foreach (var pageItem in pageItems) /// need to process one page at a time - { - // Download the catalog page and deserialize it. - var pageString = httpClient.GetStringAsync(pageItem.Url).GetAwaiter().GetResult(); - Console.WriteLine($"Fetched catalog page {pageItem.Url}."); - var page = JsonConvert.DeserializeObject(pageString); - - // Find all leaves in the catalog page that meet the time bound. - var pageLeafItems = page - .Items - .Where(x => x.CommitTimestamp > cursor); - - allLeafItems.AddRange(pageLeafItems); - - - // local - FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(sourceUrl); - - LocalPackageSearchResource localResourceSearch = new LocalPackageSearchResource(localResource); - LocalPackageMetadataResource localResourceMetadata = new LocalPackageMetadataResource(localResource); - - SearchFilter filter = new SearchFilter(_prerelease); - SourceCacheContext context = new SourceCacheContext(); - - - - // url - PackageSource source = new PackageSource(sourceUrl); - if (_credential != null) - { - string password = new NetworkCredential(string.Empty, _credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(sourceUrl, _credential.UserName, password, true, null); - } - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - - SourceRepository repository = new SourceRepository(source, provider); - PackageSearchResource resourceSearch = repository.GetResourceAsync().GetAwaiter().GetResult(); - PackageMetadataResource resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); - - - - - // Process all of the catalog leaf items. - Console.WriteLine($"Processing {allLeafItems.Count} catalog leaves."); - foreach (var leafItem in allLeafItems) - { - _version = leafItem.PackageVersion; - - IEnumerable foundPkgs; - if (sourceUrl.StartsWith("file://")) - { - foundPkgs = FindPackagesFromSourceHelper(sourceUrl, leafItem.PackageId, localResourceSearch, localResourceMetadata, filter, context).FirstOrDefault(); - } - else - { - foundPkgs = FindPackagesFromSourceHelper(sourceUrl, leafItem.PackageId, resourceSearch, resourceMetadata, filter, context).FirstOrDefault(); - } - - // var foundPkgsFlattened = foundPkgs.Flatten(); - foreach (var pkg in foundPkgs) - { - // First or default to convert the ienumeraable object into just an IPackageSearchmetadata object - // var pkgToOutput = foundPkgs.FirstOrDefault();//foundPkgs.Cast(); - PSObject pkgAsPSObject = new PSObject(); - pkgAsPSObject.Members.Add(new PSNoteProperty("Name", pkg.Identity.Id)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Version", pkg.Identity.Version)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repoName)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Description", pkg.Description)); - - WriteObject(pkgAsPSObject); - } - - } - - } - - } -*/ - // - public List> FindPackagesFromSource(string repositoryUrl, CancellationToken cancellationToken) - { - List> returnedPkgs = new List>(); - - if (repositoryUrl.StartsWith("file://")) - { - - FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(repositoryUrl); - - LocalPackageSearchResource resourceSearch = new LocalPackageSearchResource(localResource); - LocalPackageMetadataResource resourceMetadata = new LocalPackageMetadataResource(localResource); - - SearchFilter filter = new SearchFilter(_prerelease); - SourceCacheContext context = new SourceCacheContext(); - - - if ((_name == null) || (_name.Length == 0)) - { - returnedPkgs.AddRange(FindPackagesFromSourceHelper(repositoryUrl, null, resourceSearch, resourceMetadata, filter, context)); - } - - foreach (var n in _name) - { - returnedPkgs.AddRange(FindPackagesFromSourceHelper(repositoryUrl, n, resourceSearch, resourceMetadata, filter, context)); - } - } - else - { - - - - PackageSource source = new PackageSource(repositoryUrl); - if (_credential != null) - { - string password = new NetworkCredential(string.Empty, _credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl, _credential.UserName, password, true, null); - } - - - - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - - SourceRepository repository = new SourceRepository(source, provider); - - - PackageSearchResource resourceSearch = null; - PackageMetadataResource resourceMetadata = null; - try - { - resourceSearch = repository.GetResourceAsync().GetAwaiter().GetResult(); - resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); - } - catch (Exception e) - { - WriteDebug("Error retrieving resource from repository: " + e.Message); - return returnedPkgs; - } - - SearchFilter filter = new SearchFilter(_prerelease); - SourceCacheContext context = new SourceCacheContext(); - - if ((_name == null) || (_name.Length == 0)) - { - returnedPkgs.AddRange(FindPackagesFromSourceHelper(repositoryUrl, null, resourceSearch, resourceMetadata, filter, context)); - } - - foreach (var n in _name) - { - if (pkgsLeftToFind.Any()) - { - var foundPkgs = FindPackagesFromSourceHelper(repositoryUrl, n, resourceSearch, resourceMetadata, filter, context); - if (foundPkgs.Any() && foundPkgs.FirstOrDefault() != null) - { - returnedPkgs.AddRange(foundPkgs); - - - // if the repository is not specified or the repository is specified (but it's not '*'), then we can stop continuing to search for the package - if (_repository == null || !_repository[0].Equals("*")) - { - pkgsLeftToFind.Remove(n); - } - } - } - } - } - - return returnedPkgs; - } - - - private IEnumerable FindPackageFromCache(string repositoryName) - { - DataSet cachetables = new CacheSettings().CreateDataTable(repositoryName); - - return FindPackageFromCacheHelper(cachetables, repositoryName); - } - - - private IEnumerable FindPackageFromCacheHelper(DataSet cachetables, string repositoryName) - { - DataTable metadataTable = cachetables.Tables[0]; - DataTable tagsTable = cachetables.Tables[1]; - DataTable dependenciesTable = cachetables.Tables[2]; - DataTable commandsTable = cachetables.Tables[3]; - DataTable dscResourceTable = cachetables.Tables[4]; - DataTable roleCapabilityTable = cachetables.Tables[5]; - - DataTable queryTable = new DataTable(); - var predicate = PredicateBuilder.New(true); - - - if ((_tags != null) && (_tags.Length != 0)) - { - - var tagResults = from t0 in metadataTable.AsEnumerable() - join t1 in tagsTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - Tags = t1["Tags"], - }; - - DataTable joinedTagsTable = tagResults.ToDataTable(); - - var tagsPredicate = PredicateBuilder.New(true); - - // Build predicate by combining tag searches with 'or' - foreach (string t in _tags) - { - tagsPredicate = tagsPredicate.Or(pkg => pkg.Field("Tags").Equals(t)); - } - - - // final results -- All the appropriate pkgs with these tags - var tagsRowCollection = joinedTagsTable.AsEnumerable().Where(tagsPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(tagsRowCollection.ToDataTable()); - } - - if (_type != null) - { - if (_type.Contains("Command", StringComparer.OrdinalIgnoreCase)) - { - - var commandResults = from t0 in metadataTable.AsEnumerable() - join t1 in commandsTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - Commands = t1["Commands"], - }; - - DataTable joinedCommandTable = commandResults.ToDataTable(); - - var commandPredicate = PredicateBuilder.New(true); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - commandPredicate = commandPredicate.Or(pkg => pkg.Field("Commands").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var commandsRowCollection = joinedCommandTable.AsEnumerable().Where(commandPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(commandsRowCollection.ToDataTable()); - } - - - if (_type.Contains("DscResource", StringComparer.OrdinalIgnoreCase)) - { - - var dscResourceResults = from t0 in metadataTable.AsEnumerable() - join t1 in dscResourceTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - DscResources = t1["DscResources"], - }; - - var dscResourcePredicate = PredicateBuilder.New(true); - - DataTable joinedDscResourceTable = dscResourceResults.ToDataTable(); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - dscResourcePredicate = dscResourcePredicate.Or(pkg => pkg.Field("DscResources").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var dscResourcesRowCollection = joinedDscResourceTable.AsEnumerable().Where(dscResourcePredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(dscResourcesRowCollection.ToDataTable()); - } - - if (_type.Contains("RoleCapability", StringComparer.OrdinalIgnoreCase)) - { - - var roleCapabilityResults = from t0 in metadataTable.AsEnumerable() - join t1 in roleCapabilityTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - RoleCapability = t1["RoleCapability"], - }; - - var roleCapabilityPredicate = PredicateBuilder.New(true); - - DataTable joinedRoleCapabilityTable = roleCapabilityResults.ToDataTable(); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - roleCapabilityPredicate = roleCapabilityPredicate.Or(pkg => pkg.Field("RoleCapability").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var roleCapabilitiesRowCollection = joinedRoleCapabilityTable.AsEnumerable().Where(roleCapabilityPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(roleCapabilitiesRowCollection.ToDataTable()); - } - } - - - - // We'll build the rest of the predicate-- ie the portions of the predicate that do not rely on datatables - predicate = predicate.Or(BuildPredicate(repositoryName)); - - - // we want to uniquely add datarows into the table - // if queryTable is empty, we'll just query upon the metadata table - if (queryTable == null || queryTable.Rows.Count == 0) - { - queryTable = metadataTable; - } - - // final results -- All the appropriate pkgs with these tags - var queryTableRowCollection = queryTable.AsEnumerable().Where(predicate).Select(p => p); - - // ensure distinct by key - var finalQueryResults = queryTableRowCollection.AsEnumerable().DistinctBy(pkg => pkg.Field("Key")); - - // Add row collection to final table to be queried - // queryTable.Merge(distinctQueryTableRowCollection.ToDataTable()); - - - - /// ignore-- testing. - //if ((queryTable == null) || (queryTable.Rows.Count == 0) && (((_type == null) || (_type.Contains("Module", StringComparer.OrdinalIgnoreCase) || _type.Contains("Script", StringComparer.OrdinalIgnoreCase))) && ((_tags == null) || (_tags.Length == 0)))) - //{ - // queryTable = metadataTable; - //} - - - List> allFoundPkgs = new List>(); - allFoundPkgs.Add(finalQueryResults); - - // Need to handle includeDependencies - if (_includeDependencies) - { - foreach (var pkg in finalQueryResults) - { - //allFoundPkgs.Add(DependencyFinder(finalQueryResults, dependenciesTable)); - } - } - - IEnumerable flattenedFoundPkgs = (IEnumerable)allFoundPkgs.Flatten(); - - // (IEnumerable) - return flattenedFoundPkgs; - } - - - - - /*********************** come back to this - private IEnumerable DependencyFinder(IEnumerable finalQueryResults, DataTable dependenciesTable ) - { - List> foundDependencies = new List>(); - - var queryResultsDT = finalQueryResults.ToDataTable(); - - //var dependencyResults = from t0 in metadataTable.AsEnumerable() - var dependencyResults = from t0 in queryResultsDT.AsEnumerable() - join t1 in dependenciesTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - Dependencies = (Dependency)t1["Dependencies"], - }; - - var dependencyPredicate = PredicateBuilder.New(true); - - DataTable joinedDependencyTable = dependencyResults.ToDataTable(); - - // Build predicate by combining names of dependencies searches with 'or' - - // public string Name { get; set; } - // public string MinimumVersion { get; set; } - // public string MaximumVersion { get; set; } - - - - // for each pkg that was found, check to see if it has a dep - foreach (var pkg in dependencyResults) - { - // because it's an ienumerable, we need to pull out the pkg itself to access its properties, but there is only a 'default' option - if (!string.IsNullOrEmpty(pkg.Dependencies.Name)) - { - // you could just add the data row - foundDependencies.Add((IEnumerable) pkg); - } - - // and then check to make sure dep name/version exists within the cache (via the metadata table) - // call helper recursively - // (IEnumerable finalQueryResults, DataTable dependenciesTable ) - DependencyFinder(pkg, dependencyResults, dependenciesTable) - - var roleCapabilityPredicate = PredicateBuilder.New(true); - - DataTable joinedRoleCapabilityTable = roleCapabilityResults.ToDataTable(); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - roleCapabilityPredicate = roleCapabilityPredicate.Or(pkg => pkg.Field("RoleCapability").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var roleCapabilitiesRowCollection = joinedRoleCapabilityTable.AsEnumerable().Where(roleCapabilityPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(roleCapabilitiesRowCollection.ToDataTable()); - } - - // final results -- All the - var dependencies = joinedDependencyTable.AsEnumerable().Where(dependencyPredicate).Select(p => p); - - return - } - ***************/ - - - private ExpressionStarter BuildPredicate(string repository) - { - //NuGetVersion nugetVersion0; - var predicate = PredicateBuilder.New(true); - - if (_type != null) - { - var typePredicate = PredicateBuilder.New(true); - - if (_type.Contains("Script", StringComparer.OrdinalIgnoreCase)) - { - typePredicate = typePredicate.Or(pkg => pkg.Field("Type").Equals("Script")); - } - if (_type.Contains("Module", StringComparer.OrdinalIgnoreCase)) - { - typePredicate = typePredicate.Or(pkg => pkg.Field("Type").Equals("Module")); - } - predicate.And(typePredicate); - - } - - ExpressionStarter starter2 = PredicateBuilder.New(true); - if (_moduleName != null) - { - predicate = predicate.And(pkg => pkg.Field("Name").Equals(_moduleName)); - } - - if ((_type == null) || ((_type.Length == 0) || !(_type.Contains("Module", StringComparer.OrdinalIgnoreCase) || _type.Contains("Script", StringComparer.OrdinalIgnoreCase)))) - { - var typeNamePredicate = PredicateBuilder.New(true); - foreach (string name in _name) - { - - //// ? - typeNamePredicate = typeNamePredicate.Or(pkg => pkg.Field("Type").Equals("Script")); - } - } - - - // cache will only contain the latest stable and latest prerelease of each package - if (_version != null) - { - - NuGetVersion nugetVersion; - - //VersionRange versionRange = VersionRange.Parse(version); - - if (NuGetVersion.TryParse(_version, out nugetVersion)) - { - predicate = predicate.And(pkg => pkg.Field("Version").Equals(nugetVersion)); - } - - - - - } - if (!_prerelease) - { - predicate = predicate.And(pkg => pkg.Field("IsPrerelease").Equals("false")); // consider checking if it IS prerelease - } - return predicate; - } - - - - - - - - - - private List> FindPackagesFromSourceHelper(string repositoryUrl, string name, PackageSearchResource pkgSearchResource, PackageMetadataResource pkgMetadataResource, SearchFilter searchFilter, SourceCacheContext srcContext) - { - - List> foundPackages = new List>(); - //IEnumerable foundPackages; - List> filteredFoundPkgs = new List>(); - - // If module name is specified, use that as the name for the pkg to search for - if (_moduleName != null) - { - // may need to take 1 - foundPackages.Add(pkgMetadataResource.GetMetadataAsync(_moduleName, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - //foundPackages = pkgMetadataResource.GetMetadataAsync(_moduleName, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - else if (name != null) - { - // If a resource name is specified, search for that particular pkg name - // search for specific pkg name - if (!name.Contains("*")) - { - foundPackages.Add(pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - //foundPackages = pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - // search for range of pkg names - else - { - // TODO: follow up on this - //foundPackages.Add(pkgSearchResource.SearchAsync(name, searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - - name = name.Equals("*") ? "" : name; // can't use * in v3 protocol - var wildcardPkgs = pkgSearchResource.SearchAsync(name, searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - - // If not searching for *all* packages - if (!name.Equals("") && !name[0].Equals('*')) - { - char[] wildcardDelimiter = new char[] { '*' }; - var tokenizedName = name.Split(wildcardDelimiter, StringSplitOptions.RemoveEmptyEntries); - - //var startsWithWildcard = name[0].Equals('*') ? true : false; - //var endsWithWildcard = name[name.Length-1].Equals('*') ? true : false; - - // 1) *owershellge* - if (name.StartsWith("*") && name.EndsWith("*")) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.Contains(tokenizedName[0]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove(name); - } - // .Where(p => versionRange.Satisfies(p.Identity.Version)) - // .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - - } - // 2) *erShellGet - else if (name.StartsWith("*")) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.EndsWith(tokenizedName[0]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove(name); - } - } - // if 1) PowerShellG* - else if (name.EndsWith("*")) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.StartsWith(tokenizedName[0]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove(name); - } - } - // 3) Power*Get - else if (tokenizedName.Length == 2) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.StartsWith(tokenizedName[0]) && p.Identity.Id.EndsWith(tokenizedName[1]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove("*"); - } - } - } - else - { - foundPackages.Add(wildcardPkgs); - pkgsLeftToFind.Remove("*"); - } - - - } - } - else - { - /* can probably get rid of this */ - foundPackages.Add(pkgSearchResource.SearchAsync("", searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - //foundPackages = pkgSearchResource.SearchAsync("", searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - - - - - // Check version first to narrow down the number of pkgs before potential searching through tags - if (_version != null) - { - - if (_version.Equals("*")) - { - // this is all that's needed if version == "*" (I think) - /* - if (repositoryUrl.Contains("api.nuget.org") || repositoryUrl.StartsWith("file:///")) - { - // need to reverse the order of the informaiton returned when using nuget.org v3 protocol - filteredFoundPkgs.Add(pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult().Reverse()); - } - else - { - filteredFoundPkgs.Add(pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - } - */ - // ensure that the latst version is returned first (the ordering of versions differ - filteredFoundPkgs.Add(pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult().OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - } - else - { - // try to parse into a singular NuGet version - NuGetVersion specificVersion; - NuGetVersion.TryParse(_version, out specificVersion); - - foundPackages.RemoveAll(p => true); - VersionRange versionRange = null; - - if (specificVersion != null) - { - // exact version - versionRange = new VersionRange(specificVersion, true, specificVersion, true, null, null); - } - else - { - // maybe try catch this - // check if version range - versionRange = VersionRange.Parse(_version); - - } - - - - // Search for packages within a version range - // ensure that the latst version is returned first (the ordering of versions differ - // test wth Find-PSResource 'Carbon' -Version '[,2.4.0)' - foundPackages.Add(pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult() - .Where(p => versionRange.Satisfies(p.Identity.Version)) - .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - - // TODO: TEST AFTER CHANGES - // choose the most recent version -- it's not doing this right now - //int toRemove = foundPackages.First().Count() - 1; - //var singlePkg = (System.Linq.Enumerable.SkipLast(foundPackages.FirstOrDefault(), toRemove)); - var pkgList = foundPackages.FirstOrDefault(); - var singlePkg = Enumerable.Repeat(pkgList.FirstOrDefault(), 1); - - filteredFoundPkgs.Add(singlePkg); - } - } - else // version is null - { - // if version is null, but there we want to return multiple packages (muliple names), skip over this step of removing all but the lastest package/version: - if ((name != null && !name.Contains("*")) || _moduleName != null) - { - // choose the most recent version -- it's not doing this right now - int toRemove = foundPackages.First().Count() - 1; - - // var result = ((IEnumerable)firstPkg).Cast(); - // var bleh = foundPackages.FirstOrDefault().(System.Linq.Enumerable.SkipLast(foundPackages.FirstOrDefault(), 20)); - var pkgList = foundPackages.FirstOrDefault(); - var singlePkg = Enumerable.Repeat(pkgList.FirstOrDefault(), 1); - - - filteredFoundPkgs.Add(singlePkg); - } - else - { - filteredFoundPkgs = foundPackages; - } - } - - - - - // TAGS - /// should move this to the last thing that gets filtered - char[] delimiter = new char[] { ' ', ',' }; - var flattenedPkgs = filteredFoundPkgs.Flatten().ToList(); - if (_tags != null) - { - // clear filteredfoundPkgs because we'll just be adding back the pkgs we we - filteredFoundPkgs.RemoveAll(p => true); - var pkgsFilteredByTags = new List(); - - foreach (IPackageSearchMetadata p in flattenedPkgs) - { - // Enumerable.ElementAt(0) - var tagArray = p.Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); - - foreach (string t in _tags) - { - // if the pkg contains one of the tags we're searching for - if (tagArray.Contains(t, StringComparer.OrdinalIgnoreCase)) - { - pkgsFilteredByTags.Add(p); - } - } - } - // make sure just adding one pkg if not * versions - if (_version != "*") - { - filteredFoundPkgs.Add(pkgsFilteredByTags.DistinctBy(p => p.Identity.Id)); - } - else - { - // if we want all version, make sure there's only one package id/version in the returned list. - filteredFoundPkgs.Add(pkgsFilteredByTags.DistinctBy(p => p.Identity.Version)); - } - } - - - - - // optimizes searcching by - if ((_type != null || !filteredFoundPkgs.Flatten().Any()) && pkgsLeftToFind.Any() && !_name.Contains("*")) - { - //if ((_type.Contains("Module") || _type.Contains("Script")) && !_type.Contains("DscResource") && !_type.Contains("Command") && !_type.Contains("RoleCapability")) - if (_type == null || _type.Contains("DscResource") || _type.Contains("Command") || _type.Contains("RoleCapability")) - { - - if (!filteredFoundPkgs.Flatten().Any()) - { - filteredFoundPkgs.Add(pkgSearchResource.SearchAsync("", searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - } - - var tempList = (FilterPkgsByResourceType(filteredFoundPkgs)); - filteredFoundPkgs.RemoveAll(p => true); - - filteredFoundPkgs.Add(tempList); - } - - } - // else type == null - - - - - - - - // Search for dependencies - if (_includeDependencies && filteredFoundPkgs.Any()) - { - List> foundDependencies = new List>(); - - // need to parse the depenency and version and such - var filteredFoundPkgsFlattened = filteredFoundPkgs.Flatten(); - foreach (IPackageSearchMetadata pkg in filteredFoundPkgsFlattened) - { - // need to improve this later - // this function recursively finds all dependencies - // change into an ieunumerable (helpful for the finddependenciesfromsource function) - - foundDependencies.AddRange(FindDependenciesFromSource(Enumerable.Repeat(pkg, 1), pkgMetadataResource, srcContext)); - } - - filteredFoundPkgs.AddRange(foundDependencies); - } - - // return foundPackages; - return filteredFoundPkgs; - } - - - - - private List> FindDependenciesFromSource(IEnumerable pkg, PackageMetadataResource pkgMetadataResource, SourceCacheContext srcContext) - { - /// dependency resolver - /// - /// this function will be recursively called - /// - /// call the findpackages from source helper (potentially generalize this so it's finding packages from source or cache) - /// - List> foundDependencies = new List>(); - - // 1) check the dependencies of this pkg - // 2) for each dependency group, search for the appropriate name and version - // a dependency group are all the dependencies for a particular framework - // first or default because we need this pkg to be an ienumerable (so we don't need to be doing strange object conversions) - foreach (var dependencyGroup in pkg.FirstOrDefault().DependencySets) - { - - //dependencyGroup.TargetFramework - //dependencyGroup. - - foreach (var pkgDependency in dependencyGroup.Packages) - { - - // 2.1) check that the appropriate pkg dependencies exist - // returns all versions from a single package id. - var dependencies = pkgMetadataResource.GetMetadataAsync(pkgDependency.Id, _prerelease, true, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - - // then 2.2) check if the appropriate verion range exists (if version exists, then add it to the list to return) - - VersionRange versionRange = null; - try - { - versionRange = VersionRange.Parse(pkgDependency.VersionRange.OriginalString); - } - catch - { - Console.WriteLine("Error parsing version range"); - } - - - - // choose the most recent version - int toRemove = dependencies.Count() - 1; - - // if no version/version range is specified the we just return the latest version - var depPkgToReturn = (versionRange == null ? - dependencies.FirstOrDefault() : - dependencies.Where(v => versionRange.Satisfies(v.Identity.Version)).FirstOrDefault()); - - - - // using the repeat function to convert the IPackageSearchMetadata object into an enumerable. - foundDependencies.Add(Enumerable.Repeat(depPkgToReturn, 1)); - - // 3) search for any dependencies the pkg has - foundDependencies.AddRange(FindDependenciesFromSource(Enumerable.Repeat(depPkgToReturn, 1), pkgMetadataResource, srcContext)); - } - } - - // flatten after returning - return foundDependencies; - } - - - - - - - - - - - private List FilterPkgsByResourceType(List> filteredFoundPkgs) - { - - - char[] delimiter = new char[] { ' ', ',' }; - - // If there are any packages that were filtered by tags, we'll continue to filter on those packages, otherwise, we'll filter on all the packages returned from the search - var flattenedPkgs = filteredFoundPkgs.Flatten(); - - var pkgsFilteredByResource = new List(); - - // if the type is null, we'll set it to check for everything except modules and scripts, since those types were already checked. - _type = _type == null ? new string[] { "DscResource", "RoleCapability", "Command" } : _type; - string[] pkgsToFind = new string[5]; - pkgsLeftToFind.CopyTo(pkgsToFind); - - foreach (IPackageSearchMetadata pkg in flattenedPkgs) - { - // Enumerable.ElementAt(0) - var tagArray = pkg.Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); - - - // check modules and scripts here ?? - - foreach (var tag in tagArray) - { - - - // iterate through type array - foreach (var resourceType in _type) - { - - switch (resourceType) - { - case "Module": - if (tag.Equals("PSModule")) - { - pkgsFilteredByResource.Add(pkg); - } - break; - - case "Script": - if (tag.Equals("PSScript")) - { - pkgsFilteredByResource.Add(pkg); - } - break; - - case "Command": - if (tag.StartsWith("PSCommand_")) - { - foreach (var resourceName in pkgsToFind) - { - if (tag.Equals("PSCommand_" + resourceName, StringComparison.OrdinalIgnoreCase)) - { - pkgsFilteredByResource.Add(pkg); - pkgsLeftToFind.Remove(resourceName); - - } - } - } - break; - - case "DscResource": - if (tag.StartsWith("PSDscResource_")) - { - foreach (var resourceName in pkgsToFind) - { - if (tag.Equals("PSDscResource_" + resourceName, StringComparison.OrdinalIgnoreCase)) - { - pkgsFilteredByResource.Add(pkg); - pkgsLeftToFind.Remove(resourceName); - } - } - } - break; - - case "RoleCapability": - if (tag.StartsWith("PSRoleCapability_")) - { - foreach (var resourceName in pkgsToFind) - { - if (tag.Equals("PSRoleCapability_" + resourceName, StringComparison.OrdinalIgnoreCase)) - { - pkgsFilteredByResource.Add(pkg); - pkgsLeftToFind.Remove(resourceName); - } - } - } - break; - } - - } - } - } - - - - return pkgsFilteredByResource.DistinctBy(p => p.Identity.Id).ToList(); - - } - - - - - - - - - - - - - - - private static async Task GetCatalogIndexUrlAsync(string sourceUrl) - { - // This code uses the NuGet client SDK, which are the libraries used internally by the official - // NuGet client. - var sourceRepository = NuGet.Protocol.Core.Types.Repository.Factory.GetCoreV3(sourceUrl); - var serviceIndex = await sourceRepository.GetResourceAsync(); - var catalogIndexUrl = serviceIndex.GetServiceEntryUri("Catalog/3.0.0"); - - - - return catalogIndexUrl; - } - - - - /// Modified this - private static DateTime GetCursor() - { - /* - try - { - var cursorString = File.ReadAllText(CursorFileName); - var cursor = JsonConvert.DeserializeObject(cursorString); - var cursorValue = cursor.GetAsync().GetAwaiter().GetResult().GetValueOrDefault(); - DateTime cursorValueDateTime = DateTime.MinValue; - if (cursorValue != null) - { - cursorValueDateTime = cursorValue.DateTime; - } - Console.WriteLine($"Read cursor value: {cursorValueDateTime}."); - return cursorValueDateTime; - } - catch (FileNotFoundException) - { - */ - var value = DateTime.MinValue; - Console.WriteLine($"No cursor found. Defaulting to {value}."); - return value; - // } - } - -/*** - private static void ProcessCatalogLeaf(CatalogLeafItem leaf) - { - // Here, you can do whatever you want with each catalog item. If you want the full metadata about - // the catalog leaf, you can use the leafItem.Url property to fetch the full leaf document. In this case, - // we'll just keep it simple and output the details about the leaf that are included in the catalog page. - // example: Console.WriteLine($"{leaf.CommitTimeStamp}: {leaf.Id} {leaf.Version} (type is {leaf.Type})"); - - Console.WriteLine($"{leaf.CommitTimestamp}: {leaf.PackageId} {leaf.PackageVersion} (type is {leaf.Type})"); - } - - private static void SetCursor(DateTime value) - { - Console.WriteLine($"Writing cursor value: {value}."); - var cursorString = JsonConvert.SerializeObject(new Cursor { Value = value }); - File.WriteAllText(CursorFileName, cursorString); - } -***/ - - - - } - - /* - public class Cursor - { - [JsonProperty("value")] - public DateTime Value { get; set; } - } - */ -} diff --git a/srcOld/code/FindPSResource.cs b/srcOld/code/FindPSResource.cs deleted file mode 100644 index 849f3390e..000000000 --- a/srcOld/code/FindPSResource.cs +++ /dev/null @@ -1,1495 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using System; -using System.Diagnostics; -using System.Management.Automation; -using System.Collections.Generic; -using NuGet.Configuration; -using NuGet.Common; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using System.Threading; -using LinqKit; -using MoreLinq.Extensions; -using NuGet.Versioning; -using System.Data; -using System.Linq; -using System.Net; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using System.Net.Http; -using System.IO; -using System.Threading.Tasks; -using Newtonsoft.Json; -using static System.Environment; - - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - - /// - /// The Register-PSResourceRepository cmdlet registers the default repository for PowerShell modules. - /// After a repository is registered, you can reference it from the Find-PSResource, Install-PSResource, and Publish-PSResource cmdlets. - /// The registered repository becomes the default repository in Find-Module and Install-Module. - /// It returns nothing. - /// - - [Cmdlet(VerbsCommon.Find, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class FindPSResource : PSCmdlet - { - // private string PSGalleryRepoName = "PSGallery"; - - /// - /// Specifies the desired name for the resource to be searched. - /// - [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name = new string[0]; - - /// - /// Specifies the type of the resource to be searched for. - /// - [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - [ValidateSet(new string[] { "Module", "Script", "DscResource", "RoleCapability", "Command" })] - public string[] Type - { - get - { return _type; } - - set - { _type = value; } - } - private string[] _type; - - /// - /// Specifies the version or version range of the package to be searched for - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Version - { - get - { return _version; } - - set - { _version = value; } - } - - private string _version; - - /// - /// Specifies to search for prerelease resources. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter Prerelease - { - get - { return _prerelease; } - - set - { _prerelease = value; } - } - - private SwitchParameter _prerelease; - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string ModuleName - { - get - { return _moduleName; } - - set - { _moduleName = value; } - } - private string _moduleName; - - /// - /// Specifies the type of the resource to be searched for. - /// - [Parameter(ValueFromPipeline = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNull] - public string[] Tags - { - get - { return _tags; } - - set - { _tags = value; } - } - private string[] _tags; - - /// - /// Specify which repositories to search in. - /// - [ValidateNotNullOrEmpty] - [Parameter(ValueFromPipeline = true, ParameterSetName = "NameParameterSet")] - public string[] Repository - { - get { return _repository; } - - set { _repository = value; } - } - private string[] _repository; - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - public PSCredential Credential - { - get - { return _credential; } - - set - { _credential = value; } - } - private PSCredential _credential; - - /// - /// Specifies to return any dependency packages. - /// Currently only used when name param is specified. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - public SwitchParameter IncludeDependencies - { - get { return _includeDependencies; } - - set { _includeDependencies = value; } - } - private SwitchParameter _includeDependencies; - - - - - // This will be a list of all the repository caches - public static readonly List RepoCacheFileName = new List(); - // Temporarily store cache in this path for testing purposes - public static readonly string RepositoryCacheDir = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet", "RepositoryCache"); - //public static readonly string RepositoryCacheDir = @"%APPDATA%/PowerShellGet/repositorycache";//@"%APPDTA%\NuGet"; - //private readonly object p; - - // Define the cancellation token. - CancellationTokenSource source; - CancellationToken cancellationToken; - List pkgsLeftToFind; - private const string CursorFileName = "cursor.json"; - - /// - /// - protected override void ProcessRecord() - { - source = new CancellationTokenSource(); - cancellationToken = source.Token; - - - - var r = new RespositorySettings(); - var listOfRepositories = r.Read(_repository); - - var returnedPkgsFound = new List>(); - pkgsLeftToFind = _name.ToList(); - foreach (var repoName in listOfRepositories) - { - WriteDebug(string.Format("Searching in repository '{0}'", repoName.Properties["Name"].Value.ToString())); - // We'll need to use the catalog reader when enumerating through all packages under v3 protocol. - // if using v3 endpoint and there's no exact name specified (ie no name specified or a name with a wildcard is specified) - if (repoName.Properties["Url"].Value.ToString().EndsWith("/v3/index.json") && - (_name.Length == 0 || _name.Any(n => n.Contains("*"))))//_name.Contains("*"))) /// TEST THIS!!!!!!! - { - this.WriteWarning("This functionality is not yet implemented"); - // right now you can use wildcards with an array of names, ie -name "Az*", "PS*", "*Get", will take a hit performance wise, though. - // TODO: add wildcard condition here - //ProcessCatalogReader(repoName.Properties["Name"].Value.ToString(), repoName.Properties["Url"].Value.ToString()); - } - - - - // if it can't find the pkg in one repository, it'll look in the next one in the list - // returns any pkgs found, and any pkgs that weren't found - returnedPkgsFound.AddRange(FindPackagesFromSource(repoName.Properties["Name"].Value.ToString(), repoName.Properties["Url"].Value.ToString(), cancellationToken)); - - - // Flatten returned pkgs before displaying output returnedPkgsFound.Flatten().ToList()[0] - var flattenedPkgs = returnedPkgsFound.Flatten(); - // flattenedPkgs.ToList(); - - if (flattenedPkgs.Any() && flattenedPkgs.First() != null) - { - foreach (IPackageSearchMetadata pkg in flattenedPkgs) - { - //WriteObject(pkg); - - - PSObject pkgAsPSObject = new PSObject(); - pkgAsPSObject.Members.Add(new PSNoteProperty("Name", pkg.Identity.Id)); - // Version.Version ensures type is System.Version instead of type NuGetVersion - pkgAsPSObject.Members.Add(new PSNoteProperty("Version", pkg.Identity.Version.Version)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repoName.Properties["Name"].Value.ToString())); - pkgAsPSObject.Members.Add(new PSNoteProperty("Description", pkg.Description)); - - WriteObject(pkgAsPSObject); - - } - } - - // reset found packages - returnedPkgsFound.Clear(); - - // if we need to search all repositories, we'll continue, otherwise we'll just return - if (!pkgsLeftToFind.Any()) - { - break; - } - - - - } // end of foreach - - - - } - -/*** - public void ProcessCatalogReader(string repoName, string sourceUrl) - { - - // test initalizing a cursor see: https://docs.microsoft.com/en-us/nuget/guides/api/query-for-all-published-packages - // we want all packages published from the beginning of time - // DateTime cursor = DateTime.MinValue; - - - - // Define a lower time bound for leaves to fetch. This exclusive minimum time bound is called the cursor. - //var cursor = DateTime.MinValue; /// come back to this GetCursor(); - var cursor = GetCursor(); // come back to this - - // Discover the catalog index URL from the service index. - var catalogIndexUrl = GetCatalogIndexUrlAsync(sourceUrl).GetAwaiter().GetResult(); - - - var httpClient = new HttpClient(); - - // Download the catalog index and deserialize it. - var indexString = httpClient.GetStringAsync(catalogIndexUrl).GetAwaiter().GetResult(); - Console.WriteLine($"Fetched catalog index {catalogIndexUrl}."); - var index = JsonConvert.DeserializeObject(indexString); - - // Find all pages in the catalog index that meet the time bound. - - var pageItems = index - .Items - .Where(x => x.CommitTimestamp > cursor); - - var allLeafItems = new List(); - - - foreach (var pageItem in pageItems) /// need to process one page at a time - { - // Download the catalog page and deserialize it. - var pageString = httpClient.GetStringAsync(pageItem.Url).GetAwaiter().GetResult(); - Console.WriteLine($"Fetched catalog page {pageItem.Url}."); - var page = JsonConvert.DeserializeObject(pageString); - - // Find all leaves in the catalog page that meet the time bound. - var pageLeafItems = page - .Items - .Where(x => x.CommitTimestamp > cursor); - - allLeafItems.AddRange(pageLeafItems); - - - // local - FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(sourceUrl); - - LocalPackageSearchResource localResourceSearch = new LocalPackageSearchResource(localResource); - LocalPackageMetadataResource localResourceMetadata = new LocalPackageMetadataResource(localResource); - - SearchFilter filter = new SearchFilter(_prerelease); - SourceCacheContext context = new SourceCacheContext(); - - - - // url - PackageSource source = new PackageSource(sourceUrl); - if (_credential != null) - { - string password = new NetworkCredential(string.Empty, _credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(sourceUrl, _credential.UserName, password, true, null); - } - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - - SourceRepository repository = new SourceRepository(source, provider); - PackageSearchResource resourceSearch = repository.GetResourceAsync().GetAwaiter().GetResult(); - PackageMetadataResource resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); - - - - - // Process all of the catalog leaf items. - Console.WriteLine($"Processing {allLeafItems.Count} catalog leaves."); - foreach (var leafItem in allLeafItems) - { - _version = leafItem.PackageVersion; - - IEnumerable foundPkgs; - if (sourceUrl.StartsWith("file://")) - { - foundPkgs = FindPackagesFromSourceHelper(sourceUrl, leafItem.PackageId, localResourceSearch, localResourceMetadata, filter, context).FirstOrDefault(); - } - else - { - foundPkgs = FindPackagesFromSourceHelper(sourceUrl, leafItem.PackageId, resourceSearch, resourceMetadata, filter, context).FirstOrDefault(); - } - - // var foundPkgsFlattened = foundPkgs.Flatten(); - foreach(var pkg in foundPkgs) - { - // First or default to convert the ienumeraable object into just an IPackageSearchmetadata object - // var pkgToOutput = foundPkgs.FirstOrDefault();//foundPkgs.Cast(); - PSObject pkgAsPSObject = new PSObject(); - pkgAsPSObject.Members.Add(new PSNoteProperty("Name", pkg.Identity.Id)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Version", pkg.Identity.Version)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repoName)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Description", pkg.Description)); - - WriteObject(pkgAsPSObject); - } - - } - - } - - } -*/ - // - public List> FindPackagesFromSource(string repoName, string repositoryUrl, CancellationToken cancellationToken) - { - List> returnedPkgs = new List>(); - - if (repositoryUrl.StartsWith("file://")) - { - - FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(repositoryUrl); - - LocalPackageSearchResource resourceSearch = new LocalPackageSearchResource(localResource); - LocalPackageMetadataResource resourceMetadata = new LocalPackageMetadataResource(localResource); - - SearchFilter filter = new SearchFilter(_prerelease); - SourceCacheContext context = new SourceCacheContext(); - - - if ((_name == null) || (_name.Length == 0)) - { - returnedPkgs.AddRange(FindPackagesFromSourceHelper(repoName, repositoryUrl, null, resourceSearch, resourceMetadata, filter, context)); - } - - foreach(string n in _name){ - if (pkgsLeftToFind.Any()) - { - var foundPkgs = FindPackagesFromSourceHelper(repoName,repositoryUrl, n, resourceSearch, resourceMetadata, filter, context); - if (foundPkgs.Any() && foundPkgs.First().Count() != 0) - { - returnedPkgs.AddRange(foundPkgs); - - - // if the repository is not specified or the repository is specified (but it's not '*'), then we can stop continuing to search for the package - if (_repository == null || !_repository[0].Equals("*")) - { - pkgsLeftToFind.Remove(n); - } - } - } - } - } - else - { - - - - PackageSource source = new PackageSource(repositoryUrl); - if (_credential != null) - { - string password = new NetworkCredential(string.Empty, _credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl, _credential.UserName, password, true, null); - } - - - - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - - SourceRepository repository = new SourceRepository(source, provider); - - - PackageSearchResource resourceSearch = null; - PackageMetadataResource resourceMetadata = null; - try - { - resourceSearch = repository.GetResourceAsync().GetAwaiter().GetResult(); - resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); - } - catch (Exception e){ - WriteDebug("Error retrieving resource from repository: " + e.Message); - return returnedPkgs; - } - - SearchFilter filter = new SearchFilter(_prerelease); - SourceCacheContext context = new SourceCacheContext(); - - if ((_name == null) || (_name.Length == 0)) - { - returnedPkgs.AddRange(FindPackagesFromSourceHelper(repoName, repositoryUrl, null, resourceSearch, resourceMetadata, filter, context)); - } - - foreach (string n in _name) - { - if (pkgsLeftToFind.Any()) - { - var foundPkgs = FindPackagesFromSourceHelper(repoName, repositoryUrl, n, resourceSearch, resourceMetadata, filter, context); - if (foundPkgs.Any() && foundPkgs.First().Count() != 0) - { - returnedPkgs.AddRange(foundPkgs); - - - // if the repository is not specified or the repository is specified (but it's not '*'), then we can stop continuing to search for the package - if (_repository == null || !_repository[0].Equals("*")) - { - pkgsLeftToFind.Remove(n); - } - } - } - } - } - - return returnedPkgs; - } - - - private IEnumerable FindPackageFromCache(string repositoryName) - { - DataSet cachetables = new CacheSettings().CreateDataTable(repositoryName); - - return FindPackageFromCacheHelper(cachetables, repositoryName); - } - - - private IEnumerable FindPackageFromCacheHelper(DataSet cachetables, string repositoryName) - { - DataTable metadataTable = cachetables.Tables[0]; - DataTable tagsTable = cachetables.Tables[1]; - DataTable dependenciesTable = cachetables.Tables[2]; - DataTable commandsTable = cachetables.Tables[3]; - DataTable dscResourceTable = cachetables.Tables[4]; - DataTable roleCapabilityTable = cachetables.Tables[5]; - - DataTable queryTable = new DataTable(); - var predicate = PredicateBuilder.New(true); - - - if ((_tags != null) && (_tags.Length != 0)) - { - - var tagResults = from t0 in metadataTable.AsEnumerable() - join t1 in tagsTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - Tags = t1["Tags"], - }; - - DataTable joinedTagsTable = tagResults.ToDataTable(); - - var tagsPredicate = PredicateBuilder.New(true); - - // Build predicate by combining tag searches with 'or' - foreach (string t in _tags) - { - tagsPredicate = tagsPredicate.Or(pkg => pkg.Field("Tags").Equals(t)); - } - - - // final results -- All the appropriate pkgs with these tags - var tagsRowCollection = joinedTagsTable.AsEnumerable().Where(tagsPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(tagsRowCollection.ToDataTable()); - } - - if (_type != null) - { - if (_type.Contains("Command", StringComparer.OrdinalIgnoreCase)) - { - - var commandResults = from t0 in metadataTable.AsEnumerable() - join t1 in commandsTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - Commands = t1["Commands"], - }; - - DataTable joinedCommandTable = commandResults.ToDataTable(); - - var commandPredicate = PredicateBuilder.New(true); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - commandPredicate = commandPredicate.Or(pkg => pkg.Field("Commands").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var commandsRowCollection = joinedCommandTable.AsEnumerable().Where(commandPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(commandsRowCollection.ToDataTable()); - } - - - if (_type.Contains("DscResource", StringComparer.OrdinalIgnoreCase)) - { - - var dscResourceResults = from t0 in metadataTable.AsEnumerable() - join t1 in dscResourceTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - DscResources = t1["DscResources"], - }; - - var dscResourcePredicate = PredicateBuilder.New(true); - - DataTable joinedDscResourceTable = dscResourceResults.ToDataTable(); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - dscResourcePredicate = dscResourcePredicate.Or(pkg => pkg.Field("DscResources").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var dscResourcesRowCollection = joinedDscResourceTable.AsEnumerable().Where(dscResourcePredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(dscResourcesRowCollection.ToDataTable()); - } - - if (_type.Contains("RoleCapability", StringComparer.OrdinalIgnoreCase)) - { - - var roleCapabilityResults = from t0 in metadataTable.AsEnumerable() - join t1 in roleCapabilityTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - RoleCapability = t1["RoleCapability"], - }; - - var roleCapabilityPredicate = PredicateBuilder.New(true); - - DataTable joinedRoleCapabilityTable = roleCapabilityResults.ToDataTable(); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - roleCapabilityPredicate = roleCapabilityPredicate.Or(pkg => pkg.Field("RoleCapability").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var roleCapabilitiesRowCollection = joinedRoleCapabilityTable.AsEnumerable().Where(roleCapabilityPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(roleCapabilitiesRowCollection.ToDataTable()); - } - } - - - - // We'll build the rest of the predicate-- ie the portions of the predicate that do not rely on datatables - predicate = predicate.Or(BuildPredicate(repositoryName)); - - - // we want to uniquely add datarows into the table - // if queryTable is empty, we'll just query upon the metadata table - if (queryTable == null || queryTable.Rows.Count == 0) - { - queryTable = metadataTable; - } - - // final results -- All the appropriate pkgs with these tags - var queryTableRowCollection = queryTable.AsEnumerable().Where(predicate).Select(p => p); - - // ensure distinct by key - var finalQueryResults = queryTableRowCollection.AsEnumerable().DistinctBy(pkg => pkg.Field("Key")); - - // Add row collection to final table to be queried - // queryTable.Merge(distinctQueryTableRowCollection.ToDataTable()); - - - - /// ignore-- testing. - //if ((queryTable == null) || (queryTable.Rows.Count == 0) && (((_type == null) || (_type.Contains("Module", StringComparer.OrdinalIgnoreCase) || _type.Contains("Script", StringComparer.OrdinalIgnoreCase))) && ((_tags == null) || (_tags.Length == 0)))) - //{ - // queryTable = metadataTable; - //} - - - List> allFoundPkgs = new List>(); - allFoundPkgs.Add(finalQueryResults); - - // Need to handle includeDependencies - if (_includeDependencies) - { - foreach (var pkg in finalQueryResults) - { - //allFoundPkgs.Add(DependencyFinder(finalQueryResults, dependenciesTable)); - } - } - - IEnumerable flattenedFoundPkgs = (IEnumerable)allFoundPkgs.Flatten(); - - // (IEnumerable) - return flattenedFoundPkgs; - } - - - - - /*********************** come back to this - private IEnumerable DependencyFinder(IEnumerable finalQueryResults, DataTable dependenciesTable ) - { - List> foundDependencies = new List>(); - - var queryResultsDT = finalQueryResults.ToDataTable(); - - //var dependencyResults = from t0 in metadataTable.AsEnumerable() - var dependencyResults = from t0 in queryResultsDT.AsEnumerable() - join t1 in dependenciesTable.AsEnumerable() - on t0.Field("Key") equals t1.Field("Key") - select new PackageMetadataAllTables - { - Key = t0["Key"], - Name = t0["Name"], - Version = t0["Version"], - Type = (string)t0["Type"], - Description = t0["Description"], - Author = t0["Author"], - Copyright = t0["Copyright"], - PublishedDate = t0["PublishedDate"], - InstalledDate = t0["InstalledDate"], - UpdatedDate = t0["UpdatedDate"], - LicenseUri = t0["LicenseUri"], - ProjectUri = t0["ProjectUri"], - IconUri = t0["IconUri"], - PowerShellGetFormatVersion = t0["PowerShellGetFormatVersion"], - ReleaseNotes = t0["ReleaseNotes"], - RepositorySourceLocation = t0["RepositorySourceLocation"], - Repository = t0["Repository"], - IsPrerelease = t0["IsPrerelease"], - Dependencies = (Dependency)t1["Dependencies"], - }; - - var dependencyPredicate = PredicateBuilder.New(true); - - DataTable joinedDependencyTable = dependencyResults.ToDataTable(); - - // Build predicate by combining names of dependencies searches with 'or' - - // public string Name { get; set; } - // public string MinimumVersion { get; set; } - // public string MaximumVersion { get; set; } - - - - // for each pkg that was found, check to see if it has a dep - foreach (var pkg in dependencyResults) - { - // because it's an ienumerable, we need to pull out the pkg itself to access its properties, but there is only a 'default' option - if (!string.IsNullOrEmpty(pkg.Dependencies.Name)) - { - // you could just add the data row - foundDependencies.Add((IEnumerable) pkg); - } - - // and then check to make sure dep name/version exists within the cache (via the metadata table) - // call helper recursively - // (IEnumerable finalQueryResults, DataTable dependenciesTable ) - DependencyFinder(pkg, dependencyResults, dependenciesTable) - - var roleCapabilityPredicate = PredicateBuilder.New(true); - - DataTable joinedRoleCapabilityTable = roleCapabilityResults.ToDataTable(); - - // Build predicate by combining names of commands searches with 'or' - // if no name is specified, we'll return all (?) - foreach (string n in _name) - { - roleCapabilityPredicate = roleCapabilityPredicate.Or(pkg => pkg.Field("RoleCapability").Equals(n)); - } - - // final results -- All the appropriate pkgs with these tags - var roleCapabilitiesRowCollection = joinedRoleCapabilityTable.AsEnumerable().Where(roleCapabilityPredicate).Select(p => p); - - // Add row collection to final table to be queried - queryTable.Merge(roleCapabilitiesRowCollection.ToDataTable()); - } - - // final results -- All the - var dependencies = joinedDependencyTable.AsEnumerable().Where(dependencyPredicate).Select(p => p); - - return - } - ***************/ - - - private ExpressionStarter BuildPredicate(string repository) - { - //NuGetVersion nugetVersion0; - var predicate = PredicateBuilder.New(true); - - if (_type != null) - { - var typePredicate = PredicateBuilder.New(true); - - if (_type.Contains("Script", StringComparer.OrdinalIgnoreCase)) - { - typePredicate = typePredicate.Or(pkg => pkg.Field("Type").Equals("Script")); - } - if (_type.Contains("Module", StringComparer.OrdinalIgnoreCase)) - { - typePredicate = typePredicate.Or(pkg => pkg.Field("Type").Equals("Module")); - } - predicate.And(typePredicate); - - } - - ExpressionStarter starter2 = PredicateBuilder.New(true); - if (_moduleName != null) - { - predicate = predicate.And(pkg => pkg.Field("Name").Equals(_moduleName)); - } - - if ((_type == null) || ((_type.Length == 0) || !(_type.Contains("Module", StringComparer.OrdinalIgnoreCase) || _type.Contains("Script", StringComparer.OrdinalIgnoreCase)))) - { - var typeNamePredicate = PredicateBuilder.New(true); - foreach (string name in _name) - { - - //// ? - typeNamePredicate = typeNamePredicate.Or(pkg => pkg.Field("Type").Equals("Script")); - } - } - - - // cache will only contain the latest stable and latest prerelease of each package - if (_version != null) - { - - NuGetVersion nugetVersion; - - //VersionRange versionRange = VersionRange.Parse(version); - - if (NuGetVersion.TryParse(_version, out nugetVersion)) - { - predicate = predicate.And(pkg => pkg.Field("Version").Equals(nugetVersion)); - } - - - - - } - if (!_prerelease) - { - predicate = predicate.And(pkg => pkg.Field("IsPrerelease").Equals("false")); // consider checking if it IS prerelease - } - return predicate; - } - - - - - - - - private List> FindPackagesFromSourceHelper(string repoName, string repositoryUrl, string name, PackageSearchResource pkgSearchResource, PackageMetadataResource pkgMetadataResource, SearchFilter searchFilter, SourceCacheContext srcContext) - { - - List> foundPackages = new List>(); - List> filteredFoundPkgs = new List>(); - List> scriptPkgsNotNeeded = new List>(); - - char[] delimiter = new char[] { ' ', ',' }; - - // If module name is specified, use that as the name for the pkg to search for - if (_moduleName != null) - { - // may need to take 1 - foundPackages.Add(pkgMetadataResource.GetMetadataAsync(_moduleName, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - //foundPackages = pkgMetadataResource.GetMetadataAsync(_moduleName, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - else if (name != null) - { - // If a resource name is specified, search for that particular pkg name - if (!name.Contains("*")) - { - IEnumerable retrievedPkgs = null; - try - { - retrievedPkgs = pkgMetadataResource.GetMetadataAsync(name, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - catch { } - if (retrievedPkgs == null || retrievedPkgs.Count() == 0) - { - this.WriteVerbose(string.Format("'{0}' could not be found in repository '{1}'", name, repoName)); - return foundPackages; - } - else - { - foundPackages.Add(retrievedPkgs); - } - } - // search for range of pkg names - else - { - // TODO: follow up on this - //foundPackages.Add(pkgSearchResource.SearchAsync(name, searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - - name = name.Equals("*") ? "" : name; // can't use * in v3 protocol - var wildcardPkgs = pkgSearchResource.SearchAsync(name, searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - - // If not searching for *all* packages - if (!name.Equals("") && !name[0].Equals('*')) - { - char[] wildcardDelimiter = new char[] { '*' }; - var tokenizedName = name.Split(wildcardDelimiter, StringSplitOptions.RemoveEmptyEntries); - - //var startsWithWildcard = name[0].Equals('*') ? true : false; - //var endsWithWildcard = name[name.Length-1].Equals('*') ? true : false; - - // 1) *owershellge* - if (name.StartsWith("*") && name.EndsWith("*")) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.Contains(tokenizedName[0]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove(name); - } - // .Where(p => versionRange.Satisfies(p.Identity.Version)) - // .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - - } - // 2) *erShellGet - else if (name.StartsWith("*")) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.EndsWith(tokenizedName[0]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove(name); - } - } - // if 1) PowerShellG* - else if (name.EndsWith("*")) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.StartsWith(tokenizedName[0]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove(name); - } - } - // 3) Power*Get - else if (tokenizedName.Length == 2) - { - // filter results - foundPackages.Add(wildcardPkgs.Where(p => p.Identity.Id.StartsWith(tokenizedName[0]) && p.Identity.Id.EndsWith(tokenizedName[1]))); - - if (foundPackages.Flatten().Any()) - { - pkgsLeftToFind.Remove("*"); - } - } - } - else - { - foundPackages.Add(wildcardPkgs); - pkgsLeftToFind.Remove("*"); - } - - - } - } - else - { - /* can probably get rid of this */ - foundPackages.Add(pkgSearchResource.SearchAsync("", searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - //foundPackages = pkgSearchResource.SearchAsync("", searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - - - //use either ModuleName or Name (whichever not null) to prevent id error - var nameVal = name == null ? _moduleName : name; - // Check version first to narrow down the number of pkgs before potentially searching through tags - if (_version != null && nameVal != null) - { - - if (_version.Equals("*")) - { - // ensure that the latst version is returned first (the ordering of versions differ) - - if(_moduleName != null) - { - // perform checks for PSModule before adding to filteredFoundPackages - filteredFoundPkgs.Add(pkgMetadataResource.GetMetadataAsync(nameVal, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult() - .Where(p => p.Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries).Contains("PSModule")) - .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - - scriptPkgsNotNeeded.Add(pkgMetadataResource.GetMetadataAsync(nameVal, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult() - .Where(p => p.Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries).Contains("PSScript")) - .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - - scriptPkgsNotNeeded.RemoveAll(p => true); - } - else - { //name != null - filteredFoundPkgs.Add(pkgMetadataResource.GetMetadataAsync(nameVal, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult().OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - } - } - else - { - // try to parse into a singular NuGet version - NuGetVersion specificVersion; - NuGetVersion.TryParse(_version, out specificVersion); - - foundPackages.RemoveAll(p => true); - VersionRange versionRange = null; - - //todo: fix! when the Version is inputted as "[2.0]" it doesnt get parsed by TryParse() returns null - if (specificVersion != null) - { - // exact version - versionRange = new VersionRange(specificVersion, true, specificVersion, true, null, null); - } - else - { - // maybe try catch this - // check if version range - versionRange = VersionRange.Parse(_version); - - } - // Search for packages within a version range - // ensure that the latst version is returned first (the ordering of versions differ - // test wth Find-PSResource 'Carbon' -Version '[,2.4.0)' - foundPackages.Add(pkgMetadataResource.GetMetadataAsync(nameVal, _prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult() - .Where(p => versionRange.Satisfies(p.Identity.Version)) - .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease)); - - // TODO: TEST AFTER CHANGES - // choose the most recent version -- it's not doing this right now - //int toRemove = foundPackages.First().Count() - 1; - //var singlePkg = (System.Linq.Enumerable.SkipLast(foundPackages.FirstOrDefault(), toRemove)); - var pkgList = foundPackages.FirstOrDefault(); - var singlePkg = Enumerable.Repeat(pkgList.FirstOrDefault(), 1); - - - if(singlePkg != null) - { - if(_moduleName != null) - { - var tags = singlePkg.First().Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); - if(tags.Contains("PSModule")) - { - filteredFoundPkgs.Add(singlePkg); - } - } - else if(_name != null) - { - filteredFoundPkgs.Add(singlePkg); - } - } - } - } - else // version is null - { - // if version is null, but there we want to return multiple packages (muliple names), skip over this step of removing all but the lastest package/version: - if ((name != null && !name.Contains("*")) || _moduleName != null) - { - // choose the most recent version -- it's not doing this right now - int toRemove = foundPackages.First().Count() - 1; - - //to prevent NullException - if(toRemove >= 0) - { - var pkgList = foundPackages.FirstOrDefault(); - var singlePkg = Enumerable.Repeat(pkgList.FirstOrDefault(), 1); - - //if it was a ModuleName then check if the Tag is PSModule and only add then - var tags = singlePkg.First().Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); - if(_moduleName != null){ - if(tags.Contains("PSModule")){ - filteredFoundPkgs.Add(singlePkg); - } - } - else - { // _name != null - filteredFoundPkgs.Add(singlePkg); - } - } - } - else - { //if name not null,but name contains * and version is null - filteredFoundPkgs = foundPackages; - } - } - - - - - // TAGS - /// should move this to the last thing that gets filtered - var flattenedPkgs = filteredFoundPkgs.Flatten().ToList(); - if (_tags != null) - { - // clear filteredfoundPkgs because we'll just be adding back the pkgs we we - filteredFoundPkgs.RemoveAll(p => true); - var pkgsFilteredByTags = new List(); - - foreach (IPackageSearchMetadata p in flattenedPkgs) - { - // Enumerable.ElementAt(0) - var tagArray = p.Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); - - foreach (string t in _tags) - { - // if the pkg contains one of the tags we're searching for - if (tagArray.Contains(t, StringComparer.OrdinalIgnoreCase)) - { - pkgsFilteredByTags.Add(p); - } - } - } - // make sure just adding one pkg if not * versions - if (_version != "*") - { - filteredFoundPkgs.Add(pkgsFilteredByTags.DistinctBy(p => p.Identity.Id)); - } - else - { - // if we want all version, make sure there's only one package id/version in the returned list. - filteredFoundPkgs.Add(pkgsFilteredByTags.DistinctBy(p => p.Identity.Version)); - } - } - - - - - // optimizes searcching by - if ((_type != null || !filteredFoundPkgs.Flatten().Any()) && pkgsLeftToFind.Any() && !_name.Contains("*")) - { - //if ((_type.Contains("Module") || _type.Contains("Script")) && !_type.Contains("DscResource") && !_type.Contains("Command") && !_type.Contains("RoleCapability")) - if (_type == null || _type.Contains("DscResource") || _type.Contains("Command") || _type.Contains("RoleCapability")) - { - - if (!filteredFoundPkgs.Flatten().Any()) - { - filteredFoundPkgs.Add(pkgSearchResource.SearchAsync("", searchFilter, 0, 6000, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult()); - } - - var tempList = (FilterPkgsByResourceType(filteredFoundPkgs)); - filteredFoundPkgs.RemoveAll(p => true); - - filteredFoundPkgs.Add(tempList); - } - - } - // else type == null - - - - - - - - // Search for dependencies - if (_includeDependencies && filteredFoundPkgs.Any()) - { - List> foundDependencies = new List>(); - - // need to parse the depenency and version and such - var filteredFoundPkgsFlattened = filteredFoundPkgs.Flatten(); - foreach (IPackageSearchMetadata pkg in filteredFoundPkgsFlattened) - { - // need to improve this later - // this function recursively finds all dependencies - // change into an ieunumerable (helpful for the finddependenciesfromsource function) - - foundDependencies.AddRange(FindDependenciesFromSource(Enumerable.Repeat(pkg, 1), pkgMetadataResource, srcContext)); - } - - filteredFoundPkgs.AddRange(foundDependencies); - } - - // return foundPackages; - return filteredFoundPkgs; - } - - - - - private List> FindDependenciesFromSource(IEnumerable pkg, PackageMetadataResource pkgMetadataResource, SourceCacheContext srcContext) - { - /// dependency resolver - /// - /// this function will be recursively called - /// - /// call the findpackages from source helper (potentially generalize this so it's finding packages from source or cache) - /// - List> foundDependencies = new List>(); - - // 1) check the dependencies of this pkg - // 2) for each dependency group, search for the appropriate name and version - // a dependency group are all the dependencies for a particular framework - // first or default because we need this pkg to be an ienumerable (so we don't need to be doing strange object conversions) - foreach (var dependencyGroup in pkg.FirstOrDefault().DependencySets) - { - - //dependencyGroup.TargetFramework - //dependencyGroup. - - foreach (var pkgDependency in dependencyGroup.Packages) - { - - // 2.1) check that the appropriate pkg dependencies exist - // returns all versions from a single package id. - var dependencies = pkgMetadataResource.GetMetadataAsync(pkgDependency.Id, _prerelease, true, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - - // then 2.2) check if the appropriate verion range exists (if version exists, then add it to the list to return) - - VersionRange versionRange = null; - - // to ensure a null OriginalString isn't being parsed which will result in an error being thrown and caught - // if OriginalString is null, versionRange will remain null and default version will be installed. - if(pkgDependency.VersionRange.OriginalString != null){ - try - { - versionRange = VersionRange.Parse(pkgDependency.VersionRange.OriginalString); - } - catch - { - Console.WriteLine("Error parsing version range"); - } - } - - - - // choose the most recent version - int toRemove = dependencies.Count() - 1; - - // if no version/version range is specified the we just return the latest version - var depPkgToReturn = (versionRange == null ? - dependencies.FirstOrDefault() : - dependencies.Where(v => versionRange.Satisfies(v.Identity.Version)).FirstOrDefault()); - - - - // using the repeat function to convert the IPackageSearchMetadata object into an enumerable. - foundDependencies.Add(Enumerable.Repeat(depPkgToReturn, 1)); - - // 3) search for any dependencies the pkg has - foundDependencies.AddRange(FindDependenciesFromSource(Enumerable.Repeat(depPkgToReturn, 1), pkgMetadataResource, srcContext)); - } - } - - // flatten after returning - return foundDependencies; - } - - - - - - - - - - - private List FilterPkgsByResourceType(List> filteredFoundPkgs) - { - - - char[] delimiter = new char[] { ' ', ',' }; - - // If there are any packages that were filtered by tags, we'll continue to filter on those packages, otherwise, we'll filter on all the packages returned from the search - var flattenedPkgs = filteredFoundPkgs.Flatten(); - - var pkgsFilteredByResource = new List(); - - // if the type is null, we'll set it to check for everything except modules and scripts, since those types were already checked. - _type = _type == null ? new string[] { "DscResource", "RoleCapability", "Command" } : _type; - string[] pkgsToFind = new string[5]; - pkgsLeftToFind.CopyTo(pkgsToFind); - - foreach (IPackageSearchMetadata pkg in flattenedPkgs) - { - // Enumerable.ElementAt(0) - var tagArray = pkg.Tags.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); - - - // check modules and scripts here ?? - - foreach (var tag in tagArray) - { - - - // iterate through type array - foreach (var resourceType in _type) - { - - switch (resourceType) - { - case "Module": - if (tag.Equals("PSModule")) - { - pkgsFilteredByResource.Add(pkg); - } - break; - - case "Script": - if (tag.Equals("PSScript")) - { - pkgsFilteredByResource.Add(pkg); - } - break; - - case "Command": - if (tag.StartsWith("PSCommand_")) - { - foreach (var resourceName in pkgsToFind) - { - if (tag.Equals("PSCommand_" + resourceName, StringComparison.OrdinalIgnoreCase)) - { - pkgsFilteredByResource.Add(pkg); - pkgsLeftToFind.Remove(resourceName); - - } - } - } - break; - - case "DscResource": - if (tag.StartsWith("PSDscResource_")) - { - foreach (var resourceName in pkgsToFind) - { - if (tag.Equals("PSDscResource_" + resourceName, StringComparison.OrdinalIgnoreCase)) - { - pkgsFilteredByResource.Add(pkg); - pkgsLeftToFind.Remove(resourceName); - } - } - } - break; - - case "RoleCapability": - if (tag.StartsWith("PSRoleCapability_")) - { - foreach (var resourceName in pkgsToFind) - { - if (tag.Equals("PSRoleCapability_" + resourceName, StringComparison.OrdinalIgnoreCase)) - { - pkgsFilteredByResource.Add(pkg); - pkgsLeftToFind.Remove(resourceName); - } - } - } - break; - } - - } - } - } - - - - return pkgsFilteredByResource.DistinctBy(p => p.Identity.Id).ToList(); - - } - - - - - - - - - - - - - -/*** - private static async Task GetCatalogIndexUrlAsync(string sourceUrl) - { - // This code uses the NuGet client SDK, which are the libraries used internally by the official - // NuGet client. - var sourceRepository = NuGet.Protocol.Core.Types.Repository.Factory.GetCoreV3(sourceUrl); - var serviceIndex = await sourceRepository.GetResourceAsync(); - var catalogIndexUrl = serviceIndex.GetServiceEntryUri("Catalog/3.0.0"); - - - - return catalogIndexUrl; - } -*/ - - - /// Modified this - private static DateTime GetCursor() - { - /* - try - { - var cursorString = File.ReadAllText(CursorFileName); - var cursor = JsonConvert.DeserializeObject(cursorString); - var cursorValue = cursor.GetAsync().GetAwaiter().GetResult().GetValueOrDefault(); - DateTime cursorValueDateTime = DateTime.MinValue; - if (cursorValue != null) - { - cursorValueDateTime = cursorValue.DateTime; - } - Console.WriteLine($"Read cursor value: {cursorValueDateTime}."); - return cursorValueDateTime; - } - catch (FileNotFoundException) - { - */ - var value = DateTime.MinValue; - Console.WriteLine($"No cursor found. Defaulting to {value}."); - return value; - // } - } - -/*** - private static void ProcessCatalogLeaf(CatalogLeafItem leaf) - { - // Here, you can do whatever you want with each catalog item. If you want the full metadata about - // the catalog leaf, you can use the leafItem.Url property to fetch the full leaf document. In this case, - // we'll just keep it simple and output the details about the leaf that are included in the catalog page. - // example: Console.WriteLine($"{leaf.CommitTimeStamp}: {leaf.Id} {leaf.Version} (type is {leaf.Type})"); - - Console.WriteLine($"{leaf.CommitTimestamp}: {leaf.PackageId} {leaf.PackageVersion} (type is {leaf.Type})"); - } - - private static void SetCursor(DateTime value) - { - Console.WriteLine($"Writing cursor value: {value}."); - var cursorString = JsonConvert.SerializeObject(new Cursor { Value = value }); - File.WriteAllText(CursorFileName, cursorString); - } -*/ - - - - - } - - - public class Cursor - { - [JsonProperty("value")] - public DateTime Value { get; set; } - } -} diff --git a/srcOld/code/GetHelper.cs b/srcOld/code/GetHelper.cs deleted file mode 100644 index b772a4d1e..000000000 --- a/srcOld/code/GetHelper.cs +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using static System.Environment; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Net; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using System.Threading; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using MoreLinq.Extensions; -using Newtonsoft.Json; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging.Core; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// Find helper class - /// - class GetHelper : PSCmdlet - { - private CancellationToken cancellationToken; - private readonly PSCmdlet cmdletPassedIn; - - - public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - - private string programFilesPath; - private string myDocumentsPath; - - public GetHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) - { - this.cancellationToken = cancellationToken; - this.cmdletPassedIn = cmdletPassedIn; - } - - public List ProcessGetParams(string[] name, string version, bool prerelease, string path) - { - var dirsToSearch = new List(); - - if (path != null) - { - cmdletPassedIn.WriteDebug(string.Format("Provided path is: '{0}'", path)); - dirsToSearch.AddRange(Directory.GetDirectories(path).ToList()); - } - else - { - // PSModules path - var psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - var modulePaths = psModulePath.Split(';'); - - -#if NET472 - programFilesPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "WindowsPowerShell"); - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "WindowsPowerShell"); - -#else - // If PS6+ on Windows - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "PowerShell"); - programFilesPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "PowerShell"); - } - else - { - // Paths are the same for both Linux and MacOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "powershell"); - programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); - } -#endif - cmdletPassedIn.WriteDebug(string.Format("Current user scope path: '{0}'", myDocumentsPath)); - cmdletPassedIn.WriteDebug(string.Format("All users scope path: '{0}'", programFilesPath)); - - /*** Will search first in PSModulePath, then will search in default paths ***/ - - foreach (var modulePath in modulePaths) - { - dirsToSearch.AddRange(Directory.GetDirectories(modulePath).ToList()); - } - - - var pfModulesPath = System.IO.Path.Combine(programFilesPath, "Modules"); - if (Directory.Exists(pfModulesPath)) - { - dirsToSearch.AddRange(Directory.GetDirectories(pfModulesPath).ToList()); - } - - var mdModulesPath = System.IO.Path.Combine(myDocumentsPath, "Modules"); - if (Directory.Exists(mdModulesPath)) - { - dirsToSearch.AddRange(Directory.GetDirectories(mdModulesPath).ToList()); - } - - - var pfScriptsPath = System.IO.Path.Combine(programFilesPath, "Scripts", "InstalledScriptInfos"); - if (Directory.Exists(pfScriptsPath)) - { - dirsToSearch.AddRange(Directory.GetFiles(pfScriptsPath).ToList()); - } - - var mdScriptsPath = System.IO.Path.Combine(myDocumentsPath, "Scripts", "InstalledScriptInfos"); - if (Directory.Exists(mdScriptsPath)) - { - dirsToSearch.AddRange(Directory.GetFiles(mdScriptsPath).ToList()); - } - - - // uniqueify - dirsToSearch = dirsToSearch.Distinct().ToList(); - } - - foreach (var dir in dirsToSearch) - { - cmdletPassedIn.WriteDebug(string.Format("All directories to search: '{0}'", dir)); - } - - // Or a list of the passed in names - if (name != null && !name[0].Equals("*")) - { - var nameLowerCased = new List(); - var scriptXMLnames = new List(); - Array.ForEach(name, n => nameLowerCased.Add(n.ToLower())); - Array.ForEach(name, n => scriptXMLnames.Add((n + "_InstalledScriptInfo.xml").ToLower())); - - dirsToSearch = dirsToSearch.FindAll(p => (nameLowerCased.Contains(new DirectoryInfo(p).Name.ToLower()) - || scriptXMLnames.Contains((System.IO.Path.GetFileName(p)).ToLower()))); - - cmdletPassedIn.WriteDebug(dirsToSearch.Any().ToString()); - } - - // try to parse into a specific NuGet version - VersionRange versionRange = null; - if (version != null) - { - NuGetVersion specificVersion; - NuGetVersion.TryParse(version, out specificVersion); - - if (specificVersion != null) - { - // exact version - versionRange = new VersionRange(specificVersion, true, specificVersion, true, null, null); - cmdletPassedIn.WriteDebug(string.Format("A specific version, '{0}', is specified", versionRange.ToString())); - - } - else - { - // check if version range - versionRange = VersionRange.Parse(version); - cmdletPassedIn.WriteDebug(string.Format("A version range, '{0}', is specified", versionRange.ToString())); - - } - } - - List installedPkgsToReturn = new List(); - - //2) use above list to check - // if the version specificed is a version range - if (versionRange != null) - { - foreach (var pkgPath in dirsToSearch) - { - cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); - var versionsDirs = Directory.GetDirectories(pkgPath); - - foreach (var versionPath in versionsDirs) - { - cmdletPassedIn.WriteDebug(string.Format("Searching through package version path: '{0}'", versionPath)); - NuGetVersion dirAsNugetVersion; - var dirInfo = new DirectoryInfo(versionPath); - NuGetVersion.TryParse(dirInfo.Name, out dirAsNugetVersion); - cmdletPassedIn.WriteDebug(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); - - if (versionRange.Satisfies(dirAsNugetVersion)) - { - // just search scripts paths - if (pkgPath.ToLower().Contains("Scripts")) - { - if (File.Exists(pkgPath)) - { - installedPkgsToReturn.Add(pkgPath); - } - } - else - { - // modules paths - versionsDirs = Directory.GetDirectories(pkgPath); - cmdletPassedIn.WriteDebug(string.Format("Getting sub directories from : '{0}'", pkgPath)); - - // Check if the pkg path actually has version sub directories. - if (versionsDirs.Length != 0) - { - Array.Sort(versionsDirs, StringComparer.OrdinalIgnoreCase); - Array.Reverse(versionsDirs); - - var pkgXmlFilePath = System.IO.Path.Combine(versionsDirs.First(), "PSGetModuleInfo.xml"); - - // TODO: check if this xml file exists, if it doesn't check if it exists in a previous version - cmdletPassedIn.WriteDebug(string.Format("Found module XML: '{0}'", pkgXmlFilePath)); - - installedPkgsToReturn.Add(pkgXmlFilePath); - } - } - - installedPkgsToReturn.Add(versionPath); - } - } - } - } - else - { - cmdletPassedIn.WriteDebug("No version provided-- check each path for the requested package"); - // if no version is specified, just get the latest version - foreach (var pkgPath in dirsToSearch) - { - cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); - - // just search scripts paths - if (pkgPath.ToLower().Contains("scripts")) - { - if (File.Exists(pkgPath)) //check to make sure properly formatted - { - installedPkgsToReturn.Add(pkgPath); - } - } - else - { - // modules paths - string[] versionsDirs = new string[0]; - - versionsDirs = Directory.GetDirectories(pkgPath); - - // Check if the pkg path actually has version sub directories. - if (versionsDirs.Length != 0) - { - Array.Sort(versionsDirs, StringComparer.OrdinalIgnoreCase); - Array.Reverse(versionsDirs); - - var pkgXmlFilePath = System.IO.Path.Combine(versionsDirs.First(), "PSGetModuleInfo.xml"); - - // TODO: check if this xml file exists, if it doesn't check if it exists in a previous version - cmdletPassedIn.WriteDebug(string.Format("Found package XML: '{0}'", pkgXmlFilePath)); - installedPkgsToReturn.Add(pkgXmlFilePath); - } - } - } - } - - - // Flatten returned pkgs before displaying output returnedPkgsFound.Flatten().ToList()[0] - var flattenedPkgs = installedPkgsToReturn.Flatten(); - - - - List foundInstalledPkgs = new List(); - - foreach (string xmlFilePath in flattenedPkgs) - { - cmdletPassedIn.WriteDebug(string.Format("Reading package metadata from: '{0}'", xmlFilePath)); - - // Open xml and read metadata from it - if (File.Exists(xmlFilePath)) - { - ReadOnlyPSMemberInfoCollection nameInfo; - ReadOnlyPSMemberInfoCollection versionInfo; - ReadOnlyPSMemberInfoCollection typeInfo; - ReadOnlyPSMemberInfoCollection descriptionInfo; - ReadOnlyPSMemberInfoCollection authorInfo; - ReadOnlyPSMemberInfoCollection companyNameInfo; - ReadOnlyPSMemberInfoCollection copyrightInfo; - ReadOnlyPSMemberInfoCollection publishedDateInfo; - ReadOnlyPSMemberInfoCollection installedDateInfo; - ReadOnlyPSMemberInfoCollection updatedDateInfo; - ReadOnlyPSMemberInfoCollection licenseUriInfo; - ReadOnlyPSMemberInfoCollection projectUriInfo; - ReadOnlyPSMemberInfoCollection iconUriInfo; - ReadOnlyPSMemberInfoCollection tagsInfo; - ReadOnlyPSMemberInfoCollection includesInfo; - ReadOnlyPSMemberInfoCollection powerShellGetFormatVersionInfo; - ReadOnlyPSMemberInfoCollection releaseNotesInfo; - ReadOnlyPSMemberInfoCollection dependenciesInfo; - ReadOnlyPSMemberInfoCollection repositorySourceLocationInfo; - ReadOnlyPSMemberInfoCollection repositoryInfo; - ReadOnlyPSMemberInfoCollection additionalMetadataInfo; - ReadOnlyPSMemberInfoCollection installedLocationInfo; - - - //var isPrelease = false; - using (StreamReader sr = new StreamReader(xmlFilePath)) - { - - string text = sr.ReadToEnd(); - var deserializedObj = (PSObject)PSSerializer.Deserialize(text); - - nameInfo = deserializedObj.Properties.Match("Name"); - versionInfo = deserializedObj.Properties.Match("Version"); - typeInfo = deserializedObj.Properties.Match("Type"); - descriptionInfo = deserializedObj.Properties.Match("Description"); - authorInfo = deserializedObj.Properties.Match("Author"); - companyNameInfo = deserializedObj.Properties.Match("CompanyName"); - copyrightInfo = deserializedObj.Properties.Match("Copyright"); - publishedDateInfo = deserializedObj.Properties.Match("PublishedDate"); - installedDateInfo = deserializedObj.Properties.Match("InstalledDate"); - updatedDateInfo = deserializedObj.Properties.Match("UpdatedDate"); - licenseUriInfo = deserializedObj.Properties.Match("LicenseUri"); - projectUriInfo = deserializedObj.Properties.Match("ProjectUri"); - iconUriInfo = deserializedObj.Properties.Match("IconUri"); - tagsInfo = deserializedObj.Properties.Match("Tags"); - includesInfo = deserializedObj.Properties.Match("Includes"); - powerShellGetFormatVersionInfo = deserializedObj.Properties.Match("PowerShellGetFormatVersion"); - releaseNotesInfo = deserializedObj.Properties.Match("ReleaseNotes"); - dependenciesInfo = deserializedObj.Properties.Match("Dependencies"); - repositorySourceLocationInfo = deserializedObj.Properties.Match("RepositorySourceLocation"); - repositoryInfo = deserializedObj.Properties.Match("Repository"); - additionalMetadataInfo = deserializedObj.Properties.Match("AdditionalMetadata"); - installedLocationInfo = deserializedObj.Properties.Match("InstalledLocation"); - - - /* // testing adding prerelease parameter - additionalMetadataInfo = deserializedObj.Properties.Match("AdditionalMetadata"); - if (additionalMetadataInfo.Any()) - { - isPrelease = additionalMetadataInfo.FirstOrDefault().Value.ToString().Contains("IsPrerelease=true"); - if ((isPrelease == true) && _prerelease) // find a stable version of the pkg {} - } - */ - - - }; - - // if -Prerelease is not passed in as a parameter, don't allow prerelease pkgs to be returned, - // we still want all pkgs to be returned if -Prerelease is passed in as a param - //if ((_prerelease == false && isPrelease == false) || _prerelease == true) - //{ - - //var foundPkgs = List(); - - PSObject pkgAsPSObject = new PSObject(); - try - { - pkgAsPSObject.Members.Add(new PSNoteProperty("Name", nameInfo.Any()? nameInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Version", versionInfo.Any()? versionInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Type", typeInfo.Any()? typeInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Description", descriptionInfo.Any()? descriptionInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Author", authorInfo.Any()? authorInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("CompanyName", companyNameInfo.Any()? companyNameInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Copyright", copyrightInfo.Any()? copyrightInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("PublishedDate", publishedDateInfo.Any()? publishedDateInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("InstalledDate", installedDateInfo.Any()? installedDateInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("UpdatedDate", updatedDateInfo.Any()? updatedDateInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("LicenseUri", licenseUriInfo.Any()? licenseUriInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("ProjectUri", projectUriInfo.Any()? projectUriInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("IconUri", iconUriInfo.Any()? iconUriInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Tags", tagsInfo.Any()? tagsInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Includes", includesInfo.Any()? includesInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("PowerShellGetFormatVersion", powerShellGetFormatVersionInfo.Any()? powerShellGetFormatVersionInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("ReleaseNotes", releaseNotesInfo.Any()? releaseNotesInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Dependencies", dependenciesInfo.Any()? dependenciesInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("RepositorySourceLocation", repositorySourceLocationInfo.Any()? repositorySourceLocationInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repositoryInfo.Any()? repositoryInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("AdditionalMetadata", additionalMetadataInfo.Any()? additionalMetadataInfo.FirstOrDefault().Value : string.Empty)); - pkgAsPSObject.Members.Add(new PSNoteProperty("InstalledLocation", installedLocationInfo.Any()? installedLocationInfo.FirstOrDefault().Value : string.Empty)); - - - // verify that this works, then add the object to a list and return it - //WriteObject(pkgAsPSObject); - foundInstalledPkgs.Add(pkgAsPSObject); - - } - catch { } - - } - } - - // return here - return foundInstalledPkgs; - } - } -} diff --git a/srcOld/code/GetPSResource.cs b/srcOld/code/GetPSResource.cs deleted file mode 100644 index 9e0298303..000000000 --- a/srcOld/code/GetPSResource.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using NuGet.Versioning; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; -using static System.Environment; -using MoreLinq; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// It retrieves a resource that was installEd with Install-PSResource - /// Returns a single resource or multiple resource. - /// - [Cmdlet(VerbsCommon.Get, "PSResource", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class GetPSResource : PSCmdlet - { - /// - /// Specifies the desired name for the resource to look for. - /// - [Parameter(Position = 0, ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name; - - - /// - /// Specifies the version of the resource to include to look for. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty()] - public string Version - { - get - { return _version; } - - set - { _version = value; } - } - private string _version; - - /// - /// Specifies the path to look in. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty()] - public string Path - { - get - { return _path; } - - set - { _path = value; } - } - private string _path; - - - /* - /// - /// Specifies to include prerelease versions - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter Prerelease - { - get - { return _prerelease; } - - set - { _prerelease = value; } - } - private SwitchParameter _prerelease; - */ - - public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - - protected override void ProcessRecord() - { - // Define the cancellation token. - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - - WriteDebug("Entering GetPSResource"); - - // Flatten returned pkgs before displaying output returnedPkgsFound.Flatten().ToList()[0] - GetHelper getHelper = new GetHelper(cancellationToken, this); - List flattenedPkgs = getHelper.ProcessGetParams(_name, _version, prerelease:false, _path); - - foreach (PSObject psObject in flattenedPkgs) - { - // Temporary PSObject for output purposes - PSObject temp = new PSObject(); - - temp.Members.Add(new PSNoteProperty("Name", psObject.Properties["Name"].Value.ToString())); - temp.Members.Add(new PSNoteProperty("Version", psObject.Properties["Version"].Value.ToString())); - temp.Members.Add(new PSNoteProperty("Repository", psObject.Properties["Repository"].Value.ToString())); - temp.Members.Add(new PSNoteProperty("Description", psObject.Properties["Description"].Value.ToString())); - WriteObject(temp); - } - } - } -} diff --git a/srcOld/code/GetPSResourceRepository.cs b/srcOld/code/GetPSResourceRepository.cs deleted file mode 100644 index 3bcffe288..000000000 --- a/srcOld/code/GetPSResourceRepository.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Management.Automation; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; - - - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Register-PSResourceRepository cmdlet. - /// It retrieves a repository that was registered with Register-PSResourceRepository - /// Returns a single repository or multiple repositories. - /// - [Cmdlet(VerbsCommon.Get, "PSResourceRepository", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class GetPSResourceRepository : PSCmdlet - { - /// - /// Specifies the desired name for the repository to be registered. - /// - [Parameter(Position = 0, ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name = new string[0]; - - - /// - /// - protected override void ProcessRecord() - { - var r = new RespositorySettings(); - - var listOfRepositories = r.Read(_name); - - /// Print out repos - foreach (var repo in listOfRepositories) - { - WriteObject(repo); - } - } - } -} diff --git a/srcOld/code/InstallHelper.cs b/srcOld/code/InstallHelper.cs deleted file mode 100644 index 50714df98..000000000 --- a/srcOld/code/InstallHelper.cs +++ /dev/null @@ -1,1105 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using static System.Environment; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Net; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using System.Threading; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using MoreLinq.Extensions; -using Newtonsoft.Json; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging; -using NuGet.Packaging.Core; -using NuGet.Packaging.PackageExtraction; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// Find helper class - /// - class InstallHelper : PSCmdlet - { - private CancellationToken cancellationToken; - private readonly bool update; - private readonly bool save; - private readonly PSCmdlet cmdletPassedIn; - - // This will be a list of all the repository caches - public static readonly List RepoCacheFileName = new List(); - public static readonly string RepositoryCacheDir = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet", "RepositoryCache"); - public static readonly string osPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - private string programFilesPath; - private string myDocumentsPath; - private string psPath; - private string psModulesPath; - private string psScriptsPath; - private string psInstalledScriptsInfoPath; - private List psModulesPathAllDirs; - private List psScriptsPathAllDirs; - private List pkgsLeftToInstall; - private bool localRepo; - - public InstallHelper(bool update, bool save, CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) - { - this.update = update; - this.save = save; - this.cancellationToken = cancellationToken; - this.cmdletPassedIn = cmdletPassedIn; - } - - public void ProcessInstallParams(string[] _name, string _version, bool _prerelease, string[] _repository, string _scope, bool _acceptLicense, bool _quiet, bool _reinstall, bool _force, bool _trustRepository, bool _noClobber, PSCredential _credential, string _requiredResourceFile, string _requiredResourceJson, Hashtable _requiredResourceHash, string _path, bool _asNupkg, bool _includeXML) - { - cmdletPassedIn.WriteDebug(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; Scope: '{4}'; AcceptLicense: '{5}'; Quiet: '{6}'; Reinstall: '{7}'; TrustRepository: '{8}'; NoClobber: '{9}';", string.Join(",", _name), _version != null ? _version : string.Empty, _prerelease.ToString(), _repository != null ? string.Join(",", _repository) : string.Empty, _scope != null ? _scope : string.Empty, _acceptLicense.ToString(), _quiet.ToString(), _reinstall.ToString(), _trustRepository.ToString(), _noClobber.ToString())); - - Hashtable hash; - if (!save) - { - // call functions - hash = Utilities.GetInstallationPaths(cmdletPassedIn, _scope); - programFilesPath = hash["programFilesPath"] as string; - myDocumentsPath = hash["myDocumentsPath"] as string; - psPath = hash["psPath"] as string; - psModulesPath = hash["psModulesPath"] as string; - psScriptsPath = hash["psScriptsPath"] as string; - psInstalledScriptsInfoPath = hash["psInstalledScriptsInfoPath"] as string; - - psModulesPathAllDirs = hash["psModulesPathAllDirs"] as List; - psScriptsPathAllDirs = hash["psScriptsPathAllDirs"] as List; - } - - - - Dictionary pkgsinJson = new Dictionary(); - Dictionary jsonPkgsNameVersion = new Dictionary(); - - if (_requiredResourceFile != null) - { - var resolvedReqResourceFile = SessionState.Path.GetResolvedPSPathFromPSPath(_requiredResourceFile).FirstOrDefault().Path; - cmdletPassedIn.WriteDebug(String.Format("Resolved required resource file path is: '{0}'", resolvedReqResourceFile)); - - if (!File.Exists(resolvedReqResourceFile)) - { - var exMessage = String.Format("The RequiredResourceFile does not exist. Please try specifying a path to a valid .json or .psd1 file"); - var ex = new ArgumentException(exMessage); - var RequiredResourceFileDoesNotExist = new ErrorRecord(ex, "RequiredResourceFileDoesNotExist", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(RequiredResourceFileDoesNotExist); - } - - if (resolvedReqResourceFile.EndsWith(".psd1")) - { - // TODO: implement after implementing publish - throw new Exception("This feature is not yet implemented"); - } - else if (resolvedReqResourceFile.EndsWith(".json")) - { - // If json file - using (StreamReader sr = new StreamReader(resolvedReqResourceFile)) - { - _requiredResourceJson = sr.ReadToEnd(); - } - - try - { - pkgsinJson = JsonConvert.DeserializeObject>(_requiredResourceJson, new JsonSerializerSettings { MaxDepth = 6 }); - } - catch (Exception e) - { - var exMessage = String.Format("Argument for parameter -RequiredResource is not in proper json format. Make sure argument is either a hashtable or a json object. Error: {0}", e.Message); - var ex = new ArgumentException(exMessage); - var RequiredResourceNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceNotInProperJsonFormat", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(RequiredResourceNotInProperJsonFormat); - } - } - else - { - // throw new Exception("The RequiredResourceFile does not have the proper file extension. Please try specifying a path to a valid .json or .psd1 file"); - var exMessage = String.Format("The RequiredResourceFile does not have the proper file extension. Please try specifying a path to a valid .json or .psd1 file"); - var ex = new ArgumentException(exMessage); - var RequiredResourceFileExtensionError = new ErrorRecord(ex, "RequiredResourceFileExtensionError", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(RequiredResourceFileExtensionError); - } - } - - if (_requiredResourceHash != null) - { - string jsonString = ""; - try - { - jsonString = _requiredResourceHash.ToJson(); - } - catch (Exception e) - { - var exMessage = String.Format("Argument for parameter -RequiredResource is not in proper json format. Make sure argument is either a hashtable or a json object. Error: {0}", e.Message); - var ex = new ArgumentException(exMessage); - var RequiredResourceNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceNotInProperJsonFormat", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(RequiredResourceNotInProperJsonFormat); - } - - PkgParams pkg = null; - try - { - pkg = JsonConvert.DeserializeObject(jsonString, new JsonSerializerSettings { MaxDepth = 6 }); - } - catch (Exception e) - { - var exMessage = String.Format("Argument for parameter -RequiredResource is not in proper json format. Make sure argument is either a hashtable or a json object. Error: {0}", e.Message); - var ex = new ArgumentException(exMessage); - var RequiredResourceNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceNotInProperJsonFormat", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(RequiredResourceNotInProperJsonFormat); - } - - ProcessRepositories(new string[] { pkg.Name }, pkg.Version, pkg.Prerelease, new string[] { pkg.Repository }, pkg.Scope, pkg.AcceptLicense, pkg.Quiet, pkg.Reinstall, pkg.Force, pkg.TrustRepository, pkg.NoClobber, pkg.Credential, _path, _asNupkg, _includeXML); - - return; - } - - if (_requiredResourceJson != null) - { - if (!pkgsinJson.Any()) - { - try - { - pkgsinJson = JsonConvert.DeserializeObject>(_requiredResourceJson, new JsonSerializerSettings { MaxDepth = 6 }); - } - catch (Exception) - { - try - { - jsonPkgsNameVersion = JsonConvert.DeserializeObject>(_requiredResourceJson, new JsonSerializerSettings { MaxDepth = 6 }); - } - catch (Exception e) - { - var exMessage = String.Format("Argument for parameter -RequiredResource is not in proper json format. Make sure argument is either a hashtable or a json object. Error: {0}", e.Message); - var ex = new ArgumentException(exMessage); - var RequiredResourceNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceNotInProperJsonFormat", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(RequiredResourceNotInProperJsonFormat); - } - } - } - - foreach (var pkg in jsonPkgsNameVersion) - { - ProcessRepositories(new string[] { pkg.Key }, pkg.Value, false, null, null, false, false, false, false, false, false, null, _path, _asNupkg, _includeXML); - } - - foreach (var pkg in pkgsinJson) - { - ProcessRepositories(new string[] { pkg.Key }, pkg.Value.Version, pkg.Value.Prerelease, new string[] { pkg.Value.Repository }, pkg.Value.Scope, pkg.Value.AcceptLicense, pkg.Value.Quiet, pkg.Value.Reinstall, pkg.Value.Force, pkg.Value.TrustRepository, pkg.Value.NoClobber, pkg.Value.Credential, _path, _asNupkg, _includeXML); - } - return; - } - - ProcessRepositories(_name, _version, _prerelease, _repository, _scope, _acceptLicense, _quiet, _reinstall, _force, _trustRepository, _noClobber, _credential, _path, _asNupkg, _includeXML); - } - - public void ProcessRepositories(string[] packageNames, string version, bool prerelease, string[] repository, string scope, bool acceptLicense, bool quiet, bool reinstall, bool force, bool trustRepository, bool noClobber, PSCredential credential, string _path, bool _asNupkg, bool _includeXML) - { - var r = new RespositorySettings(); - var listOfRepositories = r.Read(repository); - - pkgsLeftToInstall = packageNames.ToList(); - - var yesToAll = false; - var noToAll = false; - var repositoryIsNotTrusted = "Untrusted repository"; - var queryInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; - - foreach (var repo in listOfRepositories) - { - var sourceTrusted = false; - - string repoName = repo.Properties["Name"].Value.ToString(); - - cmdletPassedIn.WriteDebug(string.Format("Attempting to search for packages in '{0}'", repoName)); - if (string.Equals(repo.Properties["Trusted"].Value.ToString(), "false", StringComparison.InvariantCultureIgnoreCase) && !trustRepository && !force) - { - cmdletPassedIn.WriteDebug("Checking if untrusted repository should be used"); - - if (!(yesToAll || noToAll)) - { - // Prompt for installation of package from untrusted repository - var message = string.Format(CultureInfo.InvariantCulture, queryInstallUntrustedPackage, repoName); - sourceTrusted = cmdletPassedIn.ShouldContinue(message, repositoryIsNotTrusted, true, ref yesToAll, ref noToAll); - } - } - else - { - sourceTrusted = true; - } - - if (sourceTrusted || yesToAll) - { - cmdletPassedIn.WriteDebug("Untrusted repository accepted as trusted source."); - // Check if repository is a local repository - localRepo = repo.Properties["Url"].Value.ToString().StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter) ? true : false; - // Try to install-- returns any pkgs that weren't found - // If it can't find the pkg in one repository, it'll look for it in the next repo in the list - var returnedPkgsNotInstalled = InstallPkgs(repoName, repo.Properties["Url"].Value.ToString(), pkgsLeftToInstall, packageNames, version, prerelease, scope, acceptLicense, quiet, reinstall, force, trustRepository, noClobber, credential, _path, _asNupkg, _includeXML); - if (!pkgsLeftToInstall.Any()) - { - return; - } - pkgsLeftToInstall = returnedPkgsNotInstalled; - } - } - } - - // Installing a package will have a transactional behavior: - // Package and its dependencies will be saved into a tmp folder - // and will only be properly installed if all dependencies are found successfully. - // Once package is installed, we want to resolve and install all dependencies. - public List InstallPkgs(string repositoryName, string repositoryUrl, List pkgsLeftToInstall, string[] packageNames, string version, bool prerelease, string scope, bool acceptLicense, bool quiet, bool reinstall, bool force, bool trustRepository, bool noClobber, PSCredential credential, string _path, bool _asNupkg, bool _includeXML) - { - PackageSource source = new PackageSource(repositoryUrl); - - if (credential != null) - { - string password = new NetworkCredential(string.Empty, credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl, credential.UserName, password, true, null); - } - - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - SourceRepository repository = new SourceRepository(source, provider); - SearchFilter filter = new SearchFilter(prerelease); - SourceCacheContext context = new SourceCacheContext(); - - // TODO: proper error handling here - PackageMetadataResource pkgMetadataResource = null; - - try - { - if (localRepo) - { - var localResource = new FindLocalPackagesResourceV2(repositoryUrl); - pkgMetadataResource = new LocalPackageMetadataResource(localResource); - } - else - { - pkgMetadataResource = repository.GetResourceAsync().GetAwaiter().GetResult(); - } - } - catch - { - } - if (pkgMetadataResource == null) - { - cmdletPassedIn.WriteVerbose(string.Format("Error retreiving resource repository from '{0}'. Try running command again with -Credential", repositoryName)); - - return pkgsLeftToInstall; - } - - foreach (var pkgName in packageNames) - { - var versionRange = Utilities.GetPkgVersion(version); - cmdletPassedIn.WriteDebug(string.Format("Parsed version is: '{0}'", versionRange.ToString())); - - var filteredFoundPkgs = FindFilteredPackages(pkgName, pkgMetadataResource, context, repositoryName, versionRange, prerelease); - - if (filteredFoundPkgs == null) - { - return pkgsLeftToInstall; - } - - List foundDependencies = new List(); - // Found package to install, now search for dependencies - if (filteredFoundPkgs != null) - { - // TODO: improve dependency search - // This function recursively finds all dependencies - foundDependencies.AddRange(FindDependenciesFromSource(filteredFoundPkgs, pkgMetadataResource, context, prerelease, reinstall, _path, repositoryUrl)); - } - - List pkgsToInstall = new List(); - pkgsToInstall.Add(filteredFoundPkgs); - pkgsToInstall.AddRange(foundDependencies); - - if (!save) - { - // Check which pkgs actually need to be installed - // We do not need to check for versions already installed in save - // We have a list of everything that needs to be installed - // Check the system to see if that particular package AND package version is there - // If it is, remove it from the list of pkgs to install - if (versionRange != null) - { - foreach (var name in packageNames) - { - var pkgDirName = Path.Combine(psModulesPath, name); - var pkgDirNameScript = Path.Combine(psInstalledScriptsInfoPath, name + "_InstalledScriptInfo.xml"); - - // Check to see if the package dir exists in the Modules path or if the script metadata file exists in the Scripts path - if (psModulesPathAllDirs.Contains(pkgDirName, StringComparer.OrdinalIgnoreCase) - || psScriptsPathAllDirs.Contains(pkgDirNameScript, StringComparer.OrdinalIgnoreCase)) - { - // Then check to see if the package version exists in the Modules path - var pkgDirVersion = new List(); - try - { - pkgDirVersion = (Directory.GetDirectories(pkgDirName)).ToList(); - } - catch { } - - List pkgVersion = new List(); - foreach (var path in pkgDirVersion) - { - pkgVersion.Add(Path.GetFileName(path)); - } - - // Remove any pkg versions that are not formatted correctly, eg: 2.2.4.1x - String[] pkgVersions = pkgVersion.ToArray(); - - foreach (var installedPkgVer in pkgVersions) - { - if (!NuGetVersion.TryParse(installedPkgVer, out NuGetVersion pkgVer)) - { - pkgVersion.Remove(installedPkgVer); - } - } - - // These are all the packages already installed - var pkgsAlreadyInstalled = pkgVersion.FindAll(p => versionRange.Satisfies(NuGetVersion.Parse(p))); - - if (pkgsAlreadyInstalled.Any() && !reinstall) - { - // Remove the pkg from the list of pkgs that need to be installed - var pkgsToRemove = pkgsToInstall.Find(p => string.Equals(p.Identity.Id, name, StringComparison.CurrentCultureIgnoreCase)); - - pkgsToInstall.Remove(pkgsToRemove); - pkgsLeftToInstall.Remove(name); - } - } - else if (update) - { - // Not installed throw terminating error - var exMessage = String.Format("Module '{0}' was not updated because no valid module was found in the module directory.Verify that the module is located in the folder specified by $env: PSModulePath.", name); - var ex = new ArgumentException(exMessage); // System.ArgumentException vs PSArgumentException - var moduleNotInstalledError = new ErrorRecord(ex, "ModuleNotInstalled", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(moduleNotInstalledError); - } - } - } - else - { - foreach (var name in packageNames) - { - var dirName = Path.Combine(psModulesPath, name); - // Example script metadata file name format: 'install-kubectl_InstalledScriptInfo.xml' - var dirNameScript = Path.Combine(psInstalledScriptsInfoPath, name + "_InstalledScriptInfo.xml"); - - // Check to see if the package dir exists in the path - if (psModulesPathAllDirs.Contains(dirName, StringComparer.OrdinalIgnoreCase) - || psScriptsPathAllDirs.Contains(dirNameScript, StringComparer.OrdinalIgnoreCase)) - { - // then check to see if the package/script exists in the path - if ((Directory.Exists(dirName) || Directory.Exists(dirNameScript)) && !reinstall && !update) - { - // Remove the pkg from the list of pkgs that need to be installed - var pkgsToRemove = pkgsToInstall.Find(p => string.Equals(p.Identity.Id, name, StringComparison.CurrentCultureIgnoreCase)); - - pkgsToInstall.Remove(pkgsToRemove); - pkgsLeftToInstall.Remove(name); - } - // if update, check to see if that particular version is in the path.. - // check script version matching too - } - else if (update) - { - // Throw module or script not installed terminating error - var exMessage = String.Format("Module '{0}' was not updated because no valid module was found in the module directory.Verify that the module is located in the folder specified by $env: PSModulePath.", name); - var ex = new ArgumentException(exMessage); - var moduleNotInstalledError = new ErrorRecord(ex, "ModuleNotInstalled", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(moduleNotInstalledError); - } - } - } - } - - // Remove any null pkgs - pkgsToInstall.Remove(null); - - foreach (var p in pkgsToInstall) - { - var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly - // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator - // with a mask (bitwise complement of desired attributes combination). - dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; - - cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", p.Identity.Id)); - - if (!quiet && !save) - { - int i = 1; - int j = 1; - /**************************** - * START PACKAGE INSTALLATION -- start progress bar - *****************************/ - // Write-Progress -Activity "Search in Progress" - Status "$i% Complete:" - PercentComplete $i - - int activityId = 0; - string activity = ""; - string statusDescription = ""; - - if (packageNames.ToList().Contains(p.Identity.Id)) - { - // If the pkg exists in one of the names passed in, then we wont include it as a dependent package - activityId = 0; - activity = string.Format("Installing {0}...", p.Identity.Id); - statusDescription = string.Format("{0}% Complete:", i++); - - j = 1; - } - else - { - // Child process - // Installing dependent package - activityId = 1; - activity = string.Format("Installing dependent package {0}...", p.Identity.Id); - statusDescription = string.Format("{0}% Complete:", j); - } - - var progressRecord = new ProgressRecord(activityId, activity, statusDescription); - cmdletPassedIn.WriteProgress(progressRecord); - } - - var pkgIdentity = new PackageIdentity(p.Identity.Id, p.Identity.Version); - var cacheContext = new SourceCacheContext(); - - if (localRepo) - { - var localResource = new FindLocalPackagesResourceV2(repositoryUrl); - var resource = new LocalDownloadResource(repositoryUrl, localResource); - - var result = resource.GetDownloadResourceResultAsync( - pkgIdentity, - new PackageDownloadContext(cacheContext), - tempInstallPath, - logger: NullLogger.Instance, - CancellationToken.None).GetAwaiter().GetResult(); - - PackageExtractionContext packageExtractionContext = new PackageExtractionContext( - PackageSaveMode.Nupkg, - PackageExtractionBehavior.XmlDocFileSaveMode, - null, - logger: NullLogger.Instance); - - if (_asNupkg) - { - DirectoryInfo nupkgPath = new DirectoryInfo (((System.IO.FileStream)result.PackageStream).Name); - File.Copy(nupkgPath.FullName, Path.Combine(tempInstallPath, pkgIdentity.Id + pkgIdentity.Version + ".nupkg")); - } - else { - - result.PackageReader.CopyFiles( - tempInstallPath, - result.PackageReader.GetFiles(), - (new PackageFileExtractor(result.PackageReader.GetFiles(), packageExtractionContext.XmlDocFileSaveMode)).ExtractPackageFile, - logger: NullLogger.Instance, - CancellationToken.None); - result.Dispose(); - } - } - else - { - var downloadResource = repository.GetResourceAsync().GetAwaiter().GetResult(); - - var result = downloadResource.GetDownloadResourceResultAsync( - pkgIdentity, - new PackageDownloadContext(cacheContext), - tempInstallPath, - logger: NullLogger.Instance, - CancellationToken.None).GetAwaiter().GetResult(); - - // Need to close the .nupkg - result.Dispose(); - - if (_asNupkg) - { - var saveNupkgPath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(_path).FirstOrDefault().Path; - var tempPkgIdPath = System.IO.Path.Combine(tempInstallPath, p.Identity.Id, p.Identity.Version.ToString()); - var tempPkgVersionPath = System.IO.Path.Combine(tempPkgIdPath, p.Identity.Id.ToLower() + "." + p.Identity.Version + ".nupkg"); - var newSavePath = System.IO.Path.Combine(saveNupkgPath, p.Identity.Id + "." + p.Identity.Version + ".nupkg"); - - File.Move(tempPkgVersionPath, newSavePath); - - pkgsLeftToInstall.Remove(pkgName); - - return pkgsLeftToInstall; - } - } - - cmdletPassedIn.WriteDebug(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); - - // Prompt if module requires license acceptance - // Need to read from .psd1 - var newVersion = p.Identity.Version.ToString(); - if (p.Identity.Version.IsPrerelease) - { - newVersion = p.Identity.Version.ToString().Substring(0, p.Identity.Version.ToString().IndexOf('-')); - } - - var modulePath = Path.Combine(tempInstallPath, pkgIdentity.Id, newVersion); - var moduleManifest = Path.Combine(modulePath, pkgIdentity.Id + ".psd1"); - var requireLicenseAcceptance = false; - - // Accept Licsense - if (!save) - { - if (File.Exists(moduleManifest)) - { - using (StreamReader sr = new StreamReader(moduleManifest)) - { - var text = sr.ReadToEnd(); - - var pattern = "RequireLicenseAcceptance\\s*=\\s*\\$true"; - var patternToSkip1 = "#\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; - var patternToSkip2 = "\\*\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; - - Regex rgx = new Regex(pattern); - - if (rgx.IsMatch(pattern) && !rgx.IsMatch(patternToSkip1) && !rgx.IsMatch(patternToSkip2)) - { - requireLicenseAcceptance = true; - } - } - - if (requireLicenseAcceptance) - { - // If module requires license acceptance and -AcceptLicense is not passed in, display prompt - if (!acceptLicense) - { - var PkgTempInstallPath = Path.Combine(tempInstallPath, p.Identity.Id, newVersion); - var LicenseFilePath = Path.Combine(PkgTempInstallPath, "License.txt"); - - if (!File.Exists(LicenseFilePath)) - { - var exMessage = "License.txt not Found. License.txt must be provided when user license acceptance is required."; - var ex = new ArgumentException(exMessage); // System.ArgumentException vs PSArgumentException - var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); - - cmdletPassedIn.ThrowTerminatingError(acceptLicenseError); - } - - // Otherwise read LicenseFile - string licenseText = System.IO.File.ReadAllText(LicenseFilePath); - var acceptanceLicenseQuery = $"Do you accept the license terms for module '{p.Identity.Id}'."; - var message = licenseText + "`r`n" + acceptanceLicenseQuery; - - var title = "License Acceptance"; - var yesToAll = false; - var noToAll = false; - var shouldContinueResult = ShouldContinue(message, title, true, ref yesToAll, ref noToAll); - - if (yesToAll) - { - acceptLicense = true; - } - } - - // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install - if (!acceptLicense) - { - var message = $"License Acceptance is required for module '{p.Identity.Id}'. Please specify '-AcceptLicense' to perform this operation."; - var ex = new ArgumentException(message); // System.ArgumentException vs PSArgumentException - var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); - - cmdletPassedIn.ThrowTerminatingError(acceptLicenseError); - } - } - } - } - - var dirNameVersion = Path.Combine(tempInstallPath, p.Identity.Id.ToLower(), p.Identity.Version.ToNormalizedString().ToLower()); - var nupkgSHAToDelete = Path.Combine(dirNameVersion, (p.Identity.ToString() + ".nupkg.sha512").ToLower()); - var nuspecToDelete = Path.Combine(dirNameVersion, (p.Identity.Id + ".nuspec").ToLower()); - var nupkgToDelete = Path.Combine(dirNameVersion, (p.Identity.ToString() + ".nupkg").ToLower()); - - if (File.Exists(nupkgSHAToDelete)) - { - cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nupkgSHAToDelete)); - File.Delete(nupkgSHAToDelete); - } - if (File.Exists(nuspecToDelete)) - { - cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nuspecToDelete)); - File.Delete(nuspecToDelete); - } - if (File.Exists(nupkgToDelete)) - { - cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nupkgToDelete)); - File.Delete(nupkgToDelete); - } - - var scriptPath = Path.Combine(dirNameVersion, (p.Identity.Id.ToString() + ".ps1")); - var isScript = File.Exists(scriptPath) ? true : false; - - if (!Directory.Exists(dirNameVersion)) - { - cmdletPassedIn.WriteDebug(string.Format("Directory does not exist, creating directory: '{0}'", dirNameVersion)); - Directory.CreateDirectory(dirNameVersion); - } - - if (_includeXML && !_asNupkg) - { - // Create PSGetModuleInfo.xml - var fullinstallPath = isScript ? Path.Combine(dirNameVersion, (p.Identity.Id + "_InstalledScriptInfo.xml")) - : Path.Combine(dirNameVersion, "PSGetModuleInfo.xml"); - - // Create XMLs - using (StreamWriter sw = new StreamWriter(fullinstallPath)) - { - var tags = p.Tags.Split(' '); - - var module = tags.Contains("PSModule") ? "Module" : null; - var script = tags.Contains("PSScript") ? "Script" : null; - - List includesDscResource = new List(); - List includesCommand = new List(); - List includesFunction = new List(); - List includesRoleCapability = new List(); - List filteredTags = new List(); - - var psDscResource = "PSDscResource_"; - var psCommand = "PSCommand_"; - var psFunction = "PSFunction_"; - var psRoleCapability = "PSRoleCapability_"; - - foreach (var tag in tags) - { - if (tag.StartsWith(psDscResource)) - { - includesDscResource.Add(tag.Remove(0, psDscResource.Length)); - } - else if (tag.StartsWith(psCommand)) - { - includesCommand.Add(tag.Remove(0, psCommand.Length)); - } - else if (tag.StartsWith(psFunction)) - { - includesFunction.Add(tag.Remove(0, psFunction.Length)); - } - else if (tag.StartsWith(psRoleCapability)) - { - includesRoleCapability.Add(tag.Remove(0, psRoleCapability.Length)); - } - else if (!tag.StartsWith("PSWorkflow_") && !tag.StartsWith("PSCmdlet_") && !tag.StartsWith("PSIncludes_") - && !tag.Equals("PSModule") && !tag.Equals("PSScript")) - { - filteredTags.Add(tag); - } - } - - // If NoClobber is specified, ensure command clobbering does not happen - if (noClobber) - { - // This is a primitive implementation - // 1) get all possible paths - // 2) search all modules and compare - /// Cannot uninstall a module if another module is dependent on it - - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) - { - // Get all modules - var results = pwsh.AddCommand("Get-Module").AddParameter("ListAvailable").Invoke(); - - // Structure of LINQ call: - // Results is a collection of PSModuleInfo objects that contain a property listing module commands, "ExportedCommands". - // ExportedCommands is collection of PSModuleInfo objects that need to be iterated through to see if any of them are the command we're trying to install - // If anything from the final call gets returned, there is a command clobber with this pkg. - - List> pkgsWithCommandClobber = new List>(); - foreach (string command in includesCommand) - { - pkgsWithCommandClobber.Add(results.Where(pkg => ((ReadOnlyCollection)pkg.Properties["ExportedCommands"].Value).Where(ec => ec.Name.Equals(command, StringComparison.InvariantCultureIgnoreCase)).Any())); - } - if (pkgsWithCommandClobber.Any()) - { - var uniqueCommandNames = (pkgsWithCommandClobber.Select(cmd => cmd.ToString()).Distinct()).ToArray(); - string strUniqueCommandNames = string.Join(",", uniqueCommandNames); - - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Command(s) with name(s) '{0}' is already available on this system. Installing '{1}' may override the existing command. If you still want to install '{1}', remove the -NoClobber parameter.", strUniqueCommandNames, p.Identity.Id)); - } - } - } - - Dictionary> includes = new Dictionary> { - { "DscResource", includesDscResource }, - { "Command", includesCommand }, - { "Function", includesFunction }, - { "RoleCapability", includesRoleCapability } - }; - - Dictionary dependencies = new Dictionary(); - foreach (var depGroup in p.DependencySets) - { - PackageDependency depPkg = depGroup.Packages.FirstOrDefault(); - dependencies.Add(depPkg.Id, depPkg.VersionRange); - } - - var psGetModuleInfoObj = new PSObject(); - // TODO: Add release notes - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Name", p.Identity.Id)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Version", p.Identity.Version)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Type", module != null ? module : (script != null ? script : null))); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Description", p.Description)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Author", p.Authors)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("CompanyName", p.Owners)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("PublishedDate", p.Published)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("InstalledDate", System.DateTime.Now)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("LicenseUri", p.LicenseUrl)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("ProjectUri", p.ProjectUrl)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("IconUri", p.IconUrl)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Includes", includes.ToList())); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("PowerShellGetFormatVersion", "3")); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Dependencies", dependencies.ToList())); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("RepositorySourceLocation", repositoryUrl)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("Repository", repositoryUrl)); - psGetModuleInfoObj.Members.Add(new PSNoteProperty("InstalledLocation", null)); - - psGetModuleInfoObj.TypeNames.Add("Microsoft.PowerShell.Commands.PSRepositoryItemInfo"); - - var serializedObj = PSSerializer.Serialize(psGetModuleInfoObj); - - sw.Write(serializedObj); - } - } - - if (save) - { - if (_asNupkg) - { - var nupkgName = pkgIdentity.Id + pkgIdentity.Version + ".nupkg"; - File.Copy(Path.Combine(tempInstallPath, nupkgName), Path.Combine(_path, nupkgName)); - } - if (!_asNupkg && isScript) - { - var tempScriptPath = Path.Combine(tempInstallPath, pkgIdentity.Id, pkgIdentity.Version.ToNormalizedString()); - var scriptName = pkgIdentity.Id + ".ps1"; - File.Copy(Path.Combine(tempScriptPath, scriptName), Path.Combine(_path, scriptName)); - - if (_includeXML) - { - // else if save and including XML - var scriptXML = p.Identity.Id + "_InstalledScriptInfo.xml"; - cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(_path, scriptXML))); - File.Move(Path.Combine(dirNameVersion, scriptXML), Path.Combine(_path, scriptXML)); - } - } - else - { - var fullTempInstallpath = Path.Combine(tempInstallPath, pkgIdentity.Id, pkgIdentity.Version.ToString()); // localRepo ? Path.Combine(tempInstallPath, pkgIdentity.Version.ToString()) : Path.Combine(tempInstallPath, pkgIdentity.Id, pkgIdentity.Version.ToString()); - var fullPermanentNewPath = localRepo ? Path.Combine(_path, pkgIdentity.Id, pkgIdentity.Version.ToString()) : Path.Combine(_path, pkgIdentity.Id); - - if (localRepo && !Directory.Exists(Path.Combine(_path, pkgIdentity.Id))) - { - Directory.CreateDirectory(Path.Combine(_path, pkgIdentity.Id)); - } - - if (localRepo) - { - Directory.Move(tempInstallPath, fullPermanentNewPath); - } - else - { - Directory.Move(Path.Combine(tempInstallPath, pkgIdentity.Id), fullPermanentNewPath); - fullPermanentNewPath = Path.Combine(fullPermanentNewPath, pkgIdentity.Version.ToString()); - } - var tempPSGetModuleInfoXML = Path.Combine(Path.Combine(fullPermanentNewPath, pkgIdentity.Id, pkgIdentity.Version.ToString()), "PSGetModuleInfo.xml"); - if (File.Exists(tempPSGetModuleInfoXML)) - { - File.Copy(tempPSGetModuleInfoXML, Path.Combine(fullPermanentNewPath, "PSGetModuleInfo.xml")); - } - - var relsPath = Path.Combine(fullPermanentNewPath, "_rels"); - if (Directory.Exists(relsPath)) - { - Directory.Delete(relsPath, true); - } - - var packagePath = Path.Combine(fullPermanentNewPath, "package"); - if (Directory.Exists(packagePath)) - { - Directory.Delete(packagePath, true); - } - - var pkgIdPath = Path.Combine(fullPermanentNewPath, pkgIdentity.Id); - if (Directory.Exists(pkgIdPath)) - { - Directory.Delete(pkgIdPath, true); - } - - var pkgVersionPath = Path.Combine(Path.Combine(_path, pkgIdentity.Id, pkgIdentity.Version.ToString()), pkgIdentity.Version.ToString()); - if (Directory.Exists(pkgVersionPath)) - { - Directory.Delete(Path.Combine(pkgVersionPath), true); - } - - var contentTypesXMLPath = Path.Combine(fullPermanentNewPath, "[Content_Types].xml"); - if (File.Exists(contentTypesXMLPath)) - { - File.Delete(contentTypesXMLPath); - } - - var nuspecPath = Path.Combine(fullPermanentNewPath, pkgIdentity.Id + ".nuspec"); - if (File.Exists(nuspecPath)) - { - File.Delete(nuspecPath); - } - - var nupkgMetadata = Path.Combine(fullPermanentNewPath, ".nupkg.metadata"); - if (File.Exists(nupkgMetadata)) - { - File.Delete(nupkgMetadata); - } - } - } - else - { - // Copy to proper path - var installPath = isScript ? psScriptsPath : psModulesPath; - - var newPath = isScript ? installPath - : Path.Combine(installPath, p.Identity.Id.ToString()); - cmdletPassedIn.WriteDebug(string.Format("Installation path is: '{0}'", newPath)); - - // If script, just move the files over, if module, move the version directory over - var tempModuleVersionDir = isScript ? dirNameVersion //Path.Combine(tempInstallPath, p.Identity.Id, p.Identity.Version.ToNormalizedString()) - : Path.Combine(tempInstallPath, p.Identity.Id.ToLower()); - cmdletPassedIn.WriteVerbose(string.Format("Full installation path is: '{0}'", tempModuleVersionDir)); - - if (isScript) - { - var scriptXML = p.Identity.Id + "_InstalledScriptInfo.xml"; - cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(psScriptsPath, "InstalledScriptInfos", scriptXML)))); - if (File.Exists(Path.Combine(psScriptsPath, "InstalledScriptInfos", scriptXML))) - { - cmdletPassedIn.WriteDebug(string.Format("Deleting script metadata XML")); - File.Delete(Path.Combine(psScriptsPath, "InstalledScriptInfos", scriptXML)); - } - - cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(psScriptsPath, "InstalledScriptInfos", scriptXML))); - File.Move(Path.Combine(dirNameVersion, scriptXML), Path.Combine(psScriptsPath, "InstalledScriptInfos", scriptXML)); - - cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(newPath, p.Identity.Id + ".ps1")))); - if (File.Exists(Path.Combine(newPath, p.Identity.Id + ".ps1"))) - { - cmdletPassedIn.WriteDebug(string.Format("Deleting script file")); - File.Delete(Path.Combine(newPath, p.Identity.Id + ".ps1")); - } - - cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(newPath, p.Identity.Id + ".ps1"))); - File.Move(scriptPath, Path.Combine(newPath, p.Identity.Id + ".ps1")); - } - else - { - if (!Directory.Exists(newPath)) - { - try - { - cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}", tempModuleVersionDir, newPath)); - Directory.Move(tempModuleVersionDir, newPath); - } - catch (Exception e) - { - throw new Exception(e.Message); - } - } - else - { - tempModuleVersionDir = Path.Combine(tempModuleVersionDir, p.Identity.Version.ToString()); - cmdletPassedIn.WriteDebug(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); - - var newVersionPath = Path.Combine(newPath, newVersion); - cmdletPassedIn.WriteDebug(string.Format("Path for module version directory installation is: '{0}'", newVersionPath)); - - - if (Directory.Exists(newVersionPath)) - { - // Delete the directory path before replacing it with the new module - try - { - cmdletPassedIn.WriteDebug(string.Format("Attempting to delete '{0}'", newVersionPath)); - Directory.Delete(newVersionPath, true); - } - catch (Exception e) - { - throw new Exception(e.Message); - } - } - - try - { - cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}", newPath, newVersion)); - Directory.Move(tempModuleVersionDir, Path.Combine(newPath, newVersion)); - } - catch (Exception e) - { - throw new Exception(e.Message); - } - } - } - } - - cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package {0}", p.Identity.Id)); - - cmdletPassedIn.WriteDebug(string.Format("Attempting to delete '{0}'", tempInstallPath)); - if (Directory.Exists(tempInstallPath)) - { - Directory.Delete(tempInstallPath, true); - } - - pkgsLeftToInstall.Remove(pkgName); - } - } - - return pkgsLeftToInstall; - } - - private IPackageSearchMetadata FindFilteredPackages(string pkgName, PackageMetadataResource pkgMetadataResource, SourceCacheContext srcContext, string repositoryName, VersionRange versionRange, bool prerelease) - { - IPackageSearchMetadata filteredFoundPkgs = null; - - if (versionRange == null) - { - // ensure that the latst version is returned first (the ordering of versions differ - // TODO: proper error handling - try - { - filteredFoundPkgs = (pkgMetadataResource.GetMetadataAsync(pkgName, prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult() - .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease) - .FirstOrDefault()); - - versionRange = Utilities.GetPkgVersion(filteredFoundPkgs.Identity.Version.ToString()); - } - catch - { - } - - if (filteredFoundPkgs == null) - { - cmdletPassedIn.WriteVerbose(String.Format("Could not find package '{0}' in repository '{1}'", pkgName, repositoryName)); - - return null; - } - } - else - { - // Search for packages within a version range - // ensure that the latest version is returned first (the ordering of versions differ - filteredFoundPkgs = (pkgMetadataResource.GetMetadataAsync(pkgName, prerelease, false, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult() - .Where(p => versionRange.Satisfies(p.Identity.Version)) - .OrderByDescending(p => p.Identity.Version, VersionComparer.VersionRelease) - .FirstOrDefault()); - } - - return filteredFoundPkgs; - } - - private List FindDependenciesFromSource(IPackageSearchMetadata pkg, PackageMetadataResource pkgMetadataResource, SourceCacheContext srcContext, bool prerelease, bool reinstall, string _path, string repositoryUrl) - { - // Dependency resolver - // This function is recursively called - // Call the findpackages from source helper (potentially generalize this so it's finding packages from source or cache) - List foundDependencies = new List(); - - // 1) Check the dependencies of this pkg - // 2) For each dependency group, search for the appropriate name and version - // A dependency group includes all the dependencies for a particular framework - foreach (var dependencyGroup in pkg.DependencySets) - { - foreach (var pkgDependency in dependencyGroup.Packages) - { - IEnumerable dependencies = null; - // a) Check that the appropriate pkg dependencies exist - // Returns all versions from a single package id. - try - { - dependencies = pkgMetadataResource.GetMetadataAsync(pkgDependency.Id, prerelease, true, srcContext, NullLogger.Instance, cancellationToken).GetAwaiter().GetResult(); - } - catch - { } - // b) Check if the appropriate verion range exists (if version exists, then add it to the list to return) - VersionRange versionRange = null; - try - { - versionRange = VersionRange.Parse(pkgDependency.VersionRange.OriginalString); - } - catch - { - var exMessage = String.Format("Error parsing version range"); - var ex = new ArgumentException(exMessage); - var ErrorParsingVersionRange = new ErrorRecord(ex, "ErrorParsingVersionRange", ErrorCategory.ParserError, null); - - cmdletPassedIn.ThrowTerminatingError(ErrorParsingVersionRange); - } - - // If no version/version range is specified the we just return the latest version - IPackageSearchMetadata depPkgToReturn = (versionRange == null ? - dependencies.FirstOrDefault() : - dependencies.Where(v => versionRange.Satisfies(v.Identity.Version)).FirstOrDefault()); - - // If the pkg already exists on the system, don't add it to the list of pkgs that need to be installed - var dirName = save ? cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(_path).FirstOrDefault().Path : Path.Combine(psModulesPath, pkgDependency.Id); - var dependencyAlreadyInstalled = false; - - // Check to see if the package dir exists in the path - // If save we only check the -path passed in - if (save || psModulesPathAllDirs.Contains(dirName, StringComparer.OrdinalIgnoreCase)) - { - // Then check to see if the package exists in the path - if (Directory.Exists(dirName)) - { - var pkgDirVersion = (Directory.GetDirectories(dirName)).ToList(); - List pkgVersion = new List(); - foreach (var path in pkgDirVersion) - { - pkgVersion.Add(Path.GetFileName(path)); - } - - // These are all the packages already installed - NuGetVersion ver; - var pkgsAlreadyInstalled = pkgVersion.FindAll(p => NuGetVersion.TryParse(p, out ver) && versionRange.Satisfies(ver)); - - if (pkgsAlreadyInstalled.Any() && !reinstall) - { - // Don't add the pkg to the list of pkgs that need to be installed - dependencyAlreadyInstalled = true; - } - } - } - - if (!dependencyAlreadyInstalled) - { - foundDependencies.Add(depPkgToReturn); - } - - // Search for any dependencies the pkg has - foundDependencies.AddRange(FindDependenciesFromSource(depPkgToReturn, pkgMetadataResource, srcContext, prerelease, reinstall, _path, repositoryUrl)); - } - } - - return foundDependencies; - } - } -} diff --git a/srcOld/code/InstallPSResource.cs b/srcOld/code/InstallPSResource.cs deleted file mode 100644 index 743df9e4f..000000000 --- a/srcOld/code/InstallPSResource.cs +++ /dev/null @@ -1,288 +0,0 @@ -using NuGet.Versioning; -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Management.Automation; -using System.Threading; -using static System.Environment; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Install-PSResource cmdlet installs a resource. - /// It returns nothing. - /// - - [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class InstallPSResource : PSCmdlet - { - /// - /// Specifies the exact names of resources to install from a repository. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name; // = new string[0]; - - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "InputObjectSet")] - [ValidateNotNullOrEmpty] - public object[] InputObject - { - get - { return _inputObject; } - - set - { _inputObject = value; } - } - private object[] _inputObject; - - /// - /// Specifies the version or version range of the package to be installed - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Version - { - get - { return _version; } - - set - { _version = value; } - } - private string _version; - - /// - /// Specifies to allow installation of prerelease versions - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter Prerelease - { - get - { return _prerelease; } - - set - { _prerelease = value; } - } - private SwitchParameter _prerelease; - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Repository - { - get - { return _repository; } - - set - { _repository = value; } - } - private string[] _repository; - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public PSCredential Credential - { - get - { return _credential; } - - set - { _credential = value; } - } - private PSCredential _credential; - - /// - /// Specifies to return any dependency packages. - /// Currently only used when name param is specified. - /// - [ValidateSet("CurrentUser", "AllUsers")] - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public string Scope - { - get { return _scope; } - - set { _scope = value; } - } - private string _scope; - - /// - /// Overrides warning messages about installation conflicts about existing commands on a computer. - /// Overwrites existing commands that have the same name as commands being installed by a module. AllowClobber and Force can be used together in an Install-Module command. - /// Prevents installing modules that have the same cmdlets as a differently named module already - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter NoClobber - { - get { return _noClobber; } - - set { _noClobber = value; } - } - private SwitchParameter _noClobber; - - /// - /// Suppresses being prompted for untrusted sources. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter TrustRepository - { - get { return _trustRepository; } - - set { _trustRepository = value; } - } - private SwitchParameter _trustRepository; - - /// - /// Overwrites a previously installed resource with the same name and version. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter Reinstall - { - get { return _reinstall; } - - set { _reinstall = value; } - } - private SwitchParameter _reinstall; - - /// - /// Suppresses progress information. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter Quiet - { - get { return _quiet; } - - set { _quiet = value; } - } - private SwitchParameter _quiet; - - /// - /// For modules that require a license, AcceptLicense automatically accepts the license agreement during installation. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter AcceptLicense - { - get { return _acceptLicense; } - - set { _acceptLicense = value; } - } - private SwitchParameter _acceptLicense; - - /// - /// - /// - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public String RequiredResourceFile - { - get { return _requiredResourceFile; } - - set { _requiredResourceFile = value; } - } - private String _requiredResourceFile; - - /// - /// - /// - [Parameter(ParameterSetName = "RequiredResourceParameterSet")] - public Object RequiredResource // takes either string (json) or hashtable - { - get { return _requiredResourceHash != null ? (Object)_requiredResourceHash : (Object)_requiredResourceJson; } - - set { - if (value.GetType().Name.Equals("String")) - { - _requiredResourceJson = (String) value; - } - else if (value.GetType().Name.Equals("Hashtable")) - { - _requiredResourceHash = (Hashtable) value; - } - else - { - throw new ParameterBindingException("Object is not a JSON or Hashtable"); - } - } - } - private string _requiredResourceJson; - private Hashtable _requiredResourceHash; - - - protected override void ProcessRecord() - { - // Define the cancellation token. - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - - // If PSModuleInfo object - if (_inputObject != null && _inputObject[0].GetType().Name.Equals("PSModuleInfo")) - { - foreach (PSModuleInfo pkg in _inputObject) - { - var installHelp = new InstallHelper(update:false, save:false, cancellationToken, this); - var prerelease = false; - - if (pkg.PrivateData != null) - { - Hashtable privateData = (Hashtable)pkg.PrivateData; - if (privateData.ContainsKey("PSData")) - { - Hashtable psData = (Hashtable)privateData["PSData"]; - - if (psData.ContainsKey("Prerelease") && !string.IsNullOrEmpty((string)psData["Prerelease"])) - { - prerelease = true; - } - } - } - - installHelp.ProcessInstallParams(new[] { pkg.Name }, pkg.Version.ToString(), prerelease, _repository, _scope, _acceptLicense, _quiet, _reinstall, _force: false, _trustRepository, _noClobber, _credential, _requiredResourceFile, _requiredResourceJson, _requiredResourceHash, _path:null, _asNupkg:false, _includeXML:true); - } - } - else if (_inputObject != null && _inputObject[0].GetType().Name.Equals("PSObject")) - { - // If PSObject - foreach (PSObject pkg in _inputObject) - { - var installHelp = new InstallHelper(update:false, save:false, cancellationToken, this); - - if (pkg != null) - { - var name = (string) pkg.Properties["Name"].Value; - var version = (NuGetVersion) pkg.Properties["Version"].Value; - var prerelease = version.IsPrerelease; - - installHelp.ProcessInstallParams(new[] { name }, version.ToString(), prerelease, _repository, _scope, _acceptLicense, _quiet, _reinstall, _force: false, _trustRepository, _noClobber, _credential, _requiredResourceFile, _requiredResourceJson, _requiredResourceHash, _path:null, _asNupkg:false, _includeXML:true); - } - } - } - - var installHelper = new InstallHelper(update:false, save:false, cancellationToken, this); - installHelper.ProcessInstallParams(_name, _version, _prerelease, _repository, _scope, _acceptLicense, _quiet, _reinstall, _force:false, _trustRepository, _noClobber, _credential, _requiredResourceFile, _requiredResourceJson, _requiredResourceHash, _path:null, _asNupkg:false, _includeXML:true); - } - } -} \ No newline at end of file diff --git a/srcOld/code/InstallPkgParams.cs b/srcOld/code/InstallPkgParams.cs deleted file mode 100644 index 3aac314f9..000000000 --- a/srcOld/code/InstallPkgParams.cs +++ /dev/null @@ -1,18 +0,0 @@ - -using System.Management.Automation; - -public class PkgParams -{ - public string Name { get; set; } - public string Version { get; set; } - public string Repository { get; set; } - public PSCredential Credential { get; set; } - public bool AcceptLicense { get; set; } - public bool Prerelease { get; set; } - public string Scope { get; set; } - public bool Quiet { get; set; } - public bool Reinstall { get; set; } - public bool Force { get; set; } - public bool TrustRepository { get; set; } - public bool NoClobber { get; set; } -} \ No newline at end of file diff --git a/srcOld/code/LoggerCatalogLeafProcessor.cs b/srcOld/code/LoggerCatalogLeafProcessor.cs deleted file mode 100644 index a28b9acc6..000000000 --- a/srcOld/code/LoggerCatalogLeafProcessor.cs +++ /dev/null @@ -1,63 +0,0 @@ -/*** -using System; -using System.Threading.Tasks; -//using Microsoft.Extensions.Logging; -using NuGet.Protocol.Catalog; - -public class LoggerCatalogLeafProcessor : ICatalogLeafProcessor -{ - private const int FailAfterCommitCount = 10; - //private readonly ILogger _logger; - private DateTimeOffset? _lastCommitTimestamp; - private int _commitCount; - - /* - public LoggerCatalogLeafProcessor(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _lastCommitTimestamp = null; - _commitCount = 0; - } - */ -/*** - public Task ProcessPackageDeleteAsync(PackageDeleteCatalogLeaf leaf) - { - Console.WriteLine( - $"{leaf.CommitTimestamp:O}: Found package delete leaf for {leaf.PackageId} {leaf.PackageVersion}."); - - return GetResultAsync(leaf); - } - - public Task ProcessPackageDetailsAsync(PackageDetailsCatalogLeaf leaf) - { - Console.WriteLine( - $"{leaf.CommitTimestamp:O}: Found package details leaf for {leaf.PackageId} {leaf.PackageVersion}."); - - return GetResultAsync(leaf); - } - - private Task GetResultAsync(ICatalogLeafItem leaf) - { - if (_lastCommitTimestamp.HasValue - && _lastCommitTimestamp.Value != leaf.CommitTimestamp) - { - _commitCount++; - - /* - // Simulate a failure every N commits to demonstrate how cursors and failures interact. - if (_commitCount % FailAfterCommitCount == 0) - { - _logger.LogError( - "{commitCount} catalog commits have been processed. We will now simulate a failure.", - FailAfterCommitCount); - return Task.FromResult(false); - } - */ -/*** - } - - _lastCommitTimestamp = leaf.CommitTimestamp; - return Task.FromResult(true); - } -} -*/ \ No newline at end of file diff --git a/srcOld/code/NuGetLogger.cs b/srcOld/code/NuGetLogger.cs deleted file mode 100644 index 95a3a26c6..000000000 --- a/srcOld/code/NuGetLogger.cs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Concurrent; -using System.Threading.Tasks; -using NuGet.Common; - - -public class NuGetLogger : ILogger -{ - private readonly ITestOutputHelper _output; - - public NuGetLogger() - { - } - - public NuGetLogger(ITestOutputHelper output) - { - _output = output; - } - - /// - /// Logged messages - /// - public ConcurrentQueue Messages { get; } = new ConcurrentQueue(); - public ConcurrentQueue DebugMessages { get; } = new ConcurrentQueue(); - public ConcurrentQueue VerboseMessages { get; } = new ConcurrentQueue(); - public ConcurrentQueue MinimalMessages { get; } = new ConcurrentQueue(); - public ConcurrentQueue ErrorMessages { get; } = new ConcurrentQueue(); - public ConcurrentQueue WarningMessages { get; } = new ConcurrentQueue(); - public ConcurrentQueue LogMessages { get; } = new ConcurrentQueue(); - public int Errors { get; set; } - public int Warnings { get; set; } - - public void LogDebug(string data) - { - Messages.Enqueue(data); - DebugMessages.Enqueue(data); - DumpMessage("DEBUG", data); - } - - public void LogError(string data) - { - Errors++; - Messages.Enqueue(data); - ErrorMessages.Enqueue(data); - DumpMessage("ERROR", data); - } - - public void LogInformation(string data) - { - Messages.Enqueue(data); - DumpMessage("INFO ", data); - } - - public void LogMinimal(string data) - { - Messages.Enqueue(data); - MinimalMessages.Enqueue(data); - DumpMessage("LOG ", data); - } - - public void LogVerbose(string data) - { - Messages.Enqueue(data); - VerboseMessages.Enqueue(data); - DumpMessage("TRACE", data); - } - - public void LogWarning(string data) - { - Warnings++; - Messages.Enqueue(data); - WarningMessages.Enqueue(data); - DumpMessage("WARN ", data); - } - - public void LogInformationSummary(string data) - { - Messages.Enqueue(data); - DumpMessage("ISMRY", data); - } - - private void DumpMessage(string level, string data) - { - _output?.WriteLine($"{level}: {data}"); - } - - public void Clear() - { - string msg; - while (Messages.TryDequeue(out msg)) - { - // do nothing - } - } - - public string ShowErrors() - { - return string.Join(Environment.NewLine, ErrorMessages); - } - - public string ShowWarnings() - { - return string.Join(Environment.NewLine, WarningMessages); - } - - public string ShowMessages() - { - return string.Join(Environment.NewLine, Messages); - } - - public void Log(LogLevel level, string data) - { - switch (level) - { - case LogLevel.Debug: - { - LogDebug(data); - break; - } - - case LogLevel.Error: - { - LogError(data); - break; - } - - case LogLevel.Information: - { - LogInformation(data); - break; - } - - case LogLevel.Minimal: - { - LogMinimal(data); - break; - } - - case LogLevel.Verbose: - { - LogVerbose(data); - break; - } - - case LogLevel.Warning: - { - LogWarning(data); - break; - } - } - } - - public Task LogAsync(LogLevel level, string data) - { - Log(level, data); - - return Task.FromResult(0); - } - - public void Log(ILogMessage message) - { - LogMessages.Enqueue(message); - - Log(message.Level, message.Message); - } - - public async Task LogAsync(ILogMessage message) - { - LogMessages.Enqueue(message); - - await LogAsync(message.Level, message.Message); - } -} - - // Summary: - // Represents a class which can be used to provide test output. - public interface ITestOutputHelper - { - // Summary: - // Adds a line of text to the output. - // Parameters: - // message: - // The message - void WriteLine(string message); - // Summary: - // Formats a line of text and adds it to the output. - // Parameters: - // format: - // The message format - // args: - // The format arguments - void WriteLine(string format, params object[] args); - } diff --git a/srcOld/code/PackageMetadata.cs b/srcOld/code/PackageMetadata.cs deleted file mode 100644 index 14c9aa42c..000000000 --- a/srcOld/code/PackageMetadata.cs +++ /dev/null @@ -1,81 +0,0 @@ - -using System; - - -public class PackageMetadata -{ - public string Name { get; set; } - public string Version { get; set; } - public string Type { get; set; } - public string Description { get; set; } - //public string Author { get; set; } - //public string[] CompanyName { get; set; } - public string Copyright { get; set; } - public DateTime PublishedDate { get; set; } - public object InstalledDate { get; set; } - public object UpdatedDate { get; set; } - public string LicenseUri { get; set; } - public string ProjectUri { get; set; } - public object IconUri { get; set; } - public string[] Tags { get; set; } - public Includes Includes { get; set; } - public object PowerShellGetFormatVersion { get; set; } - public string ReleaseNotes { get; set; } - public Dependency[] Dependencies { get; set; } - public string RepositorySourceLocation { get; set; } - public string Repository { get; set; } - public string PackageManagementProvider { get; set; } - public Additionalmetadata AdditionalMetadata { get; set; } -} - -public class Includes -{ - public string[] Command { get; set; } - public string[] RoleCapability { get; set; } - public string[] Function { get; set; } - public string[] Cmdlet { get; set; } - //public string Workflow { get; set; } - public string[] DscResource { get; set; } -} - - -public class Dependency -{ - public string Name { get; set; } - public string MinimumVersion { get; set; } - public string MaximumVersion { get; set; } -} - -public class Additionalmetadata -{ - public string summary { get; set; } - public string isLatestVersion { get; set; } - public string PackageManagementProvider { get; set; } - public string releaseNotes { get; set; } - public string DscResources { get; set; } - public string tags { get; set; } - public string downloadCount { get; set; } - public string isAbsoluteLatestVersion { get; set; } - public string GUID { get; set; } - public string Functions { get; set; } - public string ItemType { get; set; } - public string lastUpdated { get; set; } - public string developmentDependency { get; set; } - public string CompanyName { get; set; } - public string SourceName { get; set; } - public string requireLicenseAcceptance { get; set; } - public string created { get; set; } - public string description { get; set; } - public DateTime updated { get; set; } - public string NormalizedVersion { get; set; } - public string packageSize { get; set; } - public string published { get; set; } - public string PowerShellVersion { get; set; } - public string Authors { get; set; } - public string copyright { get; set; } - public string IsPrerelease { get; set; } - public string FileList { get; set; } - public string versionDownloadCount { get; set; } - public string Cmdlets { get; set; } - public string CLRVersion { get; set; } -} diff --git a/srcOld/code/PackageMetadataAllTables.cs b/srcOld/code/PackageMetadataAllTables.cs deleted file mode 100644 index 5f1c62be1..000000000 --- a/srcOld/code/PackageMetadataAllTables.cs +++ /dev/null @@ -1,30 +0,0 @@ - -using System; - - -public class PackageMetadataAllTables -{ - public object Key { get; set; } - public object Name { get; set; } - public object Version { get; set; } - public string Type { get; set; } - public object Description { get; set; } - public object Author { get; set; } - public object Copyright { get; set; } - public object PublishedDate { get; set; } - public object InstalledDate { get; set; } - public object UpdatedDate { get; set; } - public object LicenseUri { get; set; } - public object ProjectUri { get; set; } - public object IconUri { get; set; } - public object PowerShellGetFormatVersion { get; set; } - public object ReleaseNotes { get; set; } - public object RepositorySourceLocation { get; set; } - public object Repository { get; set; } - public object IsPrerelease { get; set; } - public object Tags { get; set; } - public Dependency Dependencies { get; set; } - public object Commands { get; set; } - public object DscResources { get; set; } - public object RoleCapability { get; set; } -} diff --git a/srcOld/code/PowerShellGet.csproj b/srcOld/code/PowerShellGet.csproj deleted file mode 100644 index b82551231..000000000 --- a/srcOld/code/PowerShellGet.csproj +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Library - PowerShellGet - PowerShellGet - 3.0.0.0 - 3.0.0 - 3.0.0 - netstandard2.0;net472; - - - - - - - - - - - - - - - - - - - - - - - - - - CoreTypes - - - - - diff --git a/srcOld/code/PublishPSResource.cs b/srcOld/code/PublishPSResource.cs deleted file mode 100644 index a1b17cdf6..000000000 --- a/srcOld/code/PublishPSResource.cs +++ /dev/null @@ -1,907 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Xml; -using System.Xml.Linq; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using NuGet.Commands; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging; -using NuGet.Versioning; - - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// Publishes a module, script, or nupkg to a designated repository. - /// - [Cmdlet(VerbsData.Publish, "PSResource", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class PublishPSResource : PSCmdlet - { - /// - /// Specifies the API key that you want to use to publish a module to the online gallery. - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public string APIKey - { - get - { return _APIKey; } - - set - { _APIKey = value; } - } - private string _APIKey; - - - /// - /// Specifies the repository to publish to. - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public string Repository - { - get - { return _repository; } - - set - { _repository = value; } - } - private string _repository; - - - /// - /// Can be used to publish a nupkg locally. - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public string DestinationPath - { - get - { return _destinationPath; } - - set - { _destinationPath = SessionState.Path.GetResolvedPSPathFromPSPath(_destinationPath).First().Path; } - } - private string _destinationPath; - - - /// - /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. - /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "PathParameterSet")] - [ValidateNotNullOrEmpty] - public string Path - { - get - { return _path; } - - set - { - string resolvedPath = string.Empty; - if (!string.IsNullOrEmpty(value)) - { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } - - if (Directory.Exists(resolvedPath)) - { - _path = resolvedPath; - } - else if (File.Exists(resolvedPath) && resolvedPath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) - { - isScript = true; - _path = resolvedPath; - } - } - } - private string _path; - - - /// - /// Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is used exactly as entered. - /// No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. - /// Single quotation marks tell PowerShell not to interpret any characters as escape sequences. - /// - [Parameter(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string LiteralPath - { - get - { return _literalPath; } - - set - { - if (Directory.Exists(value)) - { - _literalPath = value; - } - else if (File.Exists(value) && value.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) - { - isScript = true; - _literalPath = value; - } - } - } - private string _literalPath; - - - /// - /// Specifies a user account that has rights to a specific repository (used for finding dependencies). - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public PSCredential Credential - { - get - { return _credential; } - - set - { _credential = value; } - } - private PSCredential _credential; - - - /// - /// Bypasses the default check that all dependencies are present. - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public SwitchParameter SkipDependenciesCheck - { - get - { return _skipDependenciesCheck; } - - set - { _skipDependenciesCheck = value; } - } - private bool _skipDependenciesCheck; - - - /// - /// Updates nuspec: specifies a string containing release notes or comments that you want to be available to users of this version of the resource. - /// - [Parameter(ParameterSetName = "CreateNuspecParameterSet")] - [Parameter(ParameterSetName = "PathParameterSet")] - [Parameter(ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string ReleaseNotes - { - get - { return _releaseNotes; } - - set - { _releaseNotes = value; } - } - private string _releaseNotes; - - - /// - /// Updates nuspec: adds one or more tags to the resource that you are publishing. - /// Note-- this applies only to the nuspec. - /// - [Parameter(ParameterSetName = "CreateNuspecParameterSet")] - [Parameter(ParameterSetName = "PathParameterSet")] - [Parameter(ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Tags - { - get - { return _tags; } - - set - { _tags = value; } - } - private string[] _tags; - - - /// - /// Updates nuspec: specifies the URL of licensing terms for the resource you want to publish. - /// - [Parameter(ParameterSetName = "CreateNuspecParameterSet")] - [Parameter(ParameterSetName = "PathParameterSet")] - [Parameter(ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string LicenseUrl - { - get - { return _licenseUrl; } - - set - { _licenseUrl = value; } - } - private string _licenseUrl; - - - /// - /// Updates nuspec: specifies the URL of an icon for the resource. - /// - [Parameter(ParameterSetName = "CreateNuspecParameterSet")] - [Parameter(ParameterSetName = "PathParameterSet")] - [Parameter(ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string IconUrl - { - get - { return _iconUrl; } - - set - { _iconUrl = value; } - } - private string _iconUrl; - - - /// - /// Updates nuspec: specifies the URL of a webpage about this project. - /// - [Parameter(ParameterSetName = "CreateNuspecParameterSet")] - [Parameter(ParameterSetName = "PathParameterSet")] - [Parameter(ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string ProjectUrl - { - get - { return _projectUrl; } - - set - { _projectUrl = value; } - } - private string _projectUrl; - - - [Parameter(ParameterSetName = "ModuleNameParameterSet")] - /// - /// Excludes files from a nuspec - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public string[] Exclude - { - get - { return _exclude; } - - set - { _exclude = value; } - } - private string[] _exclude = System.Array.Empty(); - - - /// - /// Specifies a nuspec file rather than relying on this module to produce one. - /// - [Parameter(ParameterSetName = "NuspecParameterSet")] - [Parameter(ParameterSetName = "PathParameterSet")] - [Parameter(ParameterSetName = "PathLiteralParameterSet")] - [ValidateNotNullOrEmpty] - public string Nuspec - { - get - { return _nuspec; } - - set - { _nuspec = value; } - } - private string _nuspec; - - - /// - /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - [ValidateNotNullOrEmpty] - public Uri Proxy - { - get - { return _proxy; } - - set - { _proxy = value; } - } - private Uri _proxy; - - /// - /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public PSCredential ProxyCredential - { - get - { return _proxyCredential; } - - set - { _proxyCredential = value; } - } - private PSCredential _proxyCredential; - - private NuGetVersion pkgVersion = null; - private bool isScript; - private string pkgName; - - private static char[] PathSeparators = new [] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; - - protected override void ProcessRecord() - { - _path = string.IsNullOrEmpty(_path) ? _literalPath : _path; - - // Get the .psd1 file or .ps1 file - // Returns the name of the file or the name of the directory, depending on path - var pkgFileOrDir = new DirectoryInfo(_path); - string moduleManifestOrScriptPath; - if (isScript) - { - moduleManifestOrScriptPath = pkgFileOrDir.FullName; - pkgName = pkgFileOrDir.Name.Remove(pkgFileOrDir.Name.Length - 4); - } - else { - moduleManifestOrScriptPath = System.IO.Path.Combine(_path, pkgFileOrDir.Name + ".psd1"); - // Validate that there's a module manifest - if (!File.Exists(moduleManifestOrScriptPath)) - { - var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", moduleManifestOrScriptPath); - var ex = new ArgumentException(message); - var moduleManifestNotFound = new ErrorRecord(ex, "moduleManifestNotFound", ErrorCategory.ObjectNotFound, null); - - this.ThrowTerminatingError(moduleManifestNotFound); - } - pkgName = pkgFileOrDir.Name; - } - - FileInfo moduleFileInfo; - moduleFileInfo = new FileInfo(moduleManifestOrScriptPath); - // if there's no specified destination path to publish the nupkg, we'll just create a temp folder and delete it later - string outputDir = !string.IsNullOrEmpty(_destinationPath) ? _destinationPath : System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString()); - if (!Directory.Exists(outputDir)) - { - Directory.CreateDirectory(outputDir); - } - - // if user does not specify that they want to use a nuspec they've created, we'll create a nuspec - var dependencies = new Hashtable(); - if (string.IsNullOrEmpty(_nuspec)) - { - _nuspec = createNuspec(outputDir, moduleFileInfo); - } - else - { - // Read the nuspec passed in to pull out the dependency information - XDocument doc = XDocument.Load(_nuspec); - - // ex: 2.2.1 - var versionNode = doc.Descendants("version"); - NuGetVersion.TryParse(versionNode.FirstOrDefault().Value, out NuGetVersion version); - - if (version == null) - { - var message = "Version is not specified in the .nuspec provided. Please provide a valid version in the .nuspec."; - var ex = new ArgumentException(message); - var versionNotFound = new ErrorRecord(ex, "versionNotFound", ErrorCategory.NotSpecified, null); - - this.ThrowTerminatingError(versionNotFound); - } - - // ex: - var dependencyNode = doc.Descendants("dependency"); - foreach (var dep in dependencyNode) - { - dependencies.Add(dep.Attribute("id"), dep.Attribute("version")); - } - } - - // find repository - var r = new RespositorySettings(); - var repositoryUrl = r.Read(new[] { _repository }); - - if (!repositoryUrl.Any()) - { - var message = String.Format("The resource repository '{0}' is not a registered. Please run 'Register-PSResourceRepository' in order to publish to this repository.", _repository); - var ex = new ArgumentException(message); - var repositoryNotFound = new ErrorRecord(ex, "repositoryNotFound", ErrorCategory.ObjectNotFound, null); - - this.ThrowTerminatingError(repositoryNotFound); - } - - if (!_skipDependenciesCheck) - { - // Check to see that all dependencies are in the repository - var findHelper = new FindHelper(); - - foreach (var dependency in dependencies.Keys) - { - // Need to make individual calls since we're look for exact version numbers or ranges. - var depName = new[] { (string)dependency }; - var depVersion = (string)dependencies[dependency]; - var type = new[] { "module", "script" }; - var repository = new[] { _repository }; - - // Search for and return the dependency if it's in the repository. - var dependencyFound = findHelper.beginFindHelper(depName, type, depVersion, true, null, null, repository, _credential, false, false); - - if (!dependencyFound.Any()) - { - var message = String.Format("Dependency {0} was not found in repository {1}. Make sure the dependency is published to the repository before publishing this module.", depName, _repository); - var ex = new ArgumentException(message); // System.ArgumentException vs PSArgumentException - var dependencyNotFound = new ErrorRecord(ex, "DependencyNotFound", ErrorCategory.ObjectNotFound, null); - - this.ThrowTerminatingError(dependencyNotFound); - } - } - } - - if (isScript) - { - File.Copy(_path, System.IO.Path.Combine(outputDir, pkgName + ".ps1"), true); - } - else - { - // Create subdirectory structure in temp folder - foreach (string dir in System.IO.Directory.GetDirectories(_path, "*", System.IO.SearchOption.AllDirectories)) - { - var dirName = dir.Substring(_path.Length).Trim(PathSeparators); - System.IO.Directory.CreateDirectory(System.IO.Path.Combine(outputDir, dirName)); - } - // Copy files over to temp folder - foreach (string fileNamePath in System.IO.Directory.GetFiles(_path, "*", System.IO.SearchOption.AllDirectories)) - { - var fileName = fileNamePath.Substring(_path.Length).Trim(PathSeparators); - System.IO.File.Copy(fileNamePath, System.IO.Path.Combine(outputDir, fileName)); - } - } - - var outputDirectory = System.IO.Path.Combine(outputDir, "nupkg"); - // Pack the module or script into a nupkg given a nuspec. - var builder = new PackageBuilder(); - var runner = new PackCommandRunner( - new PackArgs - { - CurrentDirectory = outputDir, - OutputDirectory = outputDirectory, - Path = _nuspec, - Exclude = _exclude, - Symbols = false, - Logger = NullLogger.Instance - }, - MSBuildProjectFactory.ProjectCreator, - builder); - - runner.RunPackageBuild(); - - - // Push the nupkg to the appropriate repository - // Pkg version is parsed from .ps1 file or .psd1 file - var fullNupkgPath = System.IO.Path.Combine(outputDirectory, pkgName + "." + pkgVersion.ToNormalizedString() + ".nupkg" ); - - var repoURL = repositoryUrl.First().Properties["Url"].Value.ToString(); - var publishLocation = repoURL.EndsWith("/v2", StringComparison.OrdinalIgnoreCase) ? repoURL + "/package" : repoURL; - - var settings = NuGet.Configuration.Settings.LoadDefaultSettings(null, null, null); - NuGet.Common.ILogger log = new NuGetLogger(); - PushRunner.Run( - Settings.LoadDefaultSettings(root:null, configFileName:null, machineWideSettings:null), - new PackageSourceProvider(settings), - fullNupkgPath, - publishLocation, - _APIKey, // api key - null, // symbols source - null, // symbols api key - 0, // timeout - false, // disable buffering - false, // no symbols - // Skip duplicate: if a package and version already exists, skip it and continue with the next package in the push, if any. - false, // no skip duplicate - false, // enable server endpoint - log).GetAwaiter().GetResult(); - } - - - private string createNuspec(string outputDir, FileInfo moduleFileInfo) - { - WriteVerbose("Creating new nuspec file."); - Hashtable parsedMetadataHash = new Hashtable(); - - if (moduleFileInfo.Extension.Equals(".psd1", StringComparison.OrdinalIgnoreCase)) - { - System.Management.Automation.Language.Token[] tokens; - ParseError[] errors; - var ast = Parser.ParseFile(moduleFileInfo.FullName, out tokens, out errors); - - if (errors.Length > 0) - { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo.FullName); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - - this.ThrowTerminatingError(psdataParseError); - } - else - { - var data = ast.Find(a => a is HashtableAst, false); - if (data != null) - { - parsedMetadataHash = (Hashtable) data.SafeGetValue(); - } - else - { - var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo.FullName); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - - this.ThrowTerminatingError(psdataParseError); - } - } - } - else if (moduleFileInfo.Extension.Equals(".ps1", StringComparison.OrdinalIgnoreCase)) - { - ParseScriptMetadata(parsedMetadataHash, moduleFileInfo); - } - - /// now we have parsedMetadatahash to fill out the nuspec information - var nameSpaceUri = "http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"; - var doc = new XmlDocument(); - - // xml declaration is recommended, but not mandatory - XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "utf-8", null); - XmlElement root = doc.DocumentElement; - doc.InsertBefore(xmlDeclaration, root); - - // create top-level elements - XmlElement packageElement = doc.CreateElement("package", nameSpaceUri); - XmlElement metadataElement = doc.CreateElement("metadata", nameSpaceUri); - - Dictionary metadataElementsDictionary = new Dictionary(); - - // id is mandatory - metadataElementsDictionary.Add("id", pkgName); - - string version = String.Empty; - if (parsedMetadataHash.ContainsKey("moduleversion")) - { - version = parsedMetadataHash["moduleversion"].ToString(); - } - else if (parsedMetadataHash.ContainsKey("version")) - { - version = parsedMetadataHash["version"].ToString(); - } - else - { - // no version is specified for the nuspec - var message = "There is no package version specified. Please specify a version before publishing."; - var ex = new ArgumentException(message); - var NoVersionFound = new ErrorRecord(ex, "NoVersionFound", ErrorCategory.InvalidArgument, null); - - this.ThrowTerminatingError(NoVersionFound); - } - - // Look for Prerelease tag - if (parsedMetadataHash.ContainsKey("PrivateData")) - { - if (parsedMetadataHash["PrivateData"] is Hashtable privateData && - privateData.ContainsKey("PSData")) - { - if (privateData["PSData"] is Hashtable psData && - psData.ContainsKey("Prerelease")) - { - if (psData["Prerelease"] is string preReleaseVersion) - { - version = string.Format(@"{0}-{1}", version, preReleaseVersion); - } - } - } - } - - NuGetVersion.TryParse(version, out pkgVersion); - - metadataElementsDictionary.Add("version", pkgVersion.ToNormalizedString()); - - - if (parsedMetadataHash.ContainsKey("author")) - { - metadataElementsDictionary.Add("authors", parsedMetadataHash["author"].ToString().Trim()); - } - - if (parsedMetadataHash.ContainsKey("companyname")) - { - metadataElementsDictionary.Add("owners", parsedMetadataHash["companyname"].ToString().Trim()); - } - - // defaults to false - var requireLicenseAcceptance = parsedMetadataHash.ContainsKey("requirelicenseacceptance") ? parsedMetadataHash["requirelicenseacceptance"].ToString().ToLower().Trim() - : "false"; - metadataElementsDictionary.Add("requireLicenseAcceptance", requireLicenseAcceptance); - - if (parsedMetadataHash.ContainsKey("description")) - { - metadataElementsDictionary.Add("description", parsedMetadataHash["description"].ToString().Trim()); - } - - if (parsedMetadataHash.ContainsKey("releasenotes") || !String.IsNullOrEmpty(_releaseNotes)) - { - var releaseNotes = string.IsNullOrEmpty(_releaseNotes) ? parsedMetadataHash["releasenotes"].ToString().Trim() : _releaseNotes; - metadataElementsDictionary.Add("releaseNotes", releaseNotes); - } - - if (parsedMetadataHash.ContainsKey("copyright")) - { - metadataElementsDictionary.Add("copyright", parsedMetadataHash["copyright"].ToString().Trim()); - } - - string tags = string.Empty; - if (parsedMetadataHash.ContainsKey("tags") || _tags != null) - { - tags = _tags == null ? (parsedMetadataHash["tags"].ToString().Trim() + " ") : (_tags.ToString().Trim() + " "); - } - tags += moduleFileInfo.Extension.Equals(".psd1", StringComparison.OrdinalIgnoreCase) ? "PSModule" : "PSScript"; - metadataElementsDictionary.Add("tags", tags); - - if (parsedMetadataHash.ContainsKey("licenseurl") || !String.IsNullOrEmpty(_licenseUrl)) - { - var licenseUrl = string.IsNullOrEmpty(_licenseUrl) ? parsedMetadataHash["licenseurl"].ToString().Trim() : _licenseUrl; - metadataElementsDictionary.Add("licenseUrl", licenseUrl); - } - - if (parsedMetadataHash.ContainsKey("projecturl") || !String.IsNullOrEmpty(_projectUrl)) - { - var projectUrl = string.IsNullOrEmpty(_projectUrl) ? parsedMetadataHash["projecturl"].ToString().Trim() : _projectUrl; - metadataElementsDictionary.Add("projectUrl", projectUrl); - } - - if (parsedMetadataHash.ContainsKey("iconurl") || !String.IsNullOrEmpty(_iconUrl)) - { - var iconUrl = string.IsNullOrEmpty(_iconUrl) ? parsedMetadataHash["iconurl"].ToString().Trim() : _iconUrl; - metadataElementsDictionary.Add("iconUrl", iconUrl); - } - - - foreach (var key in metadataElementsDictionary.Keys) - { - XmlElement element = doc.CreateElement(key, nameSpaceUri); - - string elementInnerText; - metadataElementsDictionary.TryGetValue(key, out elementInnerText); - element.InnerText = elementInnerText; - - metadataElement.AppendChild(element); - } - - var requiredModules = ParseRequiredModules(parsedMetadataHash); - if (requiredModules != null) - { - XmlElement dependenciesElement = doc.CreateElement("dependencies", nameSpaceUri); - - foreach (Hashtable dependency in requiredModules) - { - XmlElement element = doc.CreateElement("dependency", nameSpaceUri); - - element.SetAttribute("id", dependency["ModuleName"].ToString()); - if (!string.IsNullOrEmpty(dependency["ModuleVersion"].ToString())) - { - element.SetAttribute("version", dependency["ModuleVersion"].ToString()); - } - - dependenciesElement.AppendChild(element); - } - metadataElement.AppendChild(dependenciesElement); - } - - packageElement.AppendChild(metadataElement); - doc.AppendChild(packageElement); - - var nuspecFullName = System.IO.Path.Combine(outputDir, pkgName + ".nuspec"); - doc.Save(nuspecFullName); - - this.WriteVerbose("The newly created nuspec is: " + nuspecFullName); - - return nuspecFullName; - } - - private Hashtable[] ParseRequiredModules(Hashtable parsedMetadataHash) - { - if (!parsedMetadataHash.ContainsKey("requiredmodules")) - { - return null; - } - - var requiredModules = parsedMetadataHash["requiredmodules"]; - - // Required modules can be: - // a. An array of hash tables of module name and version - // b. A single hash table of module name and version - // c. A string array of module names - // d. A single string module name - - if (LanguagePrimitives.TryConvertTo(requiredModules, out Hashtable[] moduleList)) - { - return moduleList; - } - - if (LanguagePrimitives.TryConvertTo(requiredModules, out string[] moduleNames)) - { - var listHashtable = new List(); - foreach (var modName in moduleNames) - { - listHashtable.Add( - new Hashtable() { - { "ModuleName", modName }, - { "ModuleVersion", string.Empty } - }); - } - - return listHashtable.ToArray(); - } - - return null; - } - - private void ParseScriptMetadata(Hashtable parsedMetadataHash, FileInfo moduleFileInfo) - { - // parse .ps1 - example .ps1 metadata: - /* <#PSScriptInfo - .VERSION 1.6 - .GUID abf490023 - 9128 - 4323 - sdf9a - jf209888ajkl - .AUTHOR Jane Doe - .COMPANYNAME Microsoft - .COPYRIGHT - .TAGS Windows MacOS - #> - - <# - .SYNOPSIS - Synopsis description here - .DESCRIPTION - Description here - .PARAMETER Name - .EXAMPLE - Example cmdlet here - #> - */ - - using (StreamReader sr = File.OpenText(moduleFileInfo.FullName)) - { - string endOfMetadata = "#>"; - - // metadata for scripts are divided into two parts - string str = String.Empty; - - // read until the beginning of the metadata is hit "<#PSScriptInfo" - do - { - str = sr.ReadLine(); - } - while (str != null && !string.Equals(str.Trim(), "<#PSScriptInfo", StringComparison.OrdinalIgnoreCase)); - - string key = String.Empty; - string value; - // Then start reading metadata - do - { - str = sr.ReadLine(); - value = String.Empty; - - if (str != null && str.StartsWith(".", StringComparison.OrdinalIgnoreCase)) - { - // Create new key - if (str.IndexOf(" ") > 0) - { - key = str.Substring(1, str.IndexOf(" ") - 1).ToLower(); - var startIndex = str.IndexOf(" ") + 1; - value = str.Substring(startIndex, str.Length - startIndex); - } - else - { - key = str.Substring(1, str.Length - 1).ToLower(); - } - - try - { - parsedMetadataHash.Add(key, value); - } - catch (Exception e) - { - var message = String.Format("Failed to add key '{0}' and value '{1}' to hashtable. Error: {2}", key, value, e.Message); - var ex = new ArgumentException(message); - var metadataCannotBeAdded = new ErrorRecord(ex, "metadataCannotBeAdded", ErrorCategory.MetadataError, null); - - this.ThrowTerminatingError(metadataCannotBeAdded); - } - } - else - { - if (!String.IsNullOrEmpty(key)) - { - // Append to existing key/value - parsedMetadataHash[key] = parsedMetadataHash[key] + " " + str; - } - } - } - while (str != null && str.Trim() != endOfMetadata); - - // Read until the beginning of the next metadata section - // Note there may only be one metadata section - try - { - do - { - str = sr.ReadLine(); - } - while (str != null && str.Trim() != "<#"); - } - catch - { - var message = "Error parsing metadata for script."; - var ex = new ArgumentException(message); - var errorParsingScriptMetadata = new ErrorRecord(ex, "errorParsingScriptMetadata", ErrorCategory.ParserError, null); - - this.ThrowTerminatingError(errorParsingScriptMetadata); - } - - // Then start reading metadata again. - str = String.Empty; - key = String.Empty; - - try - { - do - { - str = sr.ReadLine(); - value = String.Empty; - - if (str != null && str.StartsWith(".", StringComparison.OrdinalIgnoreCase)) - { - // create new key - if (str.IndexOf(" ") > 0) - { - key = str.Substring(1, str.IndexOf(" ") - 1).ToLower(); - var startIndex = str.IndexOf(" ") + 1; - value = str.Substring(startIndex, str.Length - startIndex); - } - else - { - key = str.Substring(1, str.Length - 1).ToLower(); - } - - try - { - parsedMetadataHash.Add(key, value); - } - catch - { - var message = String.Format("Failed to add key '{0}' and value '{1}' to hashtable", key, value); - var ex = new ArgumentException(message); - var errorParsingScriptMetadata = new ErrorRecord(ex, "errorParsing", ErrorCategory.ParserError, null); - - this.ThrowTerminatingError(errorParsingScriptMetadata); - } - } - else - { - // append to existing key/value - if (!String.IsNullOrEmpty(key)) - { - parsedMetadataHash[key] = parsedMetadataHash[key] + " " + str; - } - } - } - while (str != null && str.Trim() != endOfMetadata); - } - catch - { - var message = "Error parsing metadata for script"; - var ex = new ArgumentException(message); - var errorParsingScriptMetadata = new ErrorRecord(ex, "errorParsingScriptMetadata", ErrorCategory.ParserError, null); - - this.ThrowTerminatingError(errorParsingScriptMetadata); - } - } - } - } -} diff --git a/srcOld/code/RegisterPSResourceRepository.cs b/srcOld/code/RegisterPSResourceRepository.cs deleted file mode 100644 index 2e1075d1e..000000000 --- a/srcOld/code/RegisterPSResourceRepository.cs +++ /dev/null @@ -1,263 +0,0 @@ - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Management.Automation; -using System.Globalization; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using System.Collections.Generic; -using System.Linq; -using System.IO; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Register-PSResourceRepository cmdlet registers the default repository for PowerShell modules. - /// After a repository is registered, you can reference it from the Find-PSResource, Install-PSResource, and Publish-PSResource cmdlets. - /// The registered repository becomes the default repository in Find-Module and Install-Module. - /// It returns nothing. - /// - - [Cmdlet(VerbsLifecycle.Register, "PSResourceRepository", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class RegisterPSResourceRepository : PSCmdlet - { - private string PSGalleryRepoName = "PSGallery"; - private string PSGalleryRepoURL = "https://www.powershellgallery.com/api/v2"; - - /// - /// Specifies the desired name for the repository to be registered. - /// - [Parameter(Mandatory = true, Position = 0, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Name - { - get - { return _name; } - - set - { _name = value; } - } - private string _name; - - /// - /// Specifies the location of the repository to be registered. - /// - [Parameter(Mandatory = true, Position = 1, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public Uri URL - { - get - { return _url; } - - set - { - Uri url; - if (!Uri.TryCreate(value, string.Empty, out url)) - { - // Try the URL as a file path - var resolvedPath = string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", Uri.UriSchemeFile, Uri.SchemeDelimiter, SessionState.Path.GetResolvedPSPathFromPSPath(value.ToString()).FirstOrDefault().Path); - if (!Uri.TryCreate(resolvedPath, UriKind.Absolute, out url)) - { - var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0}", value); - var ex = new ArgumentException(message); - var moduleManifestNotFound = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(moduleManifestNotFound); - } - } - - _url = url; - } - } - private Uri _url; - - /// - /// Registers the PowerShell Gallery. - /// - [Parameter(Mandatory = true, ParameterSetName = "PSGalleryParameterSet")] - public SwitchParameter PSGallery - { - get - { return _psgallery; } - - set - { _psgallery = value; } - } - private SwitchParameter _psgallery; - - /// - /// Repositories is a hashtable and is used to register multiple repositories at once. - /// - [Parameter(Mandatory = true, ParameterSetName = "RepositoriesParameterSet")] - [ValidateNotNullOrEmpty] - public List Repositories - { - get { return _repositories; } - - set { _repositories = value; } - } - private List _repositories; - - /// - /// Specifies whether the repository should be trusted. - /// - [Parameter(ParameterSetName = "PSGalleryParameterSet")] - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter Trusted - { - get { return _trusted; } - - set { _trusted = value; } - } - private SwitchParameter _trusted; - - /// - /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - [ValidateNotNullOrEmpty] - public Uri Proxy - { - get - { return _proxy; } - - set - { _proxy = value; } - } - private Uri _proxy; - - /// - /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public PSCredential ProxyCredential - { - get - { return _proxyCredential; } - - set - { _proxyCredential = value; } - } - private PSCredential _proxyCredential; - - /// - /// The following is the definition of the input parameter "Port". - /// Specifies the port to be used when connecting to the ws management service. - /// - [Parameter(ParameterSetName = "PSGalleryParameterSet")] - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - [ValidateRange(0, 50)] - public int Priority - { - get { return _priority; } - - set { _priority = value; } - } - private int _priority = 50; - - /// - /// - protected override void ProcessRecord() - { - var r = new RespositorySettings(); - - if (ParameterSetName.Equals("PSGalleryParameterSet")) - { - if (!_psgallery) - { - return; - } - - /// collect parameters and make one call - var psGalleryUri = new Uri(PSGalleryRepoURL); - - try - { - r.Add(PSGalleryRepoName, psGalleryUri, _priority, _trusted); - } - catch (Exception e) - { - throw new Exception(e.Message); - } - - } - else if (ParameterSetName.Equals("NameParameterSet")) - { - if (String.IsNullOrEmpty(_name)) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository name cannot be null")); - } - if (String.IsNullOrEmpty(_url.ToString())) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository url cannot be null")); - } - - try - { - r.Add(_name, _url, _priority, _trusted); - } - catch (Exception e) - { - throw new Exception(e.Message); - } - } - else if (ParameterSetName.Equals("RepositoriesParameterSet")) - { - foreach (var repo in _repositories) - { - if (repo.ContainsKey(PSGalleryRepoName) ) - { - var _psGalleryRepoURL = new Uri(PSGalleryRepoURL); - int _psGalleryRepoPriority = repo.ContainsKey("Priority") ? (int)repo["Priority"] : 50; - var _psGalleryRepoTrusted = repo.ContainsKey("Trusted") ? (bool)repo["Trusted"] : false; - - r.Add(PSGalleryRepoName, _psGalleryRepoURL, _psGalleryRepoPriority, _psGalleryRepoTrusted); - continue; - } - - // check if key exists - if (!repo.ContainsKey("Name") || String.IsNullOrEmpty(repo["Name"].ToString())) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository name cannot be null")); - } - if (!repo.ContainsKey("Url") || String.IsNullOrEmpty(repo["Url"].ToString())) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository url cannot be null")); - } - - // https://docs.microsoft.com/en-us/dotnet/api/system.uri.trycreate?view=netframework-4.8#System_Uri_TryCreate_System_Uri_System_Uri_System_Uri__ - // convert the string to a url and check to see if the url is formatted correctly - Uri _repoURL; - if (!(Uri.TryCreate(repo["URL"].ToString(), UriKind.Absolute, out _repoURL) - && (_repoURL.Scheme == Uri.UriSchemeHttp || _repoURL.Scheme == Uri.UriSchemeHttps || _repoURL.Scheme == Uri.UriSchemeFtp || _repoURL.Scheme == Uri.UriSchemeFile))) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid Url")); - } - - int _repoPriority = 50; - if (repo.ContainsKey("Priority")) - { - _repoPriority = Convert.ToInt32(repo["Priority"].ToString()); - } - - bool _repoTrusted = false; - if (repo.ContainsKey("Trusted")) - { - _repoTrusted = Convert.ToBoolean(repo["Trusted"].ToString()); - } - - r.Add(repo["Name"].ToString(), _repoURL, _repoPriority, _repoTrusted); - } - } - else if (_name.Equals(PSGalleryRepoName)) - { - //throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, Messages.UsePSGalleryParameterSetOnRegister)); - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Use PSGallery Parmenter Set on Register")); - } - } - } -} \ No newline at end of file diff --git a/srcOld/code/RepositorySettings.cs b/srcOld/code/RepositorySettings.cs deleted file mode 100644 index bf337b4a5..000000000 --- a/srcOld/code/RepositorySettings.cs +++ /dev/null @@ -1,296 +0,0 @@ - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using System; -using System.IO; -using System.Collections.Generic; -using System.Management.Automation; -using System.Xml.Linq; -using System.Linq; -using static System.Environment; - -namespace Microsoft.PowerShell.PowerShellGet.RepositorySettings -{ - /// - /// Repository settings - /// - - class RespositorySettings - { - /// - /// Default file name for a settings file is 'psresourcerepository.config' - /// Also, the user level setting file at '%APPDATA%\NuGet' always uses this name - /// - public static readonly string DefaultRepositoryFileName = "PSResourceRepository.xml"; - public static readonly string DefaultRepositoryPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet"); //"%APPDATA%/PowerShellGet"; // c:\code\temp\repositorycache - public static readonly string DefaultFullRepositoryPath = Path.Combine(DefaultRepositoryPath, DefaultRepositoryFileName); - - public RespositorySettings() { } - - /// - /// Find a repository XML - /// Returns: - /// - /// - public bool FindRepositoryXML() - { - // Search in the designated location for the repository XML - if (File.Exists(DefaultFullRepositoryPath)) - { - return true; - } - - return false; - } - - /// - /// Create a new repository XML - /// Returns: void - /// - /// - public void CreateNewRepositoryXML() - { - // Check to see if the file already exists; if it does return - if (FindRepositoryXML()) - { - return; - } - - // create directory if needed - if (!Directory.Exists(DefaultRepositoryPath)) - { - Directory.CreateDirectory(DefaultRepositoryPath); - } - - // If the repository xml file doesn't exist yet, create one - XDocument newRepoXML = new XDocument( - new XElement("configuration") - ); - - // Should be saved in: - newRepoXML.Save(DefaultFullRepositoryPath); - } - - /// - /// Add a repository to the XML - /// Returns: void - /// - /// - public void Add(string repoName, Uri repoURL, int repoPriority, bool repoTrusted) - { - // Check to see if information we're trying to add to the repository is valid - if (string.IsNullOrEmpty(repoName)) - { - // throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(sectionName)); - throw new ArgumentException("Repository name cannot be null or empty"); - } - if (string.IsNullOrEmpty(repoURL.ToString())) - { - // throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(sectionName)); - throw new ArgumentException("Repository URL cannot be null or empty"); - } - - // Create will make a new XML if one doesn't already exist - try - { - CreateNewRepositoryXML(); - } - catch - { - throw new ArgumentException("Was not able to successfully create xml"); - } - - // Open file - XDocument doc = XDocument.Load(DefaultFullRepositoryPath); - - // Check if what's being added already exists, if it does throw an error - var node = doc.Descendants("Repository").Where(e => string.Equals(e.Attribute("Name").Value, repoName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - - if (node != null) - { - throw new ArgumentException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); - } - - // Else, keep going - // Get root of XDocument (XElement) - var root = doc.Root; - - // Create new element - XElement newElement = new XElement( - "Repository", - new XAttribute("Name", repoName), - new XAttribute("Url", repoURL), - new XAttribute("Priority", repoPriority), - new XAttribute("Trusted", repoTrusted) - ); - - root.Add(newElement); - - // Close the file - root.Save(DefaultFullRepositoryPath); - } - - /// - /// Updates a repository name, URL, priority, or installation policy - /// Returns: void - /// - public void Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted) - { - // Check to see if information we're trying to add to the repository is valid - if (string.IsNullOrEmpty(repoName)) - { - // throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(sectionName)); - throw new ArgumentException("Repository name cannot be null or empty"); - } - - // We expect the xml to exist, if it doesn't user needs to register a repository - try - { - FindRepositoryXML(); - } - catch - { - throw new ArgumentException("Was not able to successfully find xml. Try running 'Register-PSResourceRepository -PSGallery'"); - } - - // Open file - XDocument doc = XDocument.Load(DefaultFullRepositoryPath); - - // Check if what's being updated is actually there first - var node = doc.Descendants("Repository").Where(e => string.Equals(e.Attribute("Name").Value, repoName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - if (node == null) - { - throw new ArgumentException("Cannot find the repository because it does not exist. Try registering the repository using 'Register-PSResourceRepository'"); - } - - // Else, keep going - // Get root of XDocument (XElement) - var root = doc.Root; - - if (repoURL != null) - { - node.Attribute("Url").Value = repoURL.AbsoluteUri; - } - if (repoPriority >= 0) - { - node.Attribute("Priority").Value = repoPriority.ToString(); - } - // false, setting to true - // true, setting to false - // false setting to false - // true setting to true - - if (repoTrusted != null) - { - node.Attribute("Trusted").Value = repoTrusted.ToString(); - } - - // Close the file - root.Save(DefaultFullRepositoryPath); - } - - /// - /// Removes a repository from the XML - /// Returns: void - /// - /// - public void Remove(string[] repoNames) - { - - // Check to see if information we're trying to add to the repository is valid - if (repoNames == null || repoNames.Length == 0) - { - // throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(sectionName)); - throw new ArgumentException("Repository name cannot be null or empty"); - } - - if (!FindRepositoryXML()) - { - throw new ArgumentException("Was not able to successfully find xml. Try running 'Register-PSResourceRepository -PSGallery'"); - } - - // Open file - XDocument doc = XDocument.Load(DefaultFullRepositoryPath); - - // Get root of XDocument (XElement) - var root = doc.Root; - - foreach (var repo in repoNames) - { - // Check if what's being added doesn't already exist, throw an error - var node = doc.Descendants("Repository").Where(e => string.Equals(e.Attribute("Name").Value, repo, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - - if (node == null) - { - throw new ArgumentException(String.Format("Unable to find repository '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); - } - - // Remove item from file - node.Remove(); - } - - // Close the file - root.Save(DefaultFullRepositoryPath); - } - - public List Read(string[] repoNames) - { - // Can be null, will just retrieve all - // Call FindRepositoryXML() [Create will make a new xml if one doesn't already exist] - if (!FindRepositoryXML()) - { - throw new ArgumentException("Was not able to successfully find xml. Try running 'Register-PSResourceRepository -PSGallery'"); - } - - // Open file - XDocument doc = XDocument.Load(DefaultFullRepositoryPath); - - var foundRepos = new List(); - if (repoNames == null || !repoNames.Any() || string.Equals(repoNames[0], "*") || repoNames[0] == null) - { - // array is null and we will list all repositories - // iterate through the doc - foreach (var repo in doc.Descendants("Repository")) - { - PSObject repoAsPSObject = new PSObject(); - repoAsPSObject.Members.Add(new PSNoteProperty("Name", repo.Attribute("Name").Value)); - repoAsPSObject.Members.Add(new PSNoteProperty("Url", repo.Attribute("Url").Value)); - repoAsPSObject.Members.Add(new PSNoteProperty("Trusted", repo.Attribute("Trusted").Value)); - repoAsPSObject.Members.Add(new PSNoteProperty("Priority", repo.Attribute("Priority").Value)); - - foundRepos.Add(repoAsPSObject); - } - } - else - { - foreach (var repo in repoNames) - { - // Check to see if repository exists - // need to fix the case sensitivity - var node = doc.Descendants("Repository").Where(e => string.Equals(e.Attribute("Name").Value, repo, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - - if (node != null) - { - PSObject repoAsPSObject = new PSObject(); - repoAsPSObject.Members.Add(new PSNoteProperty("Name", node.Attribute("Name").Value)); - repoAsPSObject.Members.Add(new PSNoteProperty("Url", node.Attribute("Url").Value)); - repoAsPSObject.Members.Add(new PSNoteProperty("Trusted", node.Attribute("Trusted").Value)); - repoAsPSObject.Members.Add(new PSNoteProperty("Priority", node.Attribute("Priority").Value)); - - foundRepos.Add(repoAsPSObject); - } - } - } - - - // Sort by priority, then by repo name - // foundRepos.Sort((x, y) => ( Int32.Parse((x.Members.Where(m => m.Name.Equals("Priority"))).FirstOrDefault().Value.ToString()).CompareTo( Int32.Parse((y.Members.Where(m2 => m2.Name.Equals("Priority"))).FirstOrDefault().Value.ToString()) ) )); - var reposToReturn = foundRepos.OrderBy(x => (Int32.Parse((x.Members.Where(m => m.Name.Equals("Priority"))).FirstOrDefault().Value.ToString()))) - .ThenBy(x => (x.Members.Where(m => m.Name.Equals("Name"))).FirstOrDefault().Value.ToString()); - - return reposToReturn.ToList(); - } - } -} diff --git a/srcOld/code/ResourceSettings.cs b/srcOld/code/ResourceSettings.cs deleted file mode 100644 index 4461bae82..000000000 --- a/srcOld/code/ResourceSettings.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Management.Automation; -using System.Xml.Linq; -using System.Linq; - -namespace Microsoft.PowerShell.PowerShellGet.ResourceSettings -{ - /// - /// Repository settings - /// - - class ResourceSettings - { - /// - /// Default file name for a settings file is 'psresourcerepository.config' - /// Also, the user level setting file at '%APPDATA%\NuGet' always uses this name - /// - - - - } -} \ No newline at end of file diff --git a/srcOld/code/SavePSResource.cs b/srcOld/code/SavePSResource.cs deleted file mode 100644 index 6124bea4e..000000000 --- a/srcOld/code/SavePSResource.cs +++ /dev/null @@ -1,222 +0,0 @@ -using System; -using System.Collections; -using System.Management.Automation; -using System.Collections.Generic; -using System.Threading; -using NuGet.Versioning; -using static System.Environment; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - - - /// - /// The Save-PSResource cmdlet saves a resource, either packed or unpacked. - /// It returns nothing. - /// - - [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class SavePSResource : PSCmdlet - { - /// - /// Specifies the exact names of resources to save from a repository. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name; // = new string[0]; - - /// - /// Specifies the version or version range of the package to be saved - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Version - { - get - { return _version; } - - set - { _version = value; } - } - private string _version; - - /// - /// Specifies to allow installation of prerelease versions - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter Prerelease - { - get - { return _prerelease; } - - set - { _prerelease = value; } - } - private SwitchParameter _prerelease; - - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Repository - { - get - { return _repository; } - - set - { _repository = value; } - } - private string[] _repository; - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - public PSCredential Credential - { - get - { return _credential; } - - set - { _credential = value; } - } - private PSCredential _credential; - - /// - /// Saves as a .nupkg - /// - [Parameter()] - public SwitchParameter AsNupkg - { - get { return _asNupkg; } - - set { _asNupkg = value; } - } - private SwitchParameter _asNupkg; - - /// - /// Saves the metadata XML file with the resource - /// - [Parameter()] - public SwitchParameter IncludeXML - { - get { return _includeXML; } - - set { _includeXML = value; } - } - private SwitchParameter _includeXML; - - /// - /// The destination where the resource is to be installed. Works for all resource types. - /// - [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Path - { - get - { return _path; } - - set - { _path = value; } - } - private string _path; - - /// - /// Suppresses being prompted for untrusted sources. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter TrustRepository - { - get { return _trustRepository; } - - set { _trustRepository = value; } - } - private SwitchParameter _trustRepository; - - - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "InputObjectSet")] - [ValidateNotNullOrEmpty] - public object[] InputObject - { - get - { return _inputObject; } - - set - { _inputObject = value; } - } - private object[] _inputObject; - - // This will be a list of all the repository caches - public static readonly List RepoCacheFileName = new List(); - public static readonly string RepositoryCacheDir = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet", "RepositoryCache"); - public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - - - /// - /// - protected override void ProcessRecord() - { // Define the cancellation token. - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - - // If PSModuleInfo object - if (_inputObject != null && _inputObject[0].GetType().Name.Equals("PSModuleInfo")) - { - foreach (PSModuleInfo pkg in _inputObject) - { - //var prerelease = false; - if (pkg.PrivateData != null) - { - Hashtable privateData = (Hashtable)pkg.PrivateData; - if (privateData.ContainsKey("PSData")) - { - Hashtable psData = (Hashtable)privateData["PSData"]; - if (psData.ContainsKey("Prerelease") && !string.IsNullOrEmpty((string)psData["Prerelease"])) - { - //prerelease = true; - } - } - } - var installHelp = new InstallHelper(update: false, save: true, cancellationToken, this); - - installHelp.ProcessInstallParams(_name, _version, _prerelease, _repository, _scope: null, _acceptLicense: false, _quiet: false, _reinstall: false, _force: false, _trustRepository, _noClobber: false, _credential, _requiredResourceFile: null, _requiredResourceJson: null, _requiredResourceHash: null, _path, _asNupkg, _includeXML); - } - } - else if (_inputObject != null && _inputObject[0].GetType().Name.Equals("PSObject")) - { - // If PSObject - foreach (PSObject pkg in _inputObject) - { - var installHelp = new InstallHelper(update:false, save:true, cancellationToken, this); - if (pkg != null) - { - var name = (string)pkg.Properties["Name"].Value; - var version = (NuGetVersion)pkg.Properties["Version"].Value; - var prerelease = version.IsPrerelease; - - installHelp.ProcessInstallParams(new[] { name }, version.ToString(), prerelease, _repository, _scope:null, _acceptLicense:false, _quiet:false, _reinstall:false, _force: false, _trustRepository, _noClobber:false, _credential, _requiredResourceFile:null, _requiredResourceJson:null, _requiredResourceHash:null, _path, _asNupkg, _includeXML); - } - } - } - - var installHelper = new InstallHelper(update:false, save:true, cancellationToken, this); - installHelper.ProcessInstallParams(_name, _version, _prerelease, _repository, _scope:null, _acceptLicense: false, _quiet:false, _reinstall:false, _force: false, _trustRepository, _noClobber:false, _credential, _requiredResourceFile:null, _requiredResourceJson:null, _requiredResourceHash:null, _path, _asNupkg, _includeXML); - } - } -} \ No newline at end of file diff --git a/srcOld/code/SetPSResourceRepository.cs b/srcOld/code/SetPSResourceRepository.cs deleted file mode 100644 index 0bc2cd7e9..000000000 --- a/srcOld/code/SetPSResourceRepository.cs +++ /dev/null @@ -1,263 +0,0 @@ - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using System; -using System.Collections; -using System.Management.Automation; -using System.Globalization; -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using System.Collections.Generic; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Set-PSResourceRepository cmdlet sets properties for repositories. - /// After a repository is registered, you can reference it from the Find-PSResource, Install-PSResource, and Publish-PSResource cmdlets. - /// The registered repository becomes the default repository in Find-Module and Install-Module. - /// It returns nothing. - /// - [Cmdlet(VerbsCommon.Set, "PSResourceRepository", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class SetPSResourceRepository : PSCmdlet - { - // private string PSGalleryRepoName = "PSGallery"; - - /// - /// Specifies the desired name for the repository to be set. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string Name - { - get - { return _name; } - - set - { _name = value; } - } - private string _name; - - - /// - /// Specifies the location of the repository to be set. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public Uri URL - { - get - { return _url; } - - set - { _url = value; } - } - private Uri _url = null; - - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - public PSCredential Credential - { - get - { return _credential; } - - set - { _credential = value; } - } - private PSCredential _credential = null; - - - /// - /// Repositories is a hashtable and is used to register multiple repositories at once. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "RepositoriesParameterSet")] - [ValidateNotNullOrEmpty] - public List Repositories - { - get { return _repositories; } - - set { _repositories = value; } - } - private List _repositories; - - - /// - /// Specifies whether the repository should be trusted. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter Trusted - { - get { return _trusted; } - - set { _trusted = value; isSet = true; } - } - private SwitchParameter _trusted; - private bool isSet = false; /***************************************************/ - - - /// - /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - [ValidateNotNullOrEmpty] - public Uri Proxy - { - get - { return _proxy; } - - set - { _proxy = value; } - } - private Uri _proxy; - - - /// - /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public PSCredential ProxyCredential - { - get - { return _proxyCredential; } - - set - { _proxyCredential = value; } - } - private PSCredential _proxyCredential; - - - /// - /// The following is the definition of the input parameter "Port". - /// Specifies the port to be used when connecting to the ws management service. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - [ValidateNotNullOrEmpty] - [ValidateRange(0, 50)] - public int Priority - { - get { return _priority; } - - set { _priority = value; } - } - private int _priority = -1; - - - - - /// - /// - protected override void ProcessRecord() - { - var r = new RespositorySettings(); - - if (ParameterSetName.Equals("NameParameterSet")) - { - bool? _trustedNullable = isSet ? new bool?(_trusted) : new bool?(); - - if (_name.Equals("PSGallery")) - { - // if attempting to set -url with PSGallery, throw an error - if (_url != null) - { - throw new System.ArgumentException("The PSGallery repository has a pre-defined URL. The -URL parmeter is not allowed, try running 'Register-PSResourceRepository -PSGallery'."); - } - - Uri galleryURL = new Uri("https://www.powershellgallery.com/api/v2"); - - // name is the only thing that won't get updated - r.Update("PSGallery", galleryURL, _priority, _trustedNullable); - - } - - if (String.IsNullOrEmpty(_name)) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository name cannot be null.")); - } - - // https://docs.microsoft.com/en-us/dotnet/api/system.uri.trycreate?view=netframework-4.8#System_Uri_TryCreate_System_Uri_System_Uri_System_Uri__ - // check to see if the url is formatted correctly - if (_url != null && !(Uri.TryCreate(_url.ToString(), UriKind.Absolute, out _url) - && (_url.Scheme == Uri.UriSchemeHttp || _url.Scheme == Uri.UriSchemeHttps || _url.Scheme == Uri.UriSchemeFile || _url.Scheme == Uri.UriSchemeFtp))) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid Url")); - } - - r.Update(_name, _url, _priority, _trustedNullable); - } - else if (ParameterSetName.Equals("RepositoriesParameterSet")) - { - foreach (var repo in _repositories) - { - if (repo.ContainsKey("PSGallery")) - { - // if attempting to set -URL with -PSGallery, throw an error - if (_url != null) - { - throw new System.ArgumentException("The PSGallery repository has a pre-defined URL. The -URL parmeter is not allowed, try again after removing -URL."); - } - - var _psGalleryRepoName = "PSGallery"; - Uri _psGalleryRepoURL = new Uri("https://www.powershellgallery.com/api/v2"); - int _psGalleryRepoPriority = repo.ContainsKey("Priority") ? (int)repo["Priority"] : 50; - - bool? _psGalleryRepoTrusted = repo.ContainsKey("Trusted") ? (bool?)repo["Trusted"] : null; - - Uri galleryURL = new Uri("https://www.powershellgallery.com"); - - r.Update(_psGalleryRepoName, _psGalleryRepoURL, _psGalleryRepoPriority, _psGalleryRepoTrusted); - - continue; - } - - // check if key exists - if (!repo.ContainsKey("Name") || String.IsNullOrEmpty(repo["Name"].ToString())) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository name cannot be null.")); - } - if (!repo.ContainsKey("Url") || String.IsNullOrEmpty(repo["Url"].ToString())) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Repository url cannot be null.")); - } - - // https://docs.microsoft.com/en-us/dotnet/api/system.uri.trycreate?view=netframework-4.8#System_Uri_TryCreate_System_Uri_System_Uri_System_Uri__ - // convert the string to a url and check to see if the url is formatted correctly - /// Checked URL - Uri _repoURL; - if (!(Uri.TryCreate(repo["URL"].ToString(), UriKind.Absolute, out _repoURL) - && (_repoURL.Scheme == Uri.UriSchemeHttp || _repoURL.Scheme == Uri.UriSchemeHttps || _repoURL.Scheme == Uri.UriSchemeFtp || _repoURL.Scheme == Uri.UriSchemeFile))) - { - throw new System.ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid Url")); - } - - int _repoPriority = 50; - if (repo.ContainsKey("Priority")) - { - _repoPriority = Convert.ToInt32(repo["Priority"].ToString()); - } - - bool? _repoTrusted = repo.ContainsKey("Trusted") ? (bool?)repo["Trusted"] : null; - - r.Update(repo["Name"].ToString(), _repoURL, _repoPriority, _repoTrusted); - } - } - } - - - /// - /// - protected override void EndProcessing() - { - - } - } -} - - - diff --git a/srcOld/code/UnregisterPSResourceRepository.cs b/srcOld/code/UnregisterPSResourceRepository.cs deleted file mode 100644 index 0f39e6e8b..000000000 --- a/srcOld/code/UnregisterPSResourceRepository.cs +++ /dev/null @@ -1,65 +0,0 @@ - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using Microsoft.PowerShell.PowerShellGet.RepositorySettings; -using System; -using System.Management.Automation; - - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - - /// - /// The Register-PSResourceRepository cmdlet registers the default repository for PowerShell modules. - /// After a repository is registered, you can reference it from the Find-PSResource, Install-PSResource, and Publish-PSResource cmdlets. - /// The registered repository becomes the default repository in Find-Module and Install-Module. - /// It returns nothing. - /// - - [Cmdlet(VerbsLifecycle.Unregister, "PSResourceRepository", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class UnregisterPSResourceRepository : PSCmdlet - { - // private string PSGalleryRepoName = "PSGallery"; - - /// - /// Specifies the desired name for the repository to be registered. - /// - [Parameter(Mandatory= true, Position = 0, ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name; - - - - - /// - /// - protected override void ProcessRecord() - { - var r = new RespositorySettings(); - - // need to check if name is null? - try - { - r.Remove(_name); - } - catch (Exception e){ - throw new Exception(string.Format("Unable to successfully unregister repository: {0}", e.Message)); - } - } - - } -} diff --git a/srcOld/code/UpdatePSResource.cs b/srcOld/code/UpdatePSResource.cs deleted file mode 100644 index 0449b6f51..000000000 --- a/srcOld/code/UpdatePSResource.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System.Management.Automation; -using System.Threading; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Update-PSResource cmdlet updates a previously installed resource. - /// It returns nothing. - /// - [Cmdlet(VerbsData.Update, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, - HelpUri = "", RemotingCapability = RemotingCapability.None)] - public sealed - class UpdatePSResource : PSCmdlet - { - /// - /// Specifies the exact names of resources to update. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Name - { - get - { return _name; } - - set - { _name = value; } - } - private string[] _name; - - /* - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "InputObjectSet")] - [ValidateNotNullOrEmpty] - public PSCustomObject[] InputObject - { - get - { return _inputObject; } - - set - { _inputObject = value; } - } - private PSCustomObject[] _inputObject; - */ - - /// - /// Specifies the version or version range of the package to update. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string Version - { - get - { return _version; } - set - { _version = value; } - } - private string _version; - - /// - /// Specifies to allow updates to prerelease versions. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter Prerelease - { - get - { return _prerelease; } - - set - { _prerelease = value; } - } - private SwitchParameter _prerelease; - - /// - /// Specifies the repositories from which to update the resource. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [ValidateNotNullOrEmpty] - public string[] Repository - { - get - { return _repository; } - - set - { _repository = value; } - } - private string[] _repository; - - /// - /// Specifies the scope of the resource to update. - /// - [ValidateSet("CurrentUser", "AllUsers")] - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public string Scope - { - get { return _scope; } - - set { _scope = value; } - } - private string _scope; - - /// - /// Suppresses being prompted for untrusted sources. - /// - [Parameter(ParameterSetName = "NameParameterSet")] - [Parameter(ParameterSetName = "RequiredResourceFileParameterSet")] - public SwitchParameter TrustRepository - { - get { return _trustRepository; } - - set { _trustRepository = value; } - } - private SwitchParameter _trustRepository; - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] - public PSCredential Credential - { - get - { return _credential; } - - set - { _credential = value; } - } - private PSCredential _credential; - - /// - /// Suppresses progress information. - /// - [Parameter()] - public SwitchParameter Quiet - { - get { return _quiet; } - - set { _quiet = value; } - } - private SwitchParameter _quiet; - - /// - /// For modules that require a license, AcceptLicense automatically accepts the license agreement during update. - /// - [Parameter()] - public SwitchParameter AcceptLicense - { - get { return _acceptLicense; } - - set { _acceptLicense = value; } - } - private SwitchParameter _acceptLicense; - - /// - /// Overrides warning messages about installation conflicts about existing commands on a computer. - /// Overwrites existing commands that have the same name as commands being installed by a module. AllowClobber and Force can be used together in an Install-Module command. - /// Prevents installing modules that have the same cmdlets as a differently named module already - /// - [Parameter(ParameterSetName = "NameParameterSet")] - public SwitchParameter NoClobber - { - get { return _noClobber; } - - set { _noClobber = value; } - } - private SwitchParameter _noClobber; - - - protected override void ProcessRecord() - { - // Define the cancellation token. - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - - var installHelper = new InstallHelper(update:true, save:false, cancellationToken, this); - installHelper.ProcessInstallParams(_name, _version, _prerelease, _repository, _scope, _acceptLicense, _quiet, _reinstall: false, _force: false, _trustRepository, _noClobber, _credential, _requiredResourceFile: null, _requiredResourceJson: null, _requiredResourceHash: null, _path:null, _asNupkg:false, _includeXML:true); - } - } -} \ No newline at end of file diff --git a/srcOld/code/Utilities.cs b/srcOld/code/Utilities.cs deleted file mode 100644 index e6c1f0fe3..000000000 --- a/srcOld/code/Utilities.cs +++ /dev/null @@ -1,158 +0,0 @@ - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - - -using System; -using System.Collections.Generic; -using static System.Environment; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Runtime.InteropServices; -using System.Collections; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet -{ - /// - /// Internal functions - /// - - static class Utilities - { - - public static VersionRange GetPkgVersion(string versionPassedIn) - { - // Check if exact version - NuGetVersion nugetVersion; - NuGetVersion.TryParse(versionPassedIn, out nugetVersion); - //NuGetVersion.TryParse(pkg.Identity.Version.ToString(), out nugetVersion); - - VersionRange versionRange = null; - if (nugetVersion != null) - { - versionRange = new VersionRange(nugetVersion, true, nugetVersion, true, null, null); - } - else - { - // Check if version range - VersionRange.TryParse(versionPassedIn, out versionRange); - } - - return versionRange; - } - - - public static Hashtable GetInstallationPaths(PSCmdlet cmdletPassedIn, string scope) - { - //this.WriteDebug(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; Scope: '{4}'; AcceptLicense: '{5}'; Quiet: '{6}'; Reinstall: '{7}'; TrustRepository: '{8}'; NoClobber: '{9}';", string.Join(",", _name), _version != null ? _version : string.Empty, _prerelease.ToString(), _repository != null ? string.Join(",", _repository) : string.Empty, _scope != null ? _scope : string.Empty, _acceptLicense.ToString(), _quiet.ToString(), _reinstall.ToString(), _trustRepository.ToString(), _noClobber.ToString())); - Hashtable hash = new Hashtable(); - //string osPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - string programFilesPath; - string myDocumentsPath; - - bool consoleIsElevated = false; - bool isWindowsPS = false; - cmdletPassedIn.WriteDebug("Entering GetPackageInstallationPaths"); -#if NET472 - // If WindowsPS - var id = System.Security.Principal.WindowsIdentity.GetCurrent(); - consoleIsElevated = (id.Owner != id.User); - isWindowsPS = true; - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "WindowsPowerShell"); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "WindowsPowerShell"); -#else - // If PS6+ on Windows - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var id = System.Security.Principal.WindowsIdentity.GetCurrent(); - consoleIsElevated = (id.Owner != id.User); - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "PowerShell"); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "PowerShell"); - } - else - { - // Paths are the same for both Linux and MacOS - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "powershell"); - programFilesPath = Path.Combine("/usr", "local", "share", "powershell"); - - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) - { - var uID = pwsh.AddScript("id -u").Invoke(); - foreach (var item in uID) - { - cmdletPassedIn.WriteDebug(string.Format("UID is: '{0}'", item)); - consoleIsElevated = (String.Equals(item.ToString(), "0")); - } - } - } -#endif - hash.Add("myDocumentsPath", myDocumentsPath); - hash.Add("programFilesPath", programFilesPath); - - cmdletPassedIn.WriteDebug(string.Format("Console is elevated: '{0}'", consoleIsElevated)); - cmdletPassedIn.WriteDebug(string.Format("Console is Windows PowerShell: '{0}'", isWindowsPS)); - cmdletPassedIn.WriteDebug(string.Format("Current user scope installation path: '{0}'", myDocumentsPath)); - cmdletPassedIn.WriteDebug(string.Format("All users scope installation path: '{0}'", programFilesPath)); - - scope = string.IsNullOrEmpty(scope) ? "CurrentUser" : scope; - cmdletPassedIn.WriteVerbose(string.Format("Scope is: {0}", scope)); - - string psPath = string.Equals(scope, "AllUsers") ? programFilesPath : myDocumentsPath; - hash.Add("psPath", psPath); - - string psModulesPath = Path.Combine(psPath, "Modules"); - hash.Add("psModulesPath", psModulesPath); - - string psScriptsPath = Path.Combine(psPath, "Scripts"); - hash.Add("psScriptsPath", psScriptsPath); - - string psInstalledScriptsInfoPath = Path.Combine(psScriptsPath, "InstalledScriptInfos"); - hash.Add("psInstalledScriptsInfoPath", psInstalledScriptsInfoPath); - - cmdletPassedIn.WriteDebug("Checking to see if paths exist"); - cmdletPassedIn.WriteDebug(string.Format("Path: '{0}' >>> exists? '{1}'", psModulesPath, Directory.Exists(psModulesPath))); - cmdletPassedIn.WriteDebug(string.Format("Path: '{0}' >>> exists? '{1}'", psScriptsPath, Directory.Exists(psScriptsPath))); - cmdletPassedIn.WriteDebug(string.Format("Path: '{0}' >>> exists? '{1}'", psInstalledScriptsInfoPath, Directory.Exists(psInstalledScriptsInfoPath))); - - - // Create PowerShell modules and scripts paths if they don't already exist - try { - if (!Directory.Exists(psModulesPath)) - { - cmdletPassedIn.WriteVerbose(string.Format("Creating PowerShell modules path '{0}'", psModulesPath)); - Directory.CreateDirectory(psModulesPath); - - } - if (!Directory.Exists(psScriptsPath)) - { - cmdletPassedIn.WriteVerbose(string.Format("Creating PowerShell scripts path '{0}'", psScriptsPath)); - Directory.CreateDirectory(psScriptsPath); - } - if (!Directory.Exists(psInstalledScriptsInfoPath)) - { - cmdletPassedIn.WriteVerbose(string.Format("Creating PowerShell installed scripts info path '{0}'", psInstalledScriptsInfoPath)); - Directory.CreateDirectory(psInstalledScriptsInfoPath); - } - } - catch - { - - } - - - List psModulesPathAllDirs = (Directory.GetDirectories(psModulesPath)).ToList(); - hash.Add("psModulesPathAllDirs", psModulesPathAllDirs); - - // Get the script metadata XML files from the 'InstalledScriptInfos' directory - List psScriptsPathAllDirs = (Directory.GetFiles(psInstalledScriptsInfoPath)).ToList(); - hash.Add("psScriptsPathAllDirs", psScriptsPathAllDirs); - - - return hash; - } - } -} diff --git a/testOld/FindResource.Command.Tests.ps1 b/testOld/FindResource.Command.Tests.ps1 deleted file mode 100644 index 66fb5cef1..000000000 --- a/testOld/FindResource.Command.Tests.ps1 +++ /dev/null @@ -1,234 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe 'Test Find-PSResource for Command' { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - Get-NewPSResourceRepositoryFile - } - - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - # Purpose: find Command resource given Name paramater - # - # Action: Find-PSResource -Name Az.Compute - # - # Expected Result: returns Az.Compute resource - It "find Command resource given Name parameter" { - $res = Find-PSResource -Name Az.Compute - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "Az.Compute" - } - - # Purpose: not find Command resource given unavailable name - # - # Action: Find-PSResource -Name NonExistantCommand - # - # Expected result: should not return NonExistantCommand resource - It "should not find Command resource given unavailable name" { - $res = Find-PSResource -Name NonExistantCommand - $res | Should -BeNullOrEmpty - } - - # Purpose: find Command resource with exact version, given Version parameter - # - # Action: Find-PSResource -Name Az.Compute -Version "[4.3.0.0]" - # - # Expected Result: should return Az.Compute resource with version 4.3.0.0 - It "find Command resource given Name to " -TestCases @( - @{Version="[4.3.0.0]"; ExpectedVersion="4.3.0.0"; Reason="validate version, exact match"}, - @{Version="4.3.0.0"; ExpectedVersion="4.3.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[4.2.0.0, 4.4.0.0]"; ExpectedVersion="4.4.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(4.2.0.0, 4.4.0.0)"; ExpectedVersion="4.3.1.0"; Reason="validate version, exact range exclusive"}, - <# - @{Version="[4.4.0.0,)"; ExpectedVersion="4.4.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(4.2.1.0,)"; ExpectedVersion="4.4.0.0"; Reason="validate version, minimum version exclusive"}, - #> - @{Version="(,4.3.1.0)"; ExpectedVersion="4.3.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,4.3.1.0]"; ExpectedVersion="4.3.1.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[4.2.0.0, 4.3.1.0)"; ExpectedVersion="4.3.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -Name "Az.Compute" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "Az.Compute" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: not find resources with invalid version - # - # Action: Find-PSResource -Name "Az.Compute" -Version "(4.2.1.0)" - # - # Expected Result: should not return a resource - It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(4.2.1.0)'; Description="exlcusive version (4.2.1.0)"}, - @{Version='[4-2-1-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[4.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.2.1.0]'; Description="version with wilcard at start"}, - @{Version='[4.*.1.0]'; Description="version with wildcard at second digit"}, - @{Version='[4.2.*.0]'; Description="version with wildcard at third digit"} - @{Version='[4.2.1.*]'; Description="version with wildcard at end"}, - @{Version='[4..1.0]'; Description="version with missing digit in middle"}, - @{Version='[4.2.1.]'; Description="version with missing digit at end"}, - @{Version='[4.2.1.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) - - $res = $null - try { - $res = Find-PSResource -Name "Az.Compute" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty - } - - # Purpose: find Command resource with wildcard version, given Version parameter -> '*' - # - # Action: Find-PSResource -Name Az.Compute -Version "*" - # - # Expected Result: should return all Az.Compute resources (versions in descending order) - It "find Command resource given Name to validate version wilcard match " { - $res = Find-PSResource -Name "Az.Compute" -Version "*" - $res.Count | Should -BeGreaterOrEqual 40 - } - - # Purpose: find Command resource with latest version (including preview versions), with Prerelease parameter - # - # Action: Find-PSResource -Name Az.Accounts -Prerelease - # - # Expected Result: should return latest version (including preview versions) of Az.Accounts resource - <# - It "find Command resource with latest version (including preview versions), with Prerelease parameter" { - $res = Find-PSResource -Name "Az.Accounts" - $res.Version | Should -Be "1.9.4.0" - - $resPrerelease = Find-PSResource -Name Az.Accounts -Prerelease - $resPrerelease.Version | Should -Be "2.0.1.0" - } - #> - - # Purpose: find Command resource given ModuleName parameter with Version null or empty - # - # Action: Find-PSResource -ModuleName "Az.Accounts" -Repository "PoshTestGallery" - # - # Expected Result: should return resource with latest version - It "find Command resource given ModuleName with Version null or empty" { - $res = Find-PSResource -ModuleName "Az.Compute" -Repository $TestGalleryName - $res.Name | Should -Be "Az.Compute" - } - - # Purpose: find command resource when given ModuleName and any Version parameter - # - # Action: Find-PSResource -Name "Az.Accounts" -Version [2.0.0.0] -Repository "PoshTestGallery" - # - # Expected Result: should find a command resource when given ModuleName and any version value - It "find Command resource given ModuleName to " -TestCases @( - @{Version="[4.3.0.0]"; ExpectedVersion="4.3.0.0"; Reason="validate version, exact match"}, - @{Version="4.3.0.0"; ExpectedVersion="4.3.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[4.2.0.0, 4.4.0.0]"; ExpectedVersion="4.4.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(4.2.0.0, 4.4.0.0)"; ExpectedVersion="4.3.1.0"; Reason="validate version, exact range exclusive"}, - <# - @{Version="[4.4.0.0,)"; ExpectedVersion="4.4.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(4.2.1.0,)"; ExpectedVersion="4.4.0.0"; Reason="validate version, minimum version exclusive"}, - #> - @{Version="(,4.3.1.0)"; ExpectedVersion="4.3.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,4.3.1.0]"; ExpectedVersion="4.3.1.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[4.2.0.0, 4.3.1.0)"; ExpectedVersion="4.3.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -ModuleName "Az.Compute" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "Az.Compute" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: find Command resource given ModuleName to validate version match - # - # Action: Find-PSResource -ModuleName Az.Compute -Version "*" - # - # Expected Result: should return all Az.Compute resources (versions in descending order) - It "find Command resource given ModuleName to validate version wildcard match " { - $res = Find-PSResource -ModuleName "Az.Compute" -Version "*" - $res.Count | Should -BeGreaterOrEqual 40 - } - - # Purpose: find resource with tag, given single Tags parameter - # - # Action: Find-PSResource -Tags "Azure" -Repository PoshTestGallery | Where-Object { $_.Name -eq "Az.Accounts" } - # - # Expected Result: should return Az.Accounts resource - It "find resource with single tag, given Tags parameter" { - $res = Find-PSResource -Tags "Azure" -Repository $TestGalleryName | Where-Object { $_.Name -eq "Az.Accounts" } - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "Az.Accounts" - } - - # Purpose: find resource with tags, given multiple Tags parameter values - # - # Action: Find-PSResource -Tags "Azure","Authentication","ARM" -Repository PoshTestGallery | Where-Object { $_.Name -eq "Az.Accounts" } - # - # Expected Result: should return Az.Accounts resource - It "find resource with multiple tags, given Tags parameter" { - $res = Find-PSResource -Tags "Azure","Authentication","ARM" -Repository $TestGalleryName | Where-Object { $_.Name -eq "Az.Accounts" } - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "Az.Accounts" - } - - # Purpose: not find Command resource from repository where it is not available, given Repository parameter - # - # Action: Find-PSResource -Name "xWindowsUpdate" -Repository PoshTestGallery - # - # Expected Result: should not find xWindowsUpdate resource - It "not find Command resource from repository where it is not available, given Repository parameter" { - $res = Find-PSResource -Name "xWindowsUpdate" -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: find Command resource from repository where it is available, given Repository parameter - # - # Action: Find-PSResource -Name "xWindowsUpdate" -Repository PSGallery - # - # Expected Result: should find xWindowsUpdate resource - It "find Command resource, given Repository parameter" { - $res = Find-PSResource -Name "xWindowsUpdate" -Repository $PSGalleryName - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "xWindowsUpdate" - } - - # Purpose: find resource in first repository where it exists given Repository parameter - # - # Action: Find-PSResource "Az.Accounts" - # Find-PSResource "Az.Accounts" -Repository PSGallery - # - # Expected Result: Returns resource from first avaiable or specfied repository - It "find Resource given repository parameter, where resource exists in multiple repos" { - # first availability found in PoshTestGallery - $res = Find-PSResource "Az.Accounts" - $res.Repository | Should -Be "PoshTestGallery" - - # check that same resource can be returned from non-first-availability/non-default repo - $resNonDefault = Find-PSResource "Az.Accounts" -Repository $PSGalleryName - $resNonDefault | Should -Not -BeNullOrEmpty - $resNonDefault.Repository | Should -Be "PSGallery" - } - - # Purpose: find resource in local repository given Repository parameter - # - # Action: Find-PSResource -Name "local_command_module" -Repository "psgettestlocal" - # - # Expected Result: should find resource from local repository - It "find resource in local repository given Repository parameter" { - $publishCmdName = "TestFindCommandModule" - Get-CommandResourcePublishedToLocalRepoTestDrive $publishCmdName - - $res = Find-PSResource -Name $publishCmdName -Repository "psgettestlocal" - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be $publishCmdName - $res.Repository | Should -Be "psgettestlocal" - } -} diff --git a/testOld/FindResource.DSCResource.Tests.ps1 b/testOld/FindResource.DSCResource.Tests.ps1 deleted file mode 100644 index a4e1879a9..000000000 --- a/testOld/FindResource.DSCResource.Tests.ps1 +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -force - -Describe 'Test Find-PSResource for Command' { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - Get-NewPSResourceRepositoryFile - } - - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - # Purpose: find a DSCResource resource given Name parameter - # - # Action: Find-PSResource -Name NetworkingDsc - # - # Expected Result: returns resource with name NetworkingDsc - It "find a DSCResource resource given Name parameter" { - $res = Find-PSResource -Name NetworkingDsc - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "NetworkingDsc" - } - - # Purpose: find a DSC resource given Name, to validate version parameter values - # - # Action: Find-PSResource -Name NetworkingDsc -Version [6.0.0.0] - # - # Expected Result: return resource meeting version criteria - It "find DSC resource when given Name to " -TestCases @( - @{Version="[6.0.0.0]"; ExpectedVersion="6.0.0.0"; Reason="validate version, exact match"}, - @{Version="6.0.0.0"; ExpectedVersion="6.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[6.0.0.0, 8.0.0.0]"; ExpectedVersion="8.0.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(6.0.0.0, 7.4.0.0)"; ExpectedVersion="7.3.0.0"; Reason="validate version, exact range exclusive"}, - <# - @{Version="(6.0.0.0,)"; ExpectedVersion="8.1.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[6.0.0.0,)"; ExpectedVersion="8.1.0.0"; Reason="validate version, minimum version inclusive"}, - #> - @{Version="(,7.4.0.0)"; ExpectedVersion="7.3.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,7.4.0.0]"; ExpectedVersion="7.4.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[6.0.0.0, 7.4.0.0)"; ExpectedVersion="7.3.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -Name "NetworkingDsc" -Version $Version -Repository $PSGalleryName - $res.Name | Should -Be "NetworkingDsc" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: not find resources with invalid version - # - # Action: Find-PSResource -Name "NetworkingDsc" -Version "(2.5.0.0)" - # - # Expected Result: should not return a resource - It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(8.1.0.0)'; Description="exlcusive version (8.1.0.0)"}, - @{Version='[8-1-0-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[8.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.1.0.0]'; Description="version with wilcard at start"}, - @{Version='[8.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[8.1.*.0]'; Description="version with wildcard at third digit"} - @{Version='[8.1.0.*'; Description="version with wildcard at end"}, - @{Version='[8..0.0]'; Description="version with missing digit in middle"}, - @{Version='[8.1.0.]'; Description="version with missing digit at end"}, - @{Version='[8.1.0.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) - - $res = $null - try { - $res = Find-PSResource -Name "NetworkingDsc" -Version $Version -Repository $PSGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty - } - - # Purpose: find a DSCResource resource with wilcard range Version parameter -> '*' - # - # Action: Find-PSResource -Name NetworkingDsc -Version "*" - # - # Expected Result: returns all NetworkingDsc resources (with versions in descending order) - It "find a DSCResource resource given Name with Version wildcard match " { - $res = Find-PSResource -Name NetworkingDsc -Version "*" - $res.Count | Should -BeGreaterOrEqual 11 - } - - # Purpose: find DSC resource with all versions (incl preview), with Prerelease parameter - # - # Action: Find-PSResource -Name ActiveDirectoryCSDsc -Version "*" -Prerelease - # - # Expected Result: should return more versions with prerelease parameter than without - It "find DSCResource resource with all preview versions, with Prerelease parameter" { - $res = Find-PSResource -Name ActiveDirectoryCSDsc -Version "*" - $withoutPrereleaseVersions = $res.Count - - $resPrerelease = Find-PSResource -Name ActiveDirectoryCSDsc -Version "*" -Prerelease - $withPrereleaseVersions = $resPrerelease.Count - $withPrereleaseVersions | Should -BeGreaterOrEqual $withoutPrereleaseVersions - } - - # Purpose: find a DSCResource resource, with preview version - # - # Action: Find-PSResource -Name ActiveDirectoryCSDsc -Prerelease - # - # Expected Result: should return (a later or) preview version than if without Prerelease parameter - It "find DSCResource resource with preview version, with Prerelease parameter" { - $res = Find-PSResource -Name ActiveDirectoryCSDsc -Repository $PSGalleryName - $res.Version | Should -Be "5.0.0.0" - - $resPrerelease = Find-PSResource -Name ActiveDirectoryCSDsc -Prerelease -Repository $PSGalleryName - $resPrerelease.Version | Should -Be "5.0.1.0" - } - - # Purpose: find a DSCResource of package type module, given ModuleName parameter - # - # Action: Find-PSResource -ModuleName NetworkingDsc - # - # Expected Result: returns DSCResource with specified ModuleName - It "find a DSCResource of package type module, given ModuleName parameter" { - $res = Find-PSResource -ModuleName NetworkingDsc -Repository $PSGalleryName - $res.Name | Should -Be "NetworkingDsc" - } - - # Purpose: find a DSC resource given Name, to validate version parameter values - # - # Action: Find-PSResource -Name NetworkingDsc -Version [6.0.0.0] - # - # Expected Result: return resource meeting version criteria - It "find DSC resource when given ModuleName to " -TestCases @( - @{Version="[6.0.0.0]"; ExpectedVersion="6.0.0.0"; Reason="validate version, exact match"}, - @{Version="6.0.0.0"; ExpectedVersion="6.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[6.0.0.0, 8.0.0.0]"; ExpectedVersion="8.0.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(6.0.0.0, 7.4.0.0)"; ExpectedVersion="7.3.0.0"; Reason="validate version, exact range exclusive"}, - <# - @{Version="(6.0.0.0,)"; ExpectedVersion="8.1.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[6.0.0.0,)"; ExpectedVersion="8.1.0.0"; Reason="validate version, minimum version inclusive"}, - #> - @{Version="(,7.4.0.0)"; ExpectedVersion="7.3.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,7.4.0.0]"; ExpectedVersion="7.4.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[6.0.0.0, 7.4.0.0)"; ExpectedVersion="7.3.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -ModuleName "NetworkingDsc" -Version $Version -Repository $PSGalleryName - $res.Name | Should -Be "NetworkingDsc" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: find a DSCResource with a specific tag, given Tags parameter - # - # Action: Find-PSResource -Tags CommandsAndResource -Repository PoshTestGallery | Where-Object { $_.Name -eq "DscTestModule" } - # - # Expected Result: return DscTestModule resource - It "find a DSCResource with specific tag, given Tags parameter"{ - $res = Find-PSResource -Tags "CommandsAndResource" -Repository $TestGalleryName | Where-Object { $_.Name -eq "DscTestModule" } - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "DscTestModule" - } - - # Purpose: find a DSCResource with multiple tag, given Tags parameter - # - # Action: Find-PSResource -Tags CommandsAndResource,Tag-DscTestModule-2.5,Tag1 -Repository PoshTestGallery | Where-Object { $_.Name -eq "DscTestModule" } - # - # Expected Result: return DscTestModule resource - It "find a DSCResource with specific tag, given Tags parameter"{ - $res = Find-PSResource -Tags "CommandsAndResource","Tag-DscTestModule-2.5","Tag1" -Repository $TestGalleryName | Where-Object { $_.Name -eq "DscTestModule" } - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "DscTestModule" - } - - # Purpose: not find non-available DSCResource from repository, given Repository parameter - # - # Action: Find-PSResource -Name Carbon -Repository PSGallery - # - # Expected Result: should not AccessControlDSC from PoshTestGallery repository - It "not find DSCResource from repository, given Repository parameter" { - $res = Find-PSResource -Name AccessControlDSC -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: find DSCResource from repository, given Repository parameter - # - # Action: Find-PSResource -Name Carbon -Repository PoshTestGallery - # - # Expected Result: should find AccessControlDSC from PSGallery repository - It "find DSCResource from repository, given Repository parameter" { - $res = Find-PSResource -Name AccessControlDSC -Repository $PSGalleryName - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "AccessControlDSC" - } - - # Purpose: find resource in first repository where it exists given Repository parameter - # - # Action: Find-PSResource "PackageManagement" - # Find-PSResource "PackageManagement" -Repository PSGallery - # - # Expected Result: Returns resource from first avaiable or specfied repository - It "find Resource given repository parameter, where resource exists in multiple repos" { - # first availability found in PoshTestGallery - $res = Find-PSResource "PackageManagement" - $res.Repository | Should -Be "PoshTestGallery" - - # check that same resource can be returned from non-first-availability/non-default repo - $resNonDefault = Find-PSResource "PackageManagement" -Repository $PSGalleryName - $resNonDefault.Repository | Should -Be "PSGallery" - } - - # Purpose: not find existing DSCResource from non-existant repository, given Repository parameter - # - # Action: Find-PSResource -Name AccessControlDSC -Repository NonExistantRepo - # - # Expected Result: should not find AccessControlDSC resource from NonExistantRepo repository - It "not find DSCResource from non-existant repository, given Repository parameter" { - $res = Find-PSResource -Name AccessControlDSC -Repository NonExistantRepo - $res.Name | Should -BeNullOrEmpty - } - - # Purpose: find resource in local repository given Repository parameter - # - # Action: Find-PSResource -Name "local_command_module" -Repository "psgettestlocal" - # - # Expected Result: should find resource from local repository - # It "find resource in local repository given Repository parameter" { - # $publishDscName = "TestFindDSCModule" - # Get-DSCResourcePublishedToLocalRepo $publishDscName - - # $res = Find-PSResource -Name $publishDscName -Repository "psgettestlocal" - # $res | Should -Not -BeNullOrEmpty - # $res.Name | Should -Be $publishDscName - - # RemoveTmpdir - # } - It "find resource in local repository given Repository parameter"{ - $publishDscName = "TestFindDSCModule" - Get-DSCResourcePublishedToLocalRepoTestDrive $publishDscName - - $res = Find-PSResource -Name $publishDscName -Repository "psgettestlocal" - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be $publishDscName - $res.Repository | Should -Be "psgettestlocal" - } -} diff --git a/testOld/FindResource.Module.Tests.ps1 b/testOld/FindResource.Module.Tests.ps1 deleted file mode 100644 index e6c505a71..000000000 --- a/testOld/FindResource.Module.Tests.ps1 +++ /dev/null @@ -1,263 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe 'Test Find-PSResource for Module' { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - Get-NewPSResourceRepositoryFile - } - - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - # Purpose: to find all resources when no parameters are specified - # - # Action: Find-PSResource - # - # Expected-Result: finds all (more than 1) resources in PSGallery - It "find Resources Without Any Parameter Values" { - $psGetItemInfo = Find-PSResource - $psGetItemInfo.Count | Should -BeGreaterThan 1 - } - - # Purpose: to find a specific resource by name - # - # Action: Find-PSResource -Name "ContosoServer" - # - # Expected Result: Should find ContosoServer resource - It "find Specific Module Resource by Name" { - $specItem = Find-PSResource -Name ContosoServer - $specItem.Name | Should -Be "ContosoServer" - } - - # Purpose: to find a resource(s) with regex in name parameter - # - # Action: Find-PSResource -Name Contoso* - # - # Expected Result: should find multiple resources,namely atleast ContosoServer, ContosoClient, Contoso - It "find multiple Resource(s) with Wildcards for Name Param" { - $res = Find-PSResource -Name Contoso* - $res.Count | Should -BeGreaterOrEqual 1 - } - - # Purpose: to find a specific resource with wildcard in name - # - # Action: Find-PSResource *ontosoServe* - # - # Expected Result: should find the ContosoServer resource - It "find Specific Resource with Wildcards for Name Param" { - $res = Find-PSResource *ontosoServe* - $res.Name | Should -Be "ContosoServer" - } - - # Purpose: find resource when given Name, Version param not null - # - # Action: Find-PSResource -Name ContosoServer -Repository PoshTestGallery - # - # Expected Result: returns ContosoServer resource - It "find resource when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "ContosoServer" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: not find resources with invalid version - # - # Action: Find-PSResource -Name "ContosoServer" -Version "(1.5.0.0)" - # - # Expected Result: should not return a resource - It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, - @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*'; Description="version with wildcard at end"}, - @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) - - $res = $null - try { - $res = Find-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty - } - - # Purpose: not find resource with invalid verison, given Version parameter -> (1.5.0.0) - # - # Action: Find-PSResource -Name "ContosoServer" -Version "(1.5.0.0)" - # - # Expected Result: should not return a resource as version is invalid - It "not find Command resource given Name to validate handling an invalid version" { - $res = Find-PSResource -Name "ContosoServer" -Version "(1.5.0.0)" - $res | Should -BeNullOrEmpty - } - - # Purpose: find resources when given Name, Version not null --> '*' - # - # Action: Find-PSResource -Name ContosoServer -Version "*" -Repository PoshTestGallery - # - # Expected Result: returns 4 ContosoServer resources (of all versions in descending order) - It "find resources when given Name, Version not null --> '*'" { - $res = Find-PSResource -Name ContosoServer -Version "*" -Repository $TestGalleryName - $res.Count | Should -BeGreaterOrEqual 4 - } - - # Purpose: find resource when given ModuleName, Version param null - # - # Action: Find-PSResource -ModuleName ContosoServer -Repository PoshTestGallery - # - # Expected Result: returns nothing, prints error message - It "find resource when given ModuleName, Version param null" { - $res = Find-PSResource -ModuleName "ContosoServer" -Repository $TestGalleryName - $res.Name | Should -Be "ContosoServer" - $res.Version | Should -Be "2.5.0.0" - } - - # Purpose: find resource when given ModuleName, Version param not null - # - # Action: Find-PSResource -ModuleName ContosoServer -Repository PoshTestGallery - # - # Expected Result: returns ContosoServer resource - It "find resource when given ModuleName to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0,2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0,2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -ModuleName "ContosoServer" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "ContosoServer" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: find resources when given ModuleName, Version not null --> '*' - # - # Action: Find-PSResource -ModuleName ContosoServer -Version "*" -Repository PoshTestGallery - # - # Expected Result: returns 4 ContosoServer resources (of all versions in descending order) - It "find resources when given ModuleName, Version not null --> '*'" { - $res = Find-PSResource -ModuleName ContosoServer -Version "*" -Repository $TestGalleryName - $res.Count | Should -BeGreaterOrEqual 4 - } - - # Purpose: find resource with latest version (including prerelease version) given Prerelease parameter - # - # Action: Find-PSResource -Name "test_module" -Prerelease - # - # Expected Result: should return latest version (may be a prerelease version) - It "find resource with latest (including prerelease) version given Prerelease parameter" { - # test_module resource's latest version is a prerelease version, before that it has a non-prerelease version - $res = Find-PSResource -Name "test_module" - $res.Version | Should -Be "5.0.0.0" - - $resPrerelease = Find-PSResource -Name "test_module" -Prerelease - $resPrerelease.Version | Should -Be "5.2.5.0" - } - - # Purpose: to find a resource given Tags parameter with one value - # - # Action: Find-PSResource -Tags CommandsAndResource | Where-Object { $_.Name -eq "DscTestModule" } - # - # Expected Result: should return all resources with that tag, and then filer by name - It "find a resource given Tags parameter with one value" { - $res = Find-PSResource -Tags CommandsAndResource | Where-Object { $_.Name -eq "DscTestModule" } - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "DscTestModule" - } - - # Purpose: find resource(s) given multiple tags for the Tags parameter. - # - # Action: Find-PSResource -Tags CommandsAndResource,DSC,Tag1 - # - # Expected Result: Should return more resources than if just queried with -Tags CommandsAndResources - It "find a resource given tags parameter with multiple values" { - $resSingleTag = Find-PSResource -Tags CommandsAndResource - $res = Find-PSResource -Tags CommandsAndResource,DSC,Tag1 - $res | Should -Not -BeNullOrEmpty - $res.Count | Should -BeGreaterOrEqual $resSingleTag.Count - } - - # Purpose: find a resource in a specific repository, given Repository parameter - # - # Action: Find-PSResource ContosoServer -Repository $PoshTestGalleryName - # - # Expected Result: Should find the resource from the specified repository - It "find resource given repository parameter" { - $res = Find-PSResource ContosoServer -Repository $PSGalleryName - $res | Should -BeNullOrEmpty - - # ContosoServer resource exists in the PostTestGalleryRepository - $resCorrectRepo = Find-PSResource ContosoServer -Repository $TestGalleryName - $resCorrectRepo | Should -Not -BeNullOrEmpty - $resCorrectRepo.Repository | Should -Be "PoshTestGallery" - } - - # Purpose: find resource in first repository where it exists given Repository parameter - # - # Action: Find-PSResource "Az.Compute" - # Find-PSResource "Az.Compute" -Repository PSGallery - # - # Expected Result: Returns resource from first avaiable or specfied repository - It "find Resource given repository parameter, where resource exists in multiple repos" { - # first availability found in PoshTestGallery - $res = Find-PSResource "Az.Compute" - $res.Repository | Should -Be "PoshTestGallery" - - # check that same resource can be returned from non-first-availability/non-default repo - $resNonDefault = Find-PSResource "Az.Compute" -Repository $PSGalleryName - $resNonDefault.Repository | Should -Be "PSGallery" - } - - # Purpose: find a resource and associated dependecies given IncludeDependencies parameter - # - # Action: Find-PSResource ModuleWithDependencies1 -IncludeDependencies - # - # Expected Result: should return resource specified and all associated dependecy resources - It "find resource with IncludeDependencies parameter" { - $res = Find-PSResource ModuleWithDependencies1 -IncludeDependencies -Version "[1.0,2.0]" - $res.Count | Should -BeGreaterOrEqual 11 - } - - # Purpose: find resource in local repository given Repository parameter - # - # Action: Find-PSResource -Name "local_command_module" -Repository "psgettestlocal" - # - # Expected Result: should find resource from local repository - It "find resource in local repository given Repository parameter" { - $publishModuleName = "TestFindModule" - Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName - - $res = Find-PSResource -Name $publishModuleName -Repository "psgettestlocal" - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be $publishModuleName - $res.Repository | Should -Be "psgettestlocal" - } -} diff --git a/testOld/FindResource.RoleCapability.Tests.ps1 b/testOld/FindResource.RoleCapability.Tests.ps1 deleted file mode 100644 index adf61fdd4..000000000 --- a/testOld/FindResource.RoleCapability.Tests.ps1 +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -force - -Describe 'Test Find-PSResource for Role Capability' { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - Get-NewPSResourceRepositoryFile - } - - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - # Purpose: find Role Capability resource, given Name parameter - # - # Action: Find-PSResource -Name TestRoleCapModule - # - # Expected Result: return TestRoleCapModule resource - It "find Role Capability resource, given Name parameter" { - $res = Find-PSResource -Name TestRoleCapModule - $res.Name | Should -Be "TestRoleCapModule" - } - - # Purpose: not find non-existant Role Capability resource, given Name parameter - # - # Action: Find-PSResource -Name NonExistantRoleCap - # - # Expected Result: should not return any resource - It "not find non-existant Role Capability resource, given Name parameter" { - $res = Find-PSResource -Name NonExistantRoleCap - $res | Should -BeNullOrEmpty - } - - # Purpose: find a RoleCapability resource given Name, to validate version parameter values - # - # Action: Find-PSResource -Name DscTestModule -Version [2.0.0.0] - # - # Expected Result: return resource meeting version criteria - It "find resource when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -Name "DscTestModule" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "DscTestModule" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: not find resources with invalid version - # - # Action: Find-PSResource -Name "DscTestModule" -Version "(2.5.0.0)" - # - # Expected Result: should not return a resource - It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(2.5.0.0)'; Description="exlcusive version (2.5.0.0)"}, - @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[2.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[2.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[2.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[2.5.0.*'; Description="version with wildcard at end"}, - @{Version='[2..0.0]'; Description="version with missing digit in middle"}, - @{Version='[2.5.0.]'; Description="version with missing digit at end"}, - @{Version='[2.5.0.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) - - $res = $null - try { - $res = Find-PSResource -Name "DscTestModule" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty - } - - # Purpose: find Role Capability resource with wildcard version, given Version parameter - # - # Action: Find-PSResource -Name "TestRoleCapModule" -Version "*" - # - # Expected Result: returns all versions of DSCTestModule (versions in descending order) - It "find Role Capability resource with wildcard version, given Version parameter -> '*' " { - $res = Find-PSResource -Name "DscTestModule" -Version "*" -Repository $TestGalleryName - $res.Count | Should -BeGreaterOrEqual 1 - } - - # Purpose: find Role Capability resource, given ModuleName parameter - # - # Action: Find-PSResource -ModuleName JeaExamples -Repository PSGallery - # - # Expected Result: should return JeaExamples resource - It "find Role Capability resource, given ModuleName parameter" { - $res = Find-PSResource -ModuleName "DscTestModule" -Repository $TestGalleryName - $res.Name | Should -Be "DscTestModule" - } - - # Purpose: find a RoleCapability resource given ModuleName, to validate version parameter values - # - # Action: Find-PSResource -ModuleName DscTestModule -Version [2.0.0.0] - # - # Expected Result: return resource meeting version criteria - It "find resource when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -ModuleName "DscTestModule" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "DscTestModule" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: find Role Capability resource with given Tags parameter - # - # Action: Find-PSResource -Tags "CommandsAndResource" -Repository PoshTestGallery | Where-Object { $_.Name -eq "PSGETTEST-TestPackageMetadata" } - # - # Expected Result: should return PSGETTEST-TestPackageMetadata resource - It "find Role Capability resource with given Tags parameter" { - $res = Find-PSResource -Tags "CommandsAndResource" -Repository $TestGalleryName | Where-Object { $_.Name -eq "PSGETTEST-TestPackageMetadata" } - $res.Name | Should -Be "PSGETTEST-TestPackageMetadata" - } - - # Purpose: find Role Capability resource with multiple given Tags parameter - # - # Action: Find-PSResource -Tags "CommandsAndResource","Tag2", "PSGet" -Repository PoshTestGallery | Where-Object { $_.Name -eq "PSGETTEST-TestPackageMetadata" } - # - # Expected Result: should return PSGETTEST-TestPackageMetadata resource - It "find Role Capability resource with given Tags parameter" { - $res = Find-PSResource -Tags "CommandsAndResource","Tag2", "PSGet" -Repository $TestGalleryName | Where-Object { $_.Name -eq "PSGETTEST-TestPackageMetadata" } - $res.Name | Should -Be "PSGETTEST-TestPackageMetadata" - } - - # Purpose: not find Role Capability resource that doesn't exist in specified repository, given Repository parameter - # - # Action: Find-PSResource -Name JeaExamples -Repository PoshTestGallery - # - # Expected Result: should not find JeaExamples resource - It "not find Role Capability resource that doesn't exist in specified repository, given Repository parameter" { - $res = Find-PSResource -Name JeaExamples -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: find Role Capability resource that exists only in specified repository, given Repository parameter - # - # Action: Find-PSResource -Name JeaExamples -Repository $PSGalleryName - # - # Expected Result: should find JeaExamples resource - It "find resource that exists only in a specific repository, given Repository parameter" { - $resRightRepo = Find-PSResource -Name JeaExamples -Repository $PSGalleryName - $resRightRepo.Name | Should -Be "JeaExamples" - } - - It "find resource in local repository given Repository parameter" { - $roleCapName = "TestFindRoleCapModule" - Get-RoleCapabilityResourcePublishedToLocalRepoTestDrive $roleCapName - - $res = Find-PSResource -Name $roleCapName -Repository "psgettestlocal" - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be $roleCapName - $res.Repository | Should -Be "psgettestlocal" - } -} diff --git a/testOld/FindResource.Script.Tests.ps1 b/testOld/FindResource.Script.Tests.ps1 deleted file mode 100644 index bc25b49f6..000000000 --- a/testOld/FindResource.Script.Tests.ps1 +++ /dev/null @@ -1,234 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -force - -Describe "Test Find-PSResource for Script" { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - Get-NewPSResourceRepositoryFile - } - - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - # Purpose: find a script resource with specified Name parameter - # - # Action: Find-PSResource -Name Fabrikam-ServerScript - # - # Expected Result: should return a resource with specified name Fabrikam-ServerScript - It "find resource given Name parameter" { - $res = Find-PSResource -Name Fabrikam-ServerScript - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "Fabrikam-ServerScript" - } - - # Purpose: successfully not find a resource that doesn't have a valid name - # - # Action: Find-PSResource -Name NonExistantScript -Repository PoshTestGallery - # - # Expected Result: should not return a resource, as none with specified name exists - It "not find a resource that doesn't have a valid name" { - $res = Find-PSResource -Name NonExistantScript -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: find resources with multiple values provided for Name parameter - # - # Action: Find-PSResource -Name Fabrikam-ServerScript,Fabrikam-ClientScript -Repository PoshTestGallery - # - # Expected Result: should return the multiple resources specified - It "find resources with multiple values provided for Name parameter" { - $res = Find-PSResource -Name Fabrikam-ServerScript,Fabrikam-ClientScript -Repository $TestGalleryName - $res | Should -Not -BeNullOrEmpty - $res.Count | Should -Be 2 - } - - # Purpose: find resource when given Name, Version param not null - # - # Action: Find-PSResource -Name ContosoServer -Repository PoshTestGallery - # - # Expected Results: should return resource with appropriate version - It "find resource when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.2.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -Name "Fabrikam-ServerScript" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "Fabrikam-ServerScript" - $res.Version | Should -Be $ExpectedVersion - } - - # Purpose: not find resources with invalid version - # - # Action: Find-PSResource -Name "Fabrikam-ServerScript" -Version "(1.5.0.0)" - # - # Expected Result: should not return a resource - It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.5.0.0)'; Description="exlcusive version (2.5.0.0)"}, - @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*'; Description="version with wildcard at end"}, - @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) - - $res = $null - try { - $res = Find-PSResource -Name "Fabrikam-ServerScript" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty - } - - # Purpose: find resources when given Name, Version not null --> '*' - # - # Action: Find-PSResource -Name ContosoServer -Version "*" -Repository PoshTestGallery - # - # Expected Result: returns 4 ContosoServer resources (of all versions in descending order) - It "find resources when given Name, Version not null --> '*'" { - $res = Find-PSResource -Name "Fabrikam-ServerScript" -Version "*" -Repository $TestGalleryName - $res.Count | Should -BeGreaterOrEqual 5 - } - - # Purpose: not find script resource when given ModuleName and no Version parameter - # - # Action: Find-PSResource -ModuleName "Fabrikam-ServerScript" -Repository PoshTestGallery - # - # Expected Result: not find a script resource when given ModuleName - It "not find script resource when given ModuleName" { - $res = Find-PSResource -ModuleName "Fabrikam-ServerScript" -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: not find script resource when given ModuleName and any Version parameter - # - # Action: Find-PSResource -Name "Fabrikam-ServerScript" -Version [2.0.0.0] -Repository "PoshTestGallery" - # - # Expected Result: should not find a script resource when given ModuleName and any version value - It "not find script resource when given ModuleName to " -TestCases @( - @{Version="[2.0.0.0]"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Find-PSResource -ModuleName "Fabrikam-ServerScript" -Version $Version -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: not find resource with given ModuleName and wildcard Version -> '*' - # - # Action: Find-PSResource -ModuleName Fabrikam-ServerScript -Version "*" -Repository PoshTestGallery - # - # Expected Result: not return a resource - It "not find script resource with specified ModuleName and range Version parameter -> '*' " { - $res = Find-PSResource -ModuleName Fabrikam-ServerScript -Version "*" -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: find resource with latest version (including prerelease version) given Prerelease parameter - # - # Action: Find-PSResource -Name "test_script" -Prerelease - # - # Expected Result: should return latest version (may be a prerelease version) - It "find resource with latest (including prerelease) version given Prerelease parameter" { - # test_script resource's latest version is a prerelease version, before that it has a non-prerelease version - $res = Find-PSResource -Name "test_script" - $res.Version | Should -Be "2.5.0.0" - - $resPrerelease = Find-PSResource -Name "test_script" -Prerelease - $resPrerelease.Version | Should -Be "3.0.0.0" - } - - # Purpose: not find un-available resource from specified repository, when given Repository parameter - # - # Action: Find-PSResource -Name Get-WindowsAutoPilotInfo -Repository PoshTestGallery - # - # Expected Result: should not find resource from specified PSGallery repository becuase resource doesn't exist there - It "find resource from specified repository, when given Repository parameter" { - $res = Find-PSResource -Name Get-WindowsAutoPilotInfo -Repository $TestGalleryName - $res | Should -BeNullOrEmpty - } - - # Purpose: find resource from specified repository, when given Repository parameter - # - # Action: Find-PSResource -Name Get-WindowsAutoPilotInfo -Repository PSGallery - # - # Expected Result: should return resource from specified repository where it exists - It "find resource from specified repository, when given Repository parameter" { - $res = Find-PSResource -Name Get-WindowsAutoPilotInfo -Repository $PSGalleryName - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "Get-WindowsAutoPilotInfo" - $res.Repository | Should -Be "PSGallery" - } - - # Purpose: find resource in first repository where it exists given Repository parameter - # - # Action: Find-PSResource "Connect-AzureVM" - # Find-PSResource "Connect-AzureVM" -Repository PSGallery - # - # Expected Result: Returns resource from first avaiable or specfied repository - It "find Resource given repository parameter, where resource exists in multiple repos" { - # first availability found in PoshTestGallery - $res = Find-PSResource "Connect-AzureVM" - $res.Repository | Should -Be "PoshTestGallery" - - # check that same resource can be returned from non-first-availability/non-default repo - $resNonDefault = Find-PSResource "Connect-AzureVM" -Repository $PSGalleryName - $resNonDefault.Repository | Should -Be "PSGallery" - } - - # Purpose: find a resource but not its dependency resource(s) - # - # Action: Find-PSResources -Name Script-WithDependencies1 - # - # Expected Result: should return resource but none of its dependency resources - It "find resource and its dependency resource(s) with IncludeDependencies parameter" { - $res = Find-PSResource -Name Script-WithDependencies1 - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "Script-WithDependencies1" - } - - # Purpose: find a resource and its dependency resource(s) with IncludeDependencies parameter - # - # Action: Find-PSResources -Name Script-WithDependencies1 -IncludeDependencies - # - # Expected Result: should return resource and all of its dependency resources - It "find resource and its dependency resource(s) with IncludeDependencies parameter" { - $res = Find-PSResource -Name Script-WithDependencies1 -IncludeDependencies - $res | Should -Not -BeNullOrEmpty - $res.Count | Should -BeGreaterOrEqual 9 - } - - It "find resource in local repository given Repository parameter" { - $scriptName = "TestScriptName" - Get-ScriptResourcePublishedToLocalRepoTestDrive $scriptName - - $res = Find-PSResource -Name $scriptName -Repository "psgettestlocal" - $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be $scriptName - $res.Repository | Should -Be "psgettestlocal" - } -} diff --git a/testOld/PSGetTestUtils.psm1 b/testOld/PSGetTestUtils.psm1 deleted file mode 100644 index 319b85db1..000000000 --- a/testOld/PSGetTestUtils.psm1 +++ /dev/null @@ -1,428 +0,0 @@ -<##################################################################################### - # File: PSGetTestUtils.psm1 - # - # Copyright (c) Microsoft Corporation, 2020 - #####################################################################################> - -#."$PSScriptRoot\uiproxy.ps1" - -$psGetMod = Get-Module -Name PowerShellGet -if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) -{ - Write-Verbose -Verbose "Importing PowerShellGet 3.0.0 for test" - Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force -} - -$script:DotnetCommandPath = @() -$script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 } -$script:EnvPATHValueBackup = $null - -$script:PowerShellGet = 'PowerShellGet' -$script:IsInbox = $PSHOME.EndsWith('\WindowsPowerShell\v1.0', [System.StringComparison]::OrdinalIgnoreCase) -$script:IsWindows = (-not (Get-Variable -Name IsWindows -ErrorAction Ignore)) -or $IsWindows -$script:IsLinux = (Get-Variable -Name IsLinux -ErrorAction Ignore) -and $IsLinux -$script:IsMacOS = (Get-Variable -Name IsMacOS -ErrorAction Ignore) -and $IsMacOS -$script:IsCoreCLR = $PSVersionTable.ContainsKey('PSEdition') -and $PSVersionTable.PSEdition -eq 'Core' - -$script:PSGalleryName = 'PSGallery' -$script:PSGalleryLocation = 'https://www.powershellgallery.com/api/v2' - -$script:PoshTestGalleryName = 'PoshTestGallery' -$script:PostTestGalleryLocation = 'https://www.poshtestgallery.com/api/v2' - -if($script:IsInbox) -{ - $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell" -} -elseif($script:IsCoreCLR){ - if($script:IsWindows) { - $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath 'PowerShell' - } - else { - $script:ProgramFilesPSPath = Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('SHARED_MODULES')) -Parent - } -} - -try -{ - $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments") -} -catch -{ - $script:MyDocumentsFolderPath = $null -} - -if($script:IsInbox) -{ - $script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) - { - Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath "WindowsPowerShell" - } - else - { - Microsoft.PowerShell.Management\Join-Path -Path $env:USERPROFILE -ChildPath "Documents\WindowsPowerShell" - } -} -elseif($script:IsCoreCLR) { - if($script:IsWindows) - { - $script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) - { - Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath 'PowerShell' - } - else - { - Microsoft.PowerShell.Management\Join-Path -Path $HOME -ChildPath "Documents\PowerShell" - } - } - else - { - $script:MyDocumentsPSPath = Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('USER_MODULES')) -Parent - } -} - -$script:ProgramFilesModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath 'Modules' -$script:MyDocumentsModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath 'Modules' -$script:ProgramFilesScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath 'Scripts' -$script:MyDocumentsScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath 'Scripts' -$script:TempPath = [System.IO.Path]::GetTempPath() - -if($script:IsWindows) { - $script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' - $script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' -} else { - $script:PSGetProgramDataPath = Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CONFIG')) -ChildPath 'PowerShellGet' - $script:PSGetAppLocalPath = Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CACHE')) -ChildPath 'PowerShellGet' -} - -$script:ProgramDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetProgramDataPath -ChildPath $script:NuGetExeName -$script:ApplocalDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath $script:NuGetExeName -$script:moduleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath 'PSRepositories.xml' - -# PowerShellGetFormatVersion will be incremented when we change the .nupkg format structure. -# PowerShellGetFormatVersion is in the form of Major.Minor. -# Minor is incremented for the backward compatible format change. -# Major is incremented for the breaking change. -$script:CurrentPSGetFormatVersion = "1.0" -$script:PSGetFormatVersionPrefix = "PowerShellGetFormatVersion_" - -function Get-AllUsersModulesPath { - return $script:ProgramFilesModulesPath -} - -function Get-CurrentUserModulesPath { - return $script:MyDocumentsModulesPath -} - -function Get-AllUsersScriptsPath { - return $script:ProgramFilesScriptsPath -} - -function Get-CurrentUserScriptsPath { - return $script:MyDocumentsScriptsPath -} - -function Get-TempPath { - return $script:TempPath -} - -function Get-PSGetLocalAppDataPath { - return $script:PSGetAppLocalPath -} - -function Get-PSGalleryName -{ - return $script:PSGalleryName -} - -function Get-PSGalleryLocation { - return $script:PSGalleryLocation -} - -function Get-PoshTestGalleryName { - return $script:PoshTestGalleryName -} - -function Get-PoshTestGalleryLocation { - return $script:PostTestGalleryLocation -} - -function Get-NewPSResourceRepositoryFile { - # register our own repositories with desired priority - $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" - $originalXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" - $tempXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "temp.xml" - - if (Test-Path -Path $originalXmlFilePath) { - Copy-Item -Path $originalXmlFilePath -Destination $tempXmlFilePath - Remove-Item -Path $originalXmlFilePath -Force -ErrorAction Ignore - } - - if (! (Test-Path -Path $powerShellGetPath)) { - $null = New-Item -Path $powerShellGetPath -ItemType Directory -Verbose - } - - $fileToCopy = Join-Path -Path $PSScriptRoot -ChildPath "testRepositories.xml" - Copy-Item -Path $fileToCopy -Destination $originalXmlFilePath -Force -Verbose -} - -function Get-RevertPSResourceRepositoryFile { - $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" - $originalXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" - $tempXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "temp.xml" - - if (Test-Path -Path $tempXmlFilePath) { - Remove-Item -Path $originalXmlFilePath -Force -ErrorAction Ignore - Copy-Item -Path $tempXmlFilePath -Destination $originalXmlFilePath -Force - Remove-Item -Path $tempXmlFilePath -Force -ErrorAction Ignore - } -} - -function Get-TestDriveSetUp -{ - $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" - $null = New-Item $repoURLAddress -ItemType Directory -Force - - Set-PSResourceRepository -Name "psgettestlocal" -URL $repoURLAddress - - $testResourcesFolder = Join-Path $TestDrive -ChildPath "TestLocalDirectory" - - $script:testIndividualResourceFolder = Join-Path -Path $testResourcesFolder -ChildPath "PSGet_$(Get-Random)" - $null = New-Item -Path $testIndividualResourceFolder -ItemType Directory -Force -} - -function Get-RoleCapabilityResourcePublishedToLocalRepoTestDrive -{ - Param( - [string] - $roleCapName - ) - - Get-TestDriveSetUp - - $publishModuleName = $roleCapName - $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName - $null = New-Item -Path $publishModuleBase -ItemType Directory -Force - - $version = "1.0" - New-PSRoleCapabilityFile -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psrc") - New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" -DscResourcesToExport @('DefaultGatewayAddress', 'WINSSetting') -Tags @('PSDscResource_', 'DSC') - - Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal -} - -function Get-DSCResourcePublishedToLocalRepoTestDrive -{ - Param( - [string] - $dscName - ) - - Get-TestDriveSetUp - - $publishModuleName = $dscName - $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName - $null = New-Item -Path $publishModuleBase -ItemType Directory -Force - - $version = "1.0" - New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" -DscResourcesToExport @('DefaultGatewayAddress', 'WINSSetting') -Tags @('PSDscResource_', 'DSC') - - Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal -} - -function Get-ScriptResourcePublishedToLocalRepoTestDrive -{ - Param( - [string] - $scriptName - ) - Get-TestDriveSetUp - - $scriptFilePath = Join-Path -Path $script:testIndividualResourceFolder -ChildPath "$scriptName.ps1" - $null = New-Item -Path $scriptFilePath -ItemType File -Force - - $version = "1.0.0" - $params = @{ - #Path = $scriptFilePath - Version = $version - #GUID = - Author = 'Jane' - CompanyName = 'Microsoft Corporation' - Copyright = '(c) 2020 Microsoft Corporation. All rights reserved.' - Description = "Description for the $scriptName script" - LicenseUri = "https://$scriptName.com/license" - IconUri = "https://$scriptName.com/icon" - ProjectUri = "https://$scriptName.com" - Tags = @('Tag1','Tag2', "Tag-$scriptName-$version") - ReleaseNotes = "$scriptName release notes" - } - - $scriptMetadata = Create-PSScriptMetadata @params - Set-Content -Path $scriptFilePath -Value $scriptMetadata - - Publish-PSResource -path $scriptFilePath -Repository psgettestlocal -} - -function Get-CommandResourcePublishedToLocalRepoTestDrive -{ - Param( - [string] - $cmdName - ) - Get-TestDriveSetUp - - $publishModuleName = $cmdName - $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName - $null = New-Item -Path $publishModuleBase -ItemType Directory -Force - - $version = "1.0" - New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" -CmdletsToExport @('Get-Test', 'Set-Test') - - Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal -} - -function Get-ModuleResourcePublishedToLocalRepoTestDrive -{ - Param( - [string] - $moduleName - ) - Get-TestDriveSetUp - - $publishModuleName = $moduleName - $publishModuleBase = Join-Path $script:testIndividualResourceFolder $publishModuleName - $null = New-Item -Path $publishModuleBase -ItemType Directory -Force - - $version = "1.0" - New-ModuleManifest -Path (Join-Path -Path $publishModuleBase -ChildPath "$publishModuleName.psd1") -ModuleVersion $version -Description "$publishModuleName module" -NestedModules "$publishModuleName.psm1" - - Publish-PSResource -Path $publishModuleBase -Repository psgettestlocal -} - -function RemoveItem -{ - Param( - [string] - $path - ) - - if($path -and (Test-Path $path)) - { - Remove-Item $path -Force -Recurse -ErrorAction SilentlyContinue - } -} - -function Create-PSScriptMetadata -{ - [OutputType([String])] - [CmdletBinding(PositionalBinding=$false, - SupportsShouldProcess=$true)] - - Param - ( - [Parameter()] - [ValidateNotNullOrEmpty()] - [string] - $Version, - - [Parameter()] - #[ValidateNotNullOrEmpty()] - [Guid] - $Guid, - - [Parameter()] - [ValidateNotNullOrEmpty()] - [string] - $Author, - - [Parameter()] - [String] - $CompanyName, - - [Parameter()] - [string] - $Copyright, - - [Parameter()] - [string] - $Description, - - [Parameter()] - [String[]] - $ExternalModuleDependencies, - - [Parameter()] - [string[]] - $RequiredScripts, - - [Parameter()] - [String[]] - $ExternalScriptDependencies, - - [Parameter()] - [string[]] - $Tags, - - [Parameter()] - [Uri] - $ProjectUri, - - [Parameter()] - [Uri] - $LicenseUri, - - [Parameter()] - [Uri] - $IconUri, - - [Parameter()] - [string[]] - $ReleaseNotes, - - [Parameter()] - [string] - $PrivateData - ) - - Process - { - $PSScriptInfoString = @" - -<#PSScriptInfo - -.VERSION$(if ($Version) {" $Version"}) - -.GUID$(if ($Guid) {" $Guid"}) - -.AUTHOR$(if ($Author) {" $Author"}) - -.COMPANYNAME$(if ($CompanyName) {" $CompanyName"}) - -.COPYRIGHT$(if ($Copyright) {" $Copyright"}) - -.DESCRIPTION$(if ($Description) {" $Description"}) - -.TAGS$(if ($Tags) {" $Tags"}) - -.LICENSEURI$(if ($LicenseUri) {" $LicenseUri"}) - -.PROJECTURI$(if ($ProjectUri) {" $ProjectUri"}) - -.ICONURI$(if ($IconUri) {" $IconUri"}) - -.EXTERNALMODULEDEPENDENCIES$(if ($ExternalModuleDependencies) {" $($ExternalModuleDependencies -join ',')"}) - -.REQUIREDSCRIPTS$(if ($RequiredScripts) {" $($RequiredScripts -join ',')"}) - -.EXTERNALSCRIPTDEPENDENCIES$(if ($ExternalScriptDependencies) {" $($ExternalScriptDependencies -join ',')"}) - -.RELEASENOTES -$($ReleaseNotes -join "`r`n") - -.PRIVATEDATA$(if ($PrivateData) {" $PrivateData"}) - -#> -"@ - return $PSScriptInfoString - } -} diff --git a/testOld/PSRepository.Tests.ps1 b/testOld/PSRepository.Tests.ps1 deleted file mode 100644 index a44604690..000000000 --- a/testOld/PSRepository.Tests.ps1 +++ /dev/null @@ -1,619 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -# TODO: -Write-Warning "PSRepository.Tests.ps1 is current disabled." -return - -$psGetMod = Get-Module -Name PowerShellGet -if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) -{ - Write-Verbose -Verbose "Importing PowerShellGet 3.0.0 for test" - Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force -} - -$PSGalleryName = 'PSGallery' -$PSGalleryLocation = 'https://www.powershellgallery.com/api/v2' - -$TestRepoName = 'TestRepoName' -$TestRepoURL = 'https://www.poshtestgallery.com/api/v2' - -$TestRepoName2 = "NuGet" -$TestRepoURL2 = 'https://api.nuget.org/v3/index.json' - -$TestRepoLocalName = 'TestLocalRepo' -$tmpdir = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $TestRepoLocalName - -if (-not (Test-Path -LiteralPath $tmpdir)) { - New-Item -Path $tmpdir -ItemType Directory > $null -} -Write-Host $tmpdir -$TestRepoLocalURL = $tmpdir - -$TestRepoLocalName2 = "TestLocalRepoName2" -$tmpdir2 = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $TestRepoLocalName2 -if (-not (Test-Path -LiteralPath $tmpdir2)) { - New-Item -Path $tmpdir2 -ItemType Directory > $null -} - -Write-Host $tmpdir2 -$TestRepoLocalURL2 = $tmpdir2 - -# remember to delete these files -# Remove-Item -LiteralPath $tmpdir -Force -Recurse -#} - -$ErrorActionPreference = "SilentlyContinue" - -##################################### -### Register-PSResourceRepository ### -##################################### - -Describe 'Test Register-PSResourceRepository' -tags 'BVT' { - - BeforeAll { - - } - AfterAll { - #Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - BeforeEach { - # Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - AfterEach { - } - - ### Registering the PowerShell Gallery - It 'Should register the default PSGallery' { - Register-PSResourceRepository -PSGallery - - $repo = Get-PSResourceRepository $PSGalleryName - $repo | Should -Not -BeNullOrEmpty - $repo.URL | Should be $PSGalleryLocation - $repo.Trusted | Should be false - $repo.Priority | Should be 50 - } - - It 'Should register PSGallery with installation policy trusted' { - Unregister-PSResourceRepository $PSGalleryName - Register-PSResourceRepository -PSGallery -Trusted - - $repo = Get-PSResourceRepository $PSGalleryName - $repo.Name | Should be $PSGalleryName - $repo.Trusted | Should be true - } - - <################################################################# - It 'Should fail to reregister PSGallery' { - Unregister-PSResourceRepository $PSGalleryName - Register-PSResourceRepository -PSGallery - (Register-PSResourceRepository -PSGallery -ErrorVariable ev -ErrorAction SilentlyContinue) | should throw - - # $ev[0].FullyQualifiedErrorId | Should be "The PSResource Repository 'PSGallery' already exists." - } - #> - - - <################################################################# - It 'Should fail to register PSGallery when manually providing URL' { - Unregister-PSResourceRepository $PSGalleryName - {Register-PSResourceRepository $PSGalleryName -URL $PSGalleryLocation -ErrorVariable ev -ErrorAction SilentlyContinue} | should throw - - $ev[0].FullyQualifiedErrorId | Should be "Use 'Register-PSResourceRepository -Default' to register the PSGallery repository." - } - #> - - ### Registering an online URL - It 'Should register the test repository with online -URL' { - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL - - $repo = Get-PSResourceRepository $TestRepoName - $repo.Name | should be $TestRepoName - $repo.URL | should be $TestRepoURL - $repo.Trusted | should be false - } - - It 'Should register the test repository when -URL is a website and installation policy is trusted' { - Unregister-PSResourceRepository $TestRepoName - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL -Trusted - - $repo = Get-PSResourceRepository $TestRepoName - $repo.Name | should be $TestRepoName - $repo.URL | should be $TestRepoURL - $repo.Trusted | should be true - } - - It 'Should register the test repository when -URL is a website and priority is set' { - Unregister-PSResourceRepository $TestRepoName - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL -Priority 2 - - $repo = Get-PSResourceRepository $TestRepoName - $repo.Name | should be $TestRepoName - $repo.URL | should be $TestRepoURL - $repo.Trusted | should be $true - $repo.Priority | should be 2 - } - - <################################################################# - It 'Should fail to reregister the repository when the -Name is already registered' { - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL2 -ErrorVariable ev -ErrorAction SilentlyContinue - - $ev[0].FullyQualifiedErrorId | Should be "The PSResource Repository '$($TestRepoName)' exists." - } - #> - - <################################################################# - It 'Should fail to reregister the repository when the -URL is already registered' { - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL - Register-PSResourceRepository $TestRepoName2 -URL $TestRepoURL -ErrorVariable ev -ErrorAction SilentlyContinue - - $ev[0].FullyQualifiedErrorId | Should be "The repository could not be registered because there exists a registered repository with Name '$($TestRepoName)' and URL '$($TestRepoURL)'. To register another repository with Name '$($TestRepoName2)', please unregister the existing repository using the Unregister-PSResourceRepository cmdlet." - } - #> - - ### Registering a fileshare URL - It 'Should register the test repository when -URL is a fileshare' { - Write-Host $TestRepoLocalURL - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL - - $repo = Get-PSResourceRepository $TestRepoLocalName - $repo.Name | should be $TestRepoLocalName - - $repoModifiedURL = $repo.URL.replace("/","\") - $repoModifiedURL | should be ("file:\\\" + $TestRepoLocalURL) - $repo.Trusted | should be false - } - - It 'Should register the test repository when -URL is a fileshare and installation policy is trusted and priority is set' { - Write-Host $TestRepoLocalURL - Unregister-PSResourceRepository $TestRepoLocalName - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL -Trusted -Priority 2 - - $repo = Get-PSResourceRepository $TestRepoLocalName - $repo.Name | should be $TestRepoLocalName - - $repoModifiedURL = $repo.URL.replace("/","\") - $repoModifiedURL | should be ("file:\\\" + $TestRepoLocalURL) - $repo.Trusted | should be true - $repo.Priority | should be 2 - } - - <################################################################# - It 'Should fail to reregister the repository when the -Name is already registered' { - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL2 -ErrorVariable ev -ErrorAction SilentlyContinue - - $ev[0].FullyQualifiedErrorId | Should be "The PSResource Repository '$($TestRepoName)' exists." - } - #> - - <################################################################# - It 'Should fail to reregister the repository when the fileshare -URL is already registered' { - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL - Register-PSResourceRepository 'NewTestName' -URL $TestRepoLocalURL2 -ErrorVariable ev -ErrorAction SilentlyContinue - - $ev[0].FullyQualifiedErrorId | Should be "The repository could not be registered because there exists a registered repository with Name '$($TestRepoName)' and URL '$($TestRepoURL)'. To register another repository with Name '$($TestRepoName2)', please unregister the existing repository using the Unregister-PSResourceRepository cmdlet." - } - #> - - It 'Register PSResourceRepository File system location with special chars' { - $tmpdir = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'ps repo testing [$!@^&test(;)]' - if (-not (Test-Path -LiteralPath $tmpdir)) { - New-Item -Path $tmpdir -ItemType Directory > $null - } - try { - Register-PSResourceRepository -Name 'Test Repository' -URL $tmpdir - try { - Write-Host $tmpdir - - $repo = Get-PSResourceRepository -Name 'Test Repository' - $repo.Name | should be 'Test Repository' - - $repoModifiedURL = $repo.URL.replace("/","\") - $repoModifiedURL | should be ("file:\\\" + $tmpdir) - #$repo.URL | should be $tmpdir - } - finally { - Unregister-PSResourceRepository -Name 'Test Repository' -ErrorAction SilentlyContinue - } - } - finally { - Remove-Item -LiteralPath $tmpdir -Force -Recurse - } - } -} - - - -Describe 'Registering Repositories with Hashtable Parameters' -tags 'BVT', 'InnerLoop' { - - AfterAll { - # Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - BeforeEach { - # Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - It 'Should register a repository with parameters as a hashtable' { - Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - - $paramRegisterPSResourceRepository = @{ - Name = $TestRepoName - URL = $TestRepoURL - Trusted = $False - Priority = 1 - } - - { Register-PSResourceRepository @paramRegisterPSResourceRepository } | Should not Throw - - $repo = Get-PSResourceRepository -Name $TestRepoName - $repo.URL | Should be $TestRepoURL - $repo.Trusted | Should be $True - $repo.Priority | Should be 1 - } - - It 'Should register multiple repositories' { - Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - Unregister-PSResourceRepository -Name $PSGalleryName - - Register-PSResourceRepository -Repositories @( - @{ Name = $TestRepoName; URL = $TestRepoURL; Priority = 15 } - @{ Name = $TestRepoLocalName; URL = $TestRepoLocalURL } - @{ PSGallery = $true; Trusted = $true } - ) - - $repos = Get-PSResourceRepository - $repos.Count | Should be 3 - $repo1 = Get-PSResourceRepository $TestRepoName - $repo1.URL | Should be $TestRepoURL - $repo1.Priority | Should be 15 - - - $repo2 = Get-PSResourceRepository $TestRepoLocalName - - Write-Host $repo2.URL - $repo2ModifiedURL = $repo2.URL.replace("/","\") - - Write-Host $repo2.URL - Write-Host $repo2ModifiedURL - WRite-Host $TestRepoLocalURL - $repo2ModifiedURL | should be ("file:\\\" + $TestRepoLocalURL) - $repo2.Priority | Should be 50 - - $repo3 = Get-PSResourceRepository $PSGalleryName - $repo3.URL | Should be $PSGalleryLocation - $repo3.Priority | Should be 50 - } -} - - - - - - -################################ -### Set-PSResourceRepository ### -################################ -Describe 'Test Set-PSResourceRepository' -tags 'BVT', 'InnerLoop' { - - BeforeAll { - - #Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - - #Register-PSResourceRepository -PSGallery -ErrorAction SilentlyContinue - #Register-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - - #Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - AfterAll { - - } - - BeforeEach { - } - - AfterEach { - } - - It 'Should set PSGallery to a trusted installation policy and a non-zero priority' { - Unregister-PSResourceRepository -Name $PSGalleryName - Register-PSResourceRepository -PSGallery -Trusted:$False -Priority 0 - Set-PSResourceRepository $PSGalleryName -Trusted -Priority 2 - - $repo = Get-PSResourceRepository $PSGalleryName - $repo.URL | should be $PSGalleryLocation - $repo.Trusted | should be $true - $repo.Priority | should be 2 - } - - It 'Should set PSGallery to an untrusted installation policy' { - Unregister-PSResourceRepository -Name $PSGalleryName - Register-PSResourceRepository -PSGallery -Trusted - Set-PSResourceRepository -Name $PSGalleryName -Trusted:$False - - $repo = Get-PSResourceRepository $PSGalleryName - $repo.Trusted | should be false - $repo.Priority | should be 50 - } - - <################################################################# - It 'Should fail to set PSGallery to a different URL' { - Set-PSResourceRepository $PSGalleryName -URL $TestRepoURL -ErrorVariable ev -ErrorAction SilentlyContinue - - $ev[0].FullyQualifiedErrorId | Should be "The PSGallery repository has pre-defined locations. Setting the 'URL' parameter is not allowed, try again after removing the 'URL' parameter." - } - #> -} - - - -Describe 'Test Set-PSResourceRepository with hashtable parameters' -tags 'BVT', 'InnerLoop' { - - AfterAll { - } - BeforeAll { - } - - BeforeEach { - - } - - - # if repo isn't registered it shouldnt be set' - It 'Should set repository with given hashtable parameters' { - Unregister-PSResourceRepository -Name $TestRepoName - Unregister-PSResourceRepository -Name $TestRepoLocalName - Unregister-PSResourceRepository -Name $PSGalleryName - - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL - - $paramSetPSResourceRepository = @{ - Name = $TestRepoName - URL = $TestRepoURL2 - Trusted = $False - Priority = 1 - } - - { Set-PSResourceRepository -Repositories $paramSetPSResourceRepository } | Should not Throw - - $repo = Get-PSResourceRepository -Name $TestRepoName - $repo.URL | Should be $TestRepoURL2 - $repo.Trusted | Should be false - $repo.Priority | Should be 1 - } - - It 'Should set multiple repositories' { - Unregister-PSResourceRepository -Name $TestRepoName - - Register-PSResourceRepository $TestRepoName -URL $TestRepoURL - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL -Priority 0 - Register-PSResourceRepository -PSGallery - - Write-Host $TestRepoURL - $repositories = @( - @{ Name = $TestRepoName; URL = $TestRepoURL2; Priority = 9 }, - @{ Name = $TestRepoLocalName; URL = $TestRepoLocalURL2; Trusted =$True } - #@{ Name = $PSGalleryName; Trusted = $True /*****************************/ - ) - - { Set-PSResourceRepository -Repositories $repositories } | Should not Throw - - $repos = Get-PSResourceRepository - $repos.Count | Should be 3 - - $repo1 = Get-PSResourceRepository $TestRepoName - $repo1.URL | Should be $TestRepoURL2 - $repo1.Trusted | Should be false - $repo1.Priority | Should be 9 - - $repo2 = Get-PSResourceRepository $TestRepoLocalName - $repo2ModifiedURL = $repo2.URL.replace("/","\") - $repo2ModifiedURL | should be ("file:\\\" + $TestRepoLocalURL2) - #$repo2.URL | Should be $TestRepoLocalURL2 - $repo2.Trusted | Should be true - $repo2.Priority | Should be 50 - - $repo3 = Get-PSResourceRepository $PSGalleryName - $repo3.URL | Should be $PSGalleryLocation - # $repo3.Trusted | Should be true - $repo3.Priority | Should be 50 - } - -} - - - - - - -################################ -### Get-PSResourceRepository ### -################################ -Describe 'Test Get-PSResourceRepository' -tags 'BVT', 'InnerLoop' { - - BeforeAll { - - #Register-PSResourceRepository -PSGallery -Trusted -ErrorAction SilentlyContinue - #Register-PSResourceRepository -Name $TestRepoName -URL $TestRepoURL -Trusted -Priority 2 -ErrorAction SilentlyContinue - #Register-PSResourceRepository -Name $TestRepoName2 -URL $TestRepoURL2 -Priority 15 -ErrorAction SilentlyContinue - ##Register-PSResourceRepository -Name $TestRepoLocalName -URL $TestRepoLocalURL -ErrorAction SilentlyContinue - ##Register-PSResourceRepository -Name $TestRepoLocalName2 -URL $TestRepoLocalURL2 -ErrorAction SilentlyContinue - } - - AfterAll { - #Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - #Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - BeforeEach { - - } - - It 'Should get PSGallery repository' { - Unregister-PSResourceRepository -Name $PSGalleryName - Register-PSResourceRepository -PSGallery -Trusted -ErrorAction SilentlyContinue - - $repo = Get-PSResourceRepository $PSGalleryName - $repo.URL | should be $PSGalleryLocation - $repo.Trusted | should be $true - $repo.Priority | should be 50 - } - - It 'Should get test repository' { - Unregister-PSResourceRepository -Name $TestRepoName - Register-PSResourceRepository -Name $TestRepoName -URL $TestRepoURL -Trusted -Priority 2 -ErrorAction SilentlyContinue - - $repo = Get-PSResourceRepository $TestRepoName - $repo.URL | should be $TestRepoURL - $repo.Trusted | should be $true - $repo.Priority | should be 2 - } - - - - It 'Should get multiple repositories' { - get-PSResourceRepository - Unregister-PSResourceRepository -Name $TestRepoLocalName - Register-PSResourceRepository -Name $TestRepoName2 -URL $TestRepoURL2 -Priority 15 -ErrorAction SilentlyContinue - Register-PSResourceRepository -Name $TestRepoLocalName2 -URL $TestRepoLocalURL2 -ErrorAction SilentlyContinue - - $repos = Get-PSResourceRepository $PSGalleryName, $TestRepoName2, $TestRepoLocalName2 - - $repos.Count | Should be 3 - - $repos.Name | should contain $PSGalleryName - $repos.Name | should contain $TestRepoName2 - $repos.Name | should contain $TestRepoLocalName2 - - - $repos.URL | should contain $PSGalleryLocation - $repos.URL | should contain $TestRepoURL2 - - $repoModifiedURL = "file:///" + ($TestRepoLocalURL2.replace("\", "/")); - $repos.URL | should contain $repoModifiedURL - - $repos.Priority | should contain 15 - $repos.Priority | should contain 50 - - } - - It 'Should get all repositories' { - Register-PSResourceRepository $TestRepoLocalName -URL $TestRepoLocalURL - - $repos = Get-PSResourceRepository - - $repos.Count | Should be 5 - - $repos.Name | should contain $PSGalleryName - $repos.Name | should contain $TestRepoName - $repos.Name | should contain $TestRepoName2 - $repos.Name | should contain $TestRepoLocalName - $repos.Name | should contain $TestRepoLocalName2 - - $repos.URL | should contain $PSGalleryLocation - $repos.URL | should contain $TestRepoURL - $repos.URL | should contain $TestRepoURL2 - - $repoModifiedURL = "file:///" + ($TestRepoLocalURL.replace("\", "/")); - $repos.URL | should contain $repoModifiedURL - - $repoModifiedURL2 = "file:///" + ($TestRepoLocalURL2.replace("\", "/")); - $repos.URL | should contain $repoModifiedURL2 - - $repos.Priority | should contain 2 - $repos.Priority | should contain 50 - $repos.Priority | should contain 15 - - } -} - - - - - - -####################################### -### Unregister-PSResourceRepository ### -####################################### - -Describe 'Test Unregister-PSResourceRepository' -tags 'BVT' { - - BeforeAll { - - } - AfterAll { - # Unregister-PSResourceRepository -Name $PSGalleryName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoName2 -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName -ErrorAction SilentlyContinue - # Unregister-PSResourceRepository -Name $TestRepoLocalName2 -ErrorAction SilentlyContinue - } - - BeforeEach { - - } - - ### Unregistering the PowerShell Gallery - It 'Should unregister the default PSGallery' { - Unregister-PSResourceRepository $PSGalleryName -ErrorVariable ev -ErrorAction SilentlyContinue - - $repo = Get-PSResourceRepository $PSGalleryName - $repo | Should -BeNullOrEmpty - } - - ### Unregistering any repository - It 'Should unregister a given repository' { - Unregister-PSResourceRepository $TestRepoName -ErrorVariable ev -ErrorAction SilentlyContinue - - $repo = Get-PSResourceRepository $TestRepoName - $repo | Should -BeNullOrEmpty - } - -} - - -<# - It 'Should unregister multiple repositories' { - Unregister-PSResourceRepository $TestRepoName, $TestRepoName2, $TestRepoLocalName - - $repos = Get-PSResourceRepository $TestRepoName, $TestRepoName2, $TestRepoLocalName -ErrorVariable ev -ErrorAction SilentlyContinue - $repos | Should -BeNullOrEmpty - $ev[0].FullyQualifiedErrorId | Should be "Unable to find repository 'PSGallery'. Use Get-PSResourceRepository to see all available repositories." - - } - -} - -#> - - diff --git a/testOld/PublishResource.Tests.ps1 b/testOld/PublishResource.Tests.ps1 deleted file mode 100644 index 9bc25b4e0..000000000 --- a/testOld/PublishResource.Tests.ps1 +++ /dev/null @@ -1,98 +0,0 @@ -# This is a Pester test suite to validate Register-PSResourceRepository, Unregister-PSResourceRepository, Get-PSResourceRepository, and Set-PSResourceRepository. -# -# Copyright (c) Microsoft Corporation, 2019 - -# TODO: -Write-Warning "PSRepository.Tests.ps1 is current disabled." -return - -$psGetMod = Get-Module -Name PowerShellGet -if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) -{ - Write-Verbose -Verbose "Importing PowerShellGet 3.0.0 for test" - Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force -} - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -WarningAction SilentlyContinue -force - -$PSGalleryName = 'PSGallery' -$PSGalleryLocation = 'https://www.powershellgallery.com/api/v2' - -$TestLocalDirectory = 'TestLocalDirectory' -$tmpdir = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $TestLocalDirectory - - - -if (-not (Test-Path -LiteralPath $tmpdir)) { - New-Item -Path $tmpdir -ItemType Directory > $null -} - - -########################## -### Publish-PSResource ### -########################## -Describe 'Test Publish-PSResource' -tags 'BVT' { - - BeforeAll { - - Register-PSResourceRepository -Name psgettestlocal -URL "c:\code\testdir" - - # Create temp module to be published - $script:TempModulesPath = Join-Path -Path $tmpdir -ChildPath "PSGet_$(Get-Random)" - $null = New-Item -Path $script:TempModulesPath -ItemType Directory -Force - - $script:PublishModuleName = "TestPublishModule" - $script:PublishModuleBase = Join-Path $script:TempModulesPath $script:PublishModuleName - $null = New-Item -Path $script:PublishModuleBase -ItemType Directory -Force - - } - AfterAll { - if($tempdir -and (Test-Path $tempdir)) - { - Remove-Item $tempdir -Force -Recurse -ErrorAction SilentlyContinue - } - } - - ### Publish a script - It 'Should publish a script' - { - - $Name = 'TestScriptName' - $scriptFilePath = Join-Path -Path $script:TempModulesPath -ChildPath "$Name.ps1" - $null = New-Item -Path $scriptFilePath -ItemType File -Force - - $version = "1.0.0" - $params = @{ - #Path = $scriptFilePath - Version = $version - #GUID = - Author = 'Jane' - CompanyName = 'Microsoft Corporation' - Copyright = '(c) 2020 Microsoft Corporation. All rights reserved.' - Description = "Description for the $Name script" - LicenseUri = "https://$Name.com/license" - IconUri = "https://$Name.com/icon" - ProjectUri = "https://$Name.com" - Tags = @('Tag1','Tag2', "Tag-$Name-$version") - ReleaseNotes = "$Name release notes" - } - - $scriptMetadata = Create-PSScriptMetadata @params - Set-Content -Path $scriptFilePath -Value $scriptMetadata - - Publish-PSResource -path $scriptFilePath -Repository psgettestlocal - } - - - It 'Should publish a module' - { - $PublishModuleBase = Join-Path $script:TempModulesPath $script:PublishModuleName - - $version = "1.0" - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - - Publish-PSResource -path $script:PublishModuleBase -Repository psgettestlocal - } -} - - diff --git a/testOld/RequiredResource.Tests.ps1 b/testOld/RequiredResource.Tests.ps1 deleted file mode 100644 index 68d000625..000000000 --- a/testOld/RequiredResource.Tests.ps1 +++ /dev/null @@ -1,147 +0,0 @@ -# This is a Pester test suite to validate Register-PSResourceRepository, Unregister-PSResourceRepository, Get-PSResourceRepository, and Set-PSResourceRepository. -# -# Copyright (c) Microsoft Corporation, 2019 - -# TODO: -Write-Warning "PSRepository.Tests.ps1 is current disabled." -return - -$psGetMod = Get-Module -Name PowerShellGet -if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) -{ - Write-Verbose -Verbose "Importing PowerShellGet 3.0.0 for test" - Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force -} - -$PSGalleryName = 'PSGallery' -$PSGalleryLocation = 'https://www.powershellgallery.com/api/v2' - -$TestLocalDirectory = 'TestLocalDirectory' -$tmpdir = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $TestLocalDirectory - - - -if (-not (Test-Path -LiteralPath $tmpdir)) { - New-Item -Path $tmpdir -ItemType Directory > $null -} -Write-Host $tmpdir - - -############################################ -### Install-PSResource -RequiredResource ### -############################################ - -Describe 'Test Install-PSResource using the RequiredResource parameter set' -tags 'BVT' { - - AfterEach { - $null = uninstall-psresource 'CertificateDsc' -ErrorAction SilentlyContinue - } - - ### Installing using -RequiredResource and a json argument - It 'Should install the resource specified in the json (with specified parameters)' { - $json = - "{ - 'CertificateDsc': { - 'version': '[4.0.0,4.2.0]', - 'repository': 'PSGallery', - 'Prerelease': true - } - }" - - $ret = Install-PSResource -RequiredResource $json - $ret | Should -BeNullOrEmpty - - $pkg = get-psresource 'CertificateDsc' -Version '[4.0.0.0,4.2.0.0]' - $pkg.Name | Should -Be 'CertificateDsc' - $pkg.Version.ToString() | Should -BeGreaterOrEqual 4.0.0.0 - $pkg.Version.ToString() | Should -BeLessOrEqual 4.2.0.0 - } - - - It 'Should install multiple resources specified in the json' { - $json = - "{ - 'CertificateDsc': { - 'version': '[4.0.0,4.2.0]', - 'repository': 'PSGallery', - 'Prerelease': true - }, - 'WSManDsc': { - 'repository': 'PSGallery', - 'Prerelease': true - } - }" - - $ret = Install-PSResource -RequiredResource $json - $ret | Should -BeNullOrEmpty - - $pkg = get-psresource 'CertificateDsc' -Version '[4.0.0.0,4.2.0.0]' - $pkg.Name | Should -Be 'CertificateDsc' - $pkg.Version.ToString() | Should -BeGreaterOrEqual 4.0.0.0 - $pkg.Version.ToString() | Should -BeLessOrEqual 4.2.0.0 - - $pkg2 = get-psresource 'WSManDsc' -Version '3.1.2-preview0001' - $pkg2.Name | Should -Be 'WSManDsc' - $pkg2.Version.ToString() | Should -Be '3.1.2-preview0001' - } - - - ### Installing using -RequiredResource and a hashtable argument - It 'Should install the resource specified in the hashtable' { - $hash = - @{ - name = "CertificateDsc" - trustrepository = "true" - version = "[4.0.0,4.2.0]" - Prerelease = "true" - } - - $ret = Install-PSResource -RequiredResource $hash - $ret | Should -BeNullOrEmpty - - $pkg = get-psresource 'CertificateDsc' -Version '[4.0.0.0,4.2.0.0]' - $pkg.Name | Should -Be 'CertificateDsc' - $pkg.Version.ToString() | Should -BeGreaterOrEqual 4.0.0.0 - $pkg.Version.ToString() | Should -BeLessOrEqual 4.2.0.0 - } -} - - - - -################################################ -### Install-PSResource -RequiredResourceFile ### -################################################ - -Describe 'Test Install-PSResource using the RequiredResource parameter set' -tags 'BVT' { - - ### Installing using -RequiredResource and a json file - It 'Should install the resource specified in the json file' { - $json = - "{ - 'CertificateDsc': { - 'version': '[4.0.0,4.2.0]', - 'repository': 'PSGallery', - 'Prerelease': true - } - }" - - $tmpJsonFile = Join-Path -Path $tmpdir -ChildPath "TestJsonFile.json" - - New-Item -Path $tmpJsonFile -ItemType File - $json | Write-File $tmpJsonFile - - if ($tmpJsonFile -ne $null) - { - $ret = Install-PSResource -RequiredResourceFile $tmpJsonFile - } - Remove-Item $tmpJsonFile - - $ret | Should -BeNullOrEmpty - - $pkg = get-psresource 'CertificateDsc' -Version '[4.0.0.0,4.2.0.0]' - $pkg.Name | Should -Be 'CertificateDsc' - $pkg.Version.ToString() | Should -BeGreaterOrEqual 4.0.0.0 - $pkg.Version.ToString() | Should -BeLessOrEqual 4.2.0.0 - } -} diff --git a/testOld/testRepositories.xml b/testOld/testRepositories.xml deleted file mode 100644 index 5f186d004..000000000 --- a/testOld/testRepositories.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - From 4e20a1c3e5f76108cb2ba9adc24c042369799ce0 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 22 Jun 2021 13:27:24 -0700 Subject: [PATCH 017/276] Fix ci branch (#384) --- .ci/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.ci/ci.yml b/.ci/ci.yml index 1ca4269ea..c76d10ea9 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -4,13 +4,11 @@ trigger: batch: true branches: include: - #- master - - development + - master pr: branches: include: - #- master - - development + - master resources: repositories: From f8b8738a8e8cbb714d6acf21aad42cb1ebb01bed Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 22 Jun 2021 15:05:08 -0700 Subject: [PATCH 018/276] Fix CI to account for removal of bin directory. (#385) --- .ci/ci.yml | 4 +--- .ci/ci_auto.yml | 40 +--------------------------------------- .ci/ci_release.yml | 40 +--------------------------------------- doBuild.ps1 | 2 -- 4 files changed, 3 insertions(+), 83 deletions(-) diff --git a/.ci/ci.yml b/.ci/ci.yml index c76d10ea9..9df554fec 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -67,10 +67,8 @@ stages: Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force # - # First build for netstandard2.0 framework + # Build for netstandard2.0 framework $(Build.SourcesDirectory)/build.ps1 -Build -Clean -BuildConfiguration Release -BuildFramework 'netstandard2.0' - # Next build for net472 framework - $(Build.SourcesDirectory)/build.ps1 -Build -BuildConfiguration Release -BuildFramework 'net472' displayName: Build and publish artifact - pwsh: | diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 4549378c0..cfd7ceb00 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -73,10 +73,8 @@ stages: Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force # - # First build for netstandard2.0 framework + # Build for netstandard2.0 framework $(Build.SourcesDirectory)/build.ps1 -Build -Clean -BuildConfiguration Release -BuildFramework 'netstandard2.0' - # Next build for net472 framework - $(Build.SourcesDirectory)/build.ps1 -Build -BuildConfiguration Release -BuildFramework 'net472' displayName: Build and publish artifact - pwsh: | @@ -112,12 +110,6 @@ stages: Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose - $net472Path = Join-Path -Path $createdSignSrcPath -ChildPath "net472" - if (! (Test-Path -Path $net472Path)) { - $null = New-Item -Path $net472Path -ItemType Directory -Verbose - } - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "net472\PowerShellGet.*") -Dest $net472Path -Force -Verbose - $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" if (! (Test-Path -Path $netStandardPath)) { $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose @@ -186,21 +178,6 @@ stages: if (! (Test-Path -Path $thirdPartySignSrcPath)) { $null = New-Item -Path $thirdPartySignSrcPath -ItemType Directory -Verbose } - - # Net472 directory - $net472Path = Join-Path -Path $thirdPartySignSrcPath -ChildPath "net472" - if (! (Test-Path -Path $net472Path)) { - $null = New-Item -Path $net472Path -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { - # Copy for third party signing - Copy-Item -Path $_.FullName -Dest $net472Path -Force -Verbose - } - } - } # NetStandard directory $netStandardPath = Join-Path -Path $thirdPartySignSrcPath -ChildPath "netstandard2.0" @@ -256,21 +233,6 @@ stages: # en-US Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse - # Net472 directory - $net472SignedOutPath = Join-Path -Path $signOutPath -ChildPath "net472" - if (! (Test-Path -Path $net472SignedOutPath)) { - $null = New-Item -Path $net472SignedOutPath -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { - # Copy already signed files directly to output - Copy-Item -Path $_.FullName -Dest $net472SignedOutPath -Force -Verbose - } - } - } - # NetStandard directory $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" if (! (Test-Path -Path $netStandardSignedOutPath)) { diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 01b468471..9035e2676 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -72,10 +72,8 @@ stages: Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force # - # First build for netstandard2.0 framework + # Build for netstandard2.0 framework $(Build.SourcesDirectory)/build.ps1 -Build -Clean -BuildConfiguration Release -BuildFramework 'netstandard2.0' - # Next build for net472 framework - $(Build.SourcesDirectory)/build.ps1 -Build -BuildConfiguration Release -BuildFramework 'net472' displayName: Build and publish artifact - pwsh: | @@ -111,12 +109,6 @@ stages: Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose - $net472Path = Join-Path -Path $createdSignSrcPath -ChildPath "net472" - if (! (Test-Path -Path $net472Path)) { - $null = New-Item -Path $net472Path -ItemType Directory -Verbose - } - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "net472\PowerShellGet.*") -Dest $net472Path -Force -Verbose - $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" if (! (Test-Path -Path $netStandardPath)) { $null = New-Item -Path $netStandardPath -ItemType Directory -Verbose @@ -184,21 +176,6 @@ stages: if (! (Test-Path -Path $thirdPartySignSrcPath)) { $null = New-Item -Path $thirdPartySignSrcPath -ItemType Directory -Verbose } - - # Net472 directory - $net472Path = Join-Path -Path $thirdPartySignSrcPath -ChildPath "net472" - if (! (Test-Path -Path $net472Path)) { - $null = New-Item -Path $net472Path -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Microsoft*' -or $sig.SignerCertificate.Issuer -notlike '*Microsoft Code Signing PCA*') { - # Copy for third party signing - Copy-Item -Path $_.FullName -Dest $net472Path -Force -Verbose - } - } - } # NetStandard directory $netStandardPath = Join-Path -Path $thirdPartySignSrcPath -ChildPath "netstandard2.0" @@ -254,21 +231,6 @@ stages: # en-US Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse - # Net472 directory - $net472SignedOutPath = Join-Path -Path $signOutPath -ChildPath "net472" - if (! (Test-Path -Path $net472SignedOutPath)) { - $null = New-Item -Path $net472SignedOutPath -ItemType Directory -Verbose - } - Get-ChildItem -Path (Join-Path -Path $srcPath -ChildPath "net472") -Filter '*.dll' | Foreach-Object { - if ($_.Name -ne 'PowerShellGet.dll') { - $sig = Get-AuthenticodeSignature -FilePath $_.FullName - if ($sig.Status -eq 'Valid' -and ($sig.SignerCertificate.Subject -like '*Microsoft*' -and $sig.SignerCertificate.Issuer -like '*Microsoft Code Signing PCA*')) { - # Copy already signed files directly to output - Copy-Item -Path $_.FullName -Dest $net472SignedOutPath -Force -Verbose - } - } - } - # NetStandard directory $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" if (! (Test-Path -Path $netStandardSignedOutPath)) { diff --git a/doBuild.ps1 b/doBuild.ps1 index c6ae2a80c..a024b035d 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -20,8 +20,6 @@ function DoBuild # Copy module script files Write-Verbose -Verbose "Copy-Item ${SrcPath}/${ModuleName}.psd1 to $BuildOutPath" Copy-Item -Path "${SrcPath}/${ModuleName}.psd1" -Dest "$BuildOutPath" -Force - Write-Verbose -Verbose "Copy Item ${SrcPath}/PSModule.psm1 to $BuildOutPath" - Copy-Item -Path "${SrcPath}/PSModule.psm1" -Dest "$BuildOutPath" -Force #Copy module format ps1xml file Write-Verbose -Verbose -Message "Copy-Item ${SrcPath}/${FormatFileName}.ps1xml to $BuildOutPath" From 20720956681d711bd961f3fb8037ec3474c6bdae Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 22 Jun 2021 15:28:56 -0700 Subject: [PATCH 019/276] Add missing config (#386) --- nuget.config | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 nuget.config diff --git a/nuget.config b/nuget.config new file mode 100644 index 000000000..654858614 --- /dev/null +++ b/nuget.config @@ -0,0 +1,10 @@ + + + + + + + + + + From 6be9a489f508295f3e8a01a0cb03a2bb88155778 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 23 Jun 2021 10:06:47 -0700 Subject: [PATCH 020/276] Remove psmodule from build (#387) --- .ci/ci_auto.yml | 1 - .ci/ci_release.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index cfd7ceb00..10c3f4fe0 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -106,7 +106,6 @@ stages: $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSModule.psm1") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 9035e2676..d82a56a30 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -105,7 +105,6 @@ stages: $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSModule.psm1") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose From de84366c12b0185046b1e3446e7afcbf652dbbb3 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 23 Jun 2021 13:57:31 -0700 Subject: [PATCH 021/276] Remove explicit module import from tests (#389) --- test/PSGetTestUtils.psm1 | 7 ------- test/PSResourceInfo.Tests.ps1 | 7 ------- 2 files changed, 14 deletions(-) diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index dc9223c10..47ce9bcca 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -1,13 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -$psGetMod = Get-Module -Name PowerShellGet -if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) -{ - Write-Verbose -Message "Importing PowerShellGet 3.0.0 for test" -Verbose - Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force -} - $script:DotnetCommandPath = @() $script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 } $script:EnvPATHValueBackup = $null diff --git a/test/PSResourceInfo.Tests.ps1 b/test/PSResourceInfo.Tests.ps1 index 023c23c18..7f63e5a5c 100644 --- a/test/PSResourceInfo.Tests.ps1 +++ b/test/PSResourceInfo.Tests.ps1 @@ -3,13 +3,6 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force -$psGetMod = Get-Module -Name PowerShellGet -if ((! $psGetMod) -or (($psGetMod | Select-Object Version) -lt 3.0.0)) -{ - Write-Verbose -Message "Importing PowerShellGet 3.0.0 for test" -Verbose - Import-Module -Name PowerShellGet -MinimumVersion 3.0.0 -Force -} - Describe "Read PSGetModuleInfo xml file" -tags 'CI' { BeforeAll { From 03ebe2652108c1e5d6ccb3905442b102c9e91886 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 23 Jun 2021 16:52:18 -0700 Subject: [PATCH 022/276] Add missing format file to build (#390) --- .ci/ci_auto.yml | 1 + .ci/ci_release.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 10c3f4fe0..39542271a 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -106,6 +106,7 @@ stages: $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSGet.Format.ps1xml") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index d82a56a30..dec8f20c5 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -105,6 +105,7 @@ stages: $null = New-Item -Path $createdSignSrcPath -ItemType Directory -Verbose } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSGet.Format.ps1xml") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose From d6b52a8e2a623fdea947c44d004a7b5e21050524 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 24 Jun 2021 10:18:53 -0700 Subject: [PATCH 023/276] Temporary 30 min scheduled to investigate tests (#391) --- .ci/ci_auto.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 39542271a..4b0fba8ef 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -5,7 +5,9 @@ pr: none schedules: # Use https://crontab.guru/#0_8_*_*_* to compute crontab expression # Run signed build, with limited signing cert, every day at 9 am -- cron: 0 9 * * * +# - cron: 0 9 * * * +# Temporary schedule to run every 30 minutes, to investigate test failures +- cron: "*/30 * * * *" branches: include: - refs/heads/master From 45608851a5b766c35eb3df9a1a73c65a0ffd1b6b Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 24 Jun 2021 17:15:52 -0400 Subject: [PATCH 024/276] change WriteDebug in catch to WriteVerbose -Verbose (#392) --- src/code/FindHelper.cs | 13 +++++++------ src/code/Utils.cs | 12 ++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 20403865a..6a26fe732 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -191,7 +191,7 @@ public IEnumerable SearchFromRepository( resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); } catch (Exception e){ - _cmdletPassedIn.WriteDebug("Error retrieving resource from repository: " + e.Message); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "Error retrieving resource from repository: " + e.Message); } if (resourceSearch == null || resourceMetadata == null) @@ -271,16 +271,16 @@ private IEnumerable FindFromPackageSourceSearchAPI( } catch (HttpRequestException ex) { + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync()- error receiving package: " + ex.Message); if ((String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) { - _cmdletPassedIn.WriteDebug(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); - yield break; + _cmdletPassedIn.WriteWarning(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); } } catch (Exception e) { - _cmdletPassedIn.WriteDebug(String.Format("Exception retrieving package {0} due to {1}.", pkgName, e.Message)); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync()- error receiving package: " + e.Message); } if (retrievedPkgs == null || retrievedPkgs.Count() == 0) @@ -330,16 +330,17 @@ private IEnumerable FindFromPackageSourceSearchAPI( } catch (HttpRequestException ex) { + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper SearchAsync()- error receiving package: " + ex.Message); if ((String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) { - _cmdletPassedIn.WriteDebug(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); + _cmdletPassedIn.WriteWarning(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); } yield break; } catch (Exception e) { - _cmdletPassedIn.WriteDebug(String.Format("Exception retrieving package {0} due to {1}.", pkgName, e.Message)); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper SearchAsync()- error receiving package: " + e.Message); yield break; } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 5715958f5..75101d060 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -16,6 +16,18 @@ namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { internal static class Utils { + public static void WriteVerboseOnCmdlet( + PSCmdlet cmdlet, + string message) + { + cmdlet.InvokeCommand.InvokeScript( + script: $"Write-Verbose -Verbose -Message {message}", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: null); + } + public static string[] FilterOutWildcardNames( string[] pkgNames, out string[] errorMsgs) From 220905cb8c7e0e32105e7971897fe910748762a0 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 24 Jun 2021 14:57:28 -0700 Subject: [PATCH 025/276] Fix verbose message parse error (#393) --- src/code/FindHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 6a26fe732..5de3044d0 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -271,7 +271,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( } catch (HttpRequestException ex) { - Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync()- error receiving package: " + ex.Message); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync: error receiving package: " + ex.Message); if ((String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) { @@ -280,7 +280,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( } catch (Exception e) { - Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync()- error receiving package: " + e.Message); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync: error receiving package: " + e.Message); } if (retrievedPkgs == null || retrievedPkgs.Count() == 0) @@ -330,7 +330,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( } catch (HttpRequestException ex) { - Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper SearchAsync()- error receiving package: " + ex.Message); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper SearchAsync: error receiving package: " + ex.Message); if ((String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || String.Equals(repositoryName, _psGalleryScriptsRepoName, StringComparison.InvariantCultureIgnoreCase))) { @@ -340,7 +340,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( } catch (Exception e) { - Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper SearchAsync()- error receiving package: " + e.Message); + Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper SearchAsync: error receiving package: " + e.Message); yield break; } From 20f08d3341bd8a1075f23038f86324202e86cd12 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 24 Jun 2021 15:07:43 -0700 Subject: [PATCH 026/276] Fix quote (#394) --- src/code/Utils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 75101d060..1e89e401c 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -21,7 +21,7 @@ public static void WriteVerboseOnCmdlet( string message) { cmdlet.InvokeCommand.InvokeScript( - script: $"Write-Verbose -Verbose -Message {message}", + script: $"Write-Verbose -Verbose -Message '{message}'", useNewScope: true, writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, input: null, From 8b2fa95f1eef1bd5ff15fd4770a171c3c179e9e9 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 25 Jun 2021 09:21:29 -0700 Subject: [PATCH 027/276] Reset cron time (#395) --- .ci/ci_auto.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 4b0fba8ef..8b9cd3e01 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -4,10 +4,10 @@ pr: none schedules: # Use https://crontab.guru/#0_8_*_*_* to compute crontab expression -# Run signed build, with limited signing cert, every day at 9 am -# - cron: 0 9 * * * # Temporary schedule to run every 30 minutes, to investigate test failures -- cron: "*/30 * * * *" +# - cron: "*/30 * * * *" +# Run signed build, with limited signing cert, every day at 9 am +- cron: 0 9 * * * branches: include: - refs/heads/master From eab3a3864795da4b7f3f17172b64b5dc049022fe Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 25 Jun 2021 11:10:01 -0700 Subject: [PATCH 028/276] Fix WriteVerboseOnCmdlet parse error (#396) --- src/code/FindPSResource.cs | 1 + src/code/Utils.cs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index a44a5624c..8afff6668 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -109,6 +109,7 @@ class FindPSResource : PSCmdlet [Parameter(ParameterSetName = ResourceNameParameterSet)] [Parameter(ParameterSetName = CommandNameParameterSet)] [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] public string[] Repository { get; set; } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 1e89e401c..6e7dc45c1 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -20,12 +20,16 @@ public static void WriteVerboseOnCmdlet( PSCmdlet cmdlet, string message) { - cmdlet.InvokeCommand.InvokeScript( - script: $"Write-Verbose -Verbose -Message '{message}'", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: null); + try + { + cmdlet.InvokeCommand.InvokeScript( + script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { message }); + } + catch { } } public static string[] FilterOutWildcardNames( From 71b42c07672022fd6ef0fa1ee76b6c6fcca9faf3 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 25 Jun 2021 12:54:49 -0700 Subject: [PATCH 029/276] Change schedule for testing (#397) --- .ci/ci_auto.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 8b9cd3e01..4b0fba8ef 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -4,10 +4,10 @@ pr: none schedules: # Use https://crontab.guru/#0_8_*_*_* to compute crontab expression -# Temporary schedule to run every 30 minutes, to investigate test failures -# - cron: "*/30 * * * *" # Run signed build, with limited signing cert, every day at 9 am -- cron: 0 9 * * * +# - cron: 0 9 * * * +# Temporary schedule to run every 30 minutes, to investigate test failures +- cron: "*/30 * * * *" branches: include: - refs/heads/master From 61e896f8b0ba91c72c1142b914f104c7cca2c897 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 25 Jun 2021 14:11:51 -0700 Subject: [PATCH 030/276] Set schedule back (#398) --- .ci/ci_auto.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 4b0fba8ef..8b9cd3e01 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -4,10 +4,10 @@ pr: none schedules: # Use https://crontab.guru/#0_8_*_*_* to compute crontab expression -# Run signed build, with limited signing cert, every day at 9 am -# - cron: 0 9 * * * # Temporary schedule to run every 30 minutes, to investigate test failures -- cron: "*/30 * * * *" +# - cron: "*/30 * * * *" +# Run signed build, with limited signing cert, every day at 9 am +- cron: 0 9 * * * branches: include: - refs/heads/master From 6103eafe31b14c4c40f662d8201fc48579e3a6ae Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 28 Jun 2021 10:28:35 -0700 Subject: [PATCH 031/276] Add missing signing directive (#400) --- .ci/ci_auto.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 8b9cd3e01..9080e4dc1 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -213,6 +213,7 @@ stages: buildOutputPath: $(signSrcPath) signOutputPath: $(signOutPath) certificateId: "CP-231522" + shouldSign: $(ShouldSign) pattern: | **\*.dll useMinimatch: true From 55a60d1682c5a1c67014146babb484fed5ffcfdd Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 29 Jun 2021 09:56:11 -0700 Subject: [PATCH 032/276] Remove non-working tag type parameter sets (#401) --- src/code/FindPSResource.cs | 133 +++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 58 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 8afff6668..1c9bf2dbc 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -20,18 +20,14 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets [Cmdlet(VerbsCommon.Find, "PSResource", DefaultParameterSetName = ResourceNameParameterSet, - SupportsShouldProcess = true, - HelpUri = "")] + SupportsShouldProcess = true)] [OutputType(typeof(PSResourceInfo))] - public sealed - class FindPSResource : PSCmdlet + public sealed class FindPSResource : PSCmdlet { #region Members private const string ResourceNameParameterSet = "ResourceNameParameterSet"; private const string CommandNameParameterSet = "CommandNameParameterSet"; private const string DscResourceNameParameterSet = "DscResourceNameParameterSet"; - private const string TagParameterSet = "TagParameterSet"; - private const string TypeParameterSet = "TypeParameterSet"; private CancellationTokenSource _source; private CancellationToken _cancellationToken; @@ -42,7 +38,10 @@ class FindPSResource : PSCmdlet /// /// Specifies name of a resource or resources to find. Accepts wild card characters. /// - [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ResourceNameParameterSet)] + [Parameter(Position = 0, + ValueFromPipeline = true, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ResourceNameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } @@ -51,7 +50,6 @@ class FindPSResource : PSCmdlet /// Resource types supported are: Module, Script, Command, DscResource /// [Parameter(ParameterSetName = ResourceNameParameterSet)] - [Parameter(Mandatory = true, ParameterSetName = TypeParameterSet)] public ResourceType Type { get; set; } /// @@ -82,14 +80,14 @@ class FindPSResource : PSCmdlet /// /// Specifies a list of command names that searched module packages will provide. Wildcards are supported. /// - [Parameter(ParameterSetName = CommandNameParameterSet)] + [Parameter(Mandatory = true, ParameterSetName = CommandNameParameterSet)] [ValidateNotNullOrEmpty] public string[] CommandName { get; set; } /// /// Specifies a list of dsc resource names that searched module packages will provide. Wildcards are supported. /// - [Parameter(ParameterSetName = DscResourceNameParameterSet)] + [Parameter(Mandatory = true, ParameterSetName = DscResourceNameParameterSet)] [ValidateNotNullOrEmpty] public string[] DscResourceName { get; set; } @@ -99,7 +97,6 @@ class FindPSResource : PSCmdlet [Parameter(ParameterSetName = ResourceNameParameterSet)] [Parameter(ParameterSetName = CommandNameParameterSet)] [Parameter(ParameterSetName = DscResourceNameParameterSet)] - [Parameter(Mandatory = true, ParameterSetName = TagParameterSet)] [ValidateNotNull] public string[] Tag { get; set; } @@ -131,7 +128,7 @@ class FindPSResource : PSCmdlet #endregion - #region Methods + #region Method overrides protected override void BeginProcessing() { @@ -146,40 +143,10 @@ protected override void StopProcessing() protected override void ProcessRecord() { - Name = Utils.FilterOutWildcardNames(Name, out string[] errorMsgs); - - foreach (string error in errorMsgs) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); - } - - if (Name.Length == 0) - { - return; - } - switch (ParameterSetName) { case ResourceNameParameterSet: - FindHelper findHelper = new FindHelper(_cancellationToken, this); - List foundPackages = new List(); - - foreach (PSResourceInfo package in findHelper.FindByResourceName(Name, Type, Version, Prerelease, Tag, Repository, Credential, IncludeDependencies)) - { - foundPackages.Add(package); - } - - foreach (var uniquePackageVersion in foundPackages.GroupBy( - m => new {m.Name, m.Version}).Select( - group => group.First()).ToList()) - { - WriteObject(uniquePackageVersion); - } - + ProcessResourceNameParameterSet(); break; case CommandNameParameterSet: @@ -198,25 +165,75 @@ protected override void ProcessRecord() this)); break; - case TagParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("DscResourceNameParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "TagParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); + default: + Dbg.Assert(false, "Invalid parameter set"); break; + } + } - case TypeParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("TypeParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "TypeParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, + #endregion + + #region Private methods + + 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))) + { + ThrowTerminatingError( + new ErrorRecord( + new PSNotImplementedException("Search by Tag or Type parameter is not yet implemented."), + "TagTypeSearchNotYetImplemented", + ErrorCategory.NotImplemented, + this)); + } + + ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException("Name parameter must be provided."), + "NameParameterNotProvided", + ErrorCategory.InvalidOperation, this)); - break; + } + + Name = Utils.FilterOutWildcardNames(Name, out string[] errorMsgs); + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } - default: - Dbg.Assert(false, "Invalid parameter set"); - break; + if (Name.Length == 0) + { + return; + } + + FindHelper findHelper = new FindHelper(_cancellationToken, this); + List foundPackages = new List(); + + foreach (PSResourceInfo package in findHelper.FindByResourceName( + Name, + Type, + Version, + Prerelease, + Tag, + Repository, + Credential, + IncludeDependencies)) + { + foundPackages.Add(package); + } + + foreach (var uniquePackageVersion in foundPackages.GroupBy( + m => new {m.Name, m.Version}).Select( + group => group.First()).ToList()) + { + WriteObject(uniquePackageVersion); } } From 1e3d7332209a036cf283b74ddaceba56278e4bfa Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 29 Jun 2021 14:32:49 -0700 Subject: [PATCH 033/276] Fix PSResourceInfo property string types to not be null (#402) * Fix exported PSResourceInfo data to use empty strings rather than null values * Fix xml file write to not write null value strings --- src/code/PSResourceInfo.cs | 59 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index 286627d73..f425d3a61 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -153,7 +153,6 @@ private string[] GetHashTableItem( #endregion - #region Dependency public sealed class Dependency @@ -290,45 +289,43 @@ public static bool TryRead( System.IO.File.ReadAllText( filePath)); - var additionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo); Version version = GetVersionInfo(psObjectInfo, additionalMetadata, out string prereleaseLabel); psGetInfo = new PSResourceInfo { AdditionalMetadata = additionalMetadata, - Author = GetProperty(nameof(PSResourceInfo.Author), psObjectInfo), - CompanyName = GetProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), - Copyright = GetProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), + Author = GetStringProperty(nameof(PSResourceInfo.Author), psObjectInfo), + CompanyName = GetStringProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), + Copyright = GetStringProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), Dependencies = GetDependencies(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), - Description = GetProperty(nameof(PSResourceInfo.Description), psObjectInfo), + Description = GetStringProperty(nameof(PSResourceInfo.Description), psObjectInfo), IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), - InstalledLocation = GetProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), + InstalledLocation = GetStringProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), IsPrerelease = GetProperty(nameof(PSResourceInfo.IsPrerelease), psObjectInfo), LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), - Name = GetProperty(nameof(PSResourceInfo.Name), psObjectInfo), - PackageManagementProvider = GetProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), - PowerShellGetFormatVersion = GetProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), + Name = GetStringProperty(nameof(PSResourceInfo.Name), psObjectInfo), + PackageManagementProvider = GetStringProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), + PowerShellGetFormatVersion = GetStringProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), PrereleaseLabel = prereleaseLabel, ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), - ReleaseNotes = GetProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), - Repository = GetProperty(nameof(PSResourceInfo.Repository), psObjectInfo), - RepositorySourceLocation = GetProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), + ReleaseNotes = GetStringProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), + Repository = GetStringProperty(nameof(PSResourceInfo.Repository), psObjectInfo), + RepositorySourceLocation = GetStringProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), // try to get the value of PSResourceInfo.Type property, if the value is null use ResourceType.Module as value // this value will be used in Enum.TryParse. If Enum.TryParse returns false, use ResourceType.Module to set Type instead. Type = Enum.TryParse( GetProperty(nameof(PSResourceInfo.Type), psObjectInfo) ?? nameof(ResourceType.Module), - out ResourceType currentReadType) - ? currentReadType : ResourceType.Module, + out ResourceType currentReadType) + ? currentReadType : ResourceType.Module, UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), Version = version }; - return true; } catch(Exception ex) @@ -342,6 +339,13 @@ public static bool TryRead( } } + private static string GetStringProperty( + string name, + PSObject psObjectInfo) + { + return GetProperty(name, psObjectInfo) ?? string.Empty; + } + private static Version GetVersionInfo( PSObject psObjectInfo, Dictionary additionalMetadata, @@ -765,7 +769,6 @@ private static Version ParseMetadataVersion(IPackageSearchMetadata pkg) #endregion - #region Private methods private PSObject ConvertToCustomObject() @@ -777,13 +780,13 @@ private PSObject ConvertToCustomObject() } var psObject = new PSObject(); - psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); + psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(Version), ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel))); psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); - psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); - psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); - psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); - psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); + psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description ?? string.Empty)); + psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author ?? string.Empty)); + psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName ?? string.Empty)); + psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); @@ -792,14 +795,14 @@ private PSObject ConvertToCustomObject() psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); - psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); - psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); + psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion ?? string.Empty)); + psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); - psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); - psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); - psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); + psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation ?? string.Empty)); + psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository ?? string.Empty)); + psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation ?? string.Empty)); return psObject; } From 001f032614fcd1756bc029c2c89d70492e508698 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 30 Jun 2021 15:49:00 -0400 Subject: [PATCH 034/276] Get helper null fix (#403) --- src/code/GetHelper.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index faf50bd95..6c16628d7 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -35,7 +35,11 @@ public IEnumerable ProcessGetParams(string[] name, VersionRange foreach (string pkgPath in FilterPkgPathsByVersion(versionRange, filteredPathsToSearch)) { - yield return OutputPackageObject(pkgPath, _scriptDictionary); + PSResourceInfo pkg = OutputPackageObject(pkgPath, _scriptDictionary); + if (pkg != null) + { + yield return pkg; + } } } @@ -174,7 +178,7 @@ public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary Date: Wed, 30 Jun 2021 16:00:12 -0700 Subject: [PATCH 035/276] Fix resource name and path resolution (#404) --- src/code/GetHelper.cs | 51 +++++++++++++++++++++++------- src/code/GetInstalledPSResource.cs | 47 ++++++++++++++++----------- src/code/UninstallPSResource.cs | 7 +--- 3 files changed, 68 insertions(+), 37 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 6c16628d7..58a07ffbf 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -18,22 +18,33 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// internal class GetHelper { - private CancellationToken _cancellationToken; + #region Members + private readonly PSCmdlet _cmdletPassedIn; - private Dictionary _scriptDictionary; + private readonly Dictionary _scriptDictionary; + + #endregion + + #region Constructors - public GetHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) + public GetHelper(PSCmdlet cmdletPassedIn) { - _cancellationToken = cancellationToken; _cmdletPassedIn = cmdletPassedIn; _scriptDictionary = new Dictionary(); } - public IEnumerable ProcessGetParams(string[] name, VersionRange versionRange, List pathsToSearch) + #endregion + + #region Public methods + + public IEnumerable FilterPkgPaths( + string[] name, + VersionRange versionRange, + List pathsToSearch) { - List filteredPathsToSearch = FilterPkgPathsByName(name, pathsToSearch); + List pgkPathsByName = FilterPkgPathsByName(name, pathsToSearch); - foreach (string pkgPath in FilterPkgPathsByVersion(versionRange, filteredPathsToSearch)) + foreach (string pkgPath in FilterPkgPathsByVersion(versionRange, pgkPathsByName)) { PSResourceInfo pkg = OutputPackageObject(pkgPath, _scriptDictionary); if (pkg != null) @@ -58,11 +69,9 @@ public List FilterPkgPathsByName(string[] names, List dirsToSear { WildcardPattern nameWildCardPattern = new WildcardPattern(name, WildcardOptions.IgnoreCase); - // ./Modules/Test-Module - // ./Scripts/Test-Script.ps1 wildCardDirsToSearch.AddRange(dirsToSearch.FindAll( - p => nameWildCardPattern.IsMatch( - System.IO.Path.GetFileNameWithoutExtension((new DirectoryInfo(p).Name))))); + path => nameWildCardPattern.IsMatch( + GetResourceNameFromPath(path)))); } _cmdletPassedIn.WriteDebug(wildCardDirsToSearch.Any().ToString()); @@ -171,7 +180,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // Create package object for each found resource directory public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary scriptDictionary) { - string xmlFilePath = string.Empty; + string xmlFilePath; var parentDir = new DirectoryInfo(pkgPath).Parent; // find package name @@ -208,5 +217,23 @@ public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary - [Cmdlet(VerbsCommon.Get, "InstalledPSResource", HelpUri = "")] - public sealed - class GetInstalledPSResource : PSCmdlet + [Cmdlet(VerbsCommon.Get, "InstalledPSResource")] + public sealed class GetInstalledPSResource : PSCmdlet { + #region Members + + private VersionRange _versionRange; + private List _pathsToSearch; + + #endregion + #region Parameters /// @@ -43,19 +49,11 @@ class GetInstalledPSResource : PSCmdlet #endregion - private CancellationTokenSource _source; - private CancellationToken _cancellationToken; - private VersionRange _versionRange; - List _pathsToSearch; - #region Methods protected override void BeginProcessing() { - _source = new CancellationTokenSource(); - _cancellationToken = _source.Token; - - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // Validate that if a -Version param is passed in that it can be parsed into a NuGet version range. // an exact version will be formatted into a version range. if (Version == null) { @@ -69,11 +67,25 @@ protected override void BeginProcessing() ThrowTerminatingError(IncorrectVersionFormat); } + // Determine paths to search. + _pathsToSearch = new List(); if (Path != null) { - this.WriteDebug(string.Format("Provided path is: '{0}'", Path)); + WriteDebug(string.Format("Provided path is: '{0}'", Path)); + + var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(Path); + if (resolvedPaths.Count != 1) + { + ThrowTerminatingError( + new ErrorRecord( + new PSArgumentException("Error: Could not resolve provided Path argument into a single path."), + "ErrorInvalidPathArgument", + ErrorCategory.InvalidArgument, + this)); + } - var resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path).ToString(); + var resolvedPath = resolvedPaths[0].Path; + WriteDebug(string.Format("Provided resolved path is '{0}'", resolvedPath)); try { @@ -115,13 +127,10 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - WriteDebug("Entering GetInstalledPSResource"); - GetHelper getHelper = new GetHelper(cancellationToken, this); - foreach (PSResourceInfo pkg in getHelper.ProcessGetParams(Name, _versionRange, _pathsToSearch)) + GetHelper getHelper = new GetHelper(this); + foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(Name, _versionRange, _pathsToSearch)) { WriteObject(pkg); } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index aff8f16c6..8e8b1fee9 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -50,8 +50,6 @@ public sealed class UninstallPSResource : PSCmdlet private const string NameParameterSet = "NameParameterSet"; private const string InputObjectSet = "InputObjectSet"; public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; - private CancellationTokenSource _source; - private CancellationToken _cancellationToken; VersionRange _versionRange; List _pathsToSearch = new List(); #endregion @@ -59,9 +57,6 @@ public sealed class UninstallPSResource : PSCmdlet #region Methods protected override void BeginProcessing() { - _source = new CancellationTokenSource(); - _cancellationToken = _source.Token; - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. // an exact version will be formatted into a version range. if (ParameterSetName.Equals("NameParameterSet") && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) @@ -128,7 +123,7 @@ private bool UninstallPkgHelper() { var successfullyUninstalled = false; - GetHelper getHelper = new GetHelper(_cancellationToken, this); + GetHelper getHelper = new GetHelper(this); List dirsToDelete = getHelper.FilterPkgPathsByName(Name, _pathsToSearch); // Checking if module or script From 265a9a8000761219044f00265677ddb12785c6e6 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 1 Jul 2021 14:44:43 -0700 Subject: [PATCH 036/276] Fix codeql to work on new master branch (#405) --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d4a0a1110..d261f7cdb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,10 +7,10 @@ name: "CodeQL" on: push: - branches: [development] + branches: [master] pull_request: # The branches below must be a subset of the branches above - branches: [development] + branches: [master] #schedule: # - cron: '0 7 * * 0' From 34f6c479964c546e24596f29045cfe99ea821d0c Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 9 Jul 2021 13:55:58 -0700 Subject: [PATCH 037/276] Update release ci (#410) * Update release ci * Remove batch directive --- .ci/ci_release.yml | 4 +-- .ci/release.yml | 55 +++++++++++++-------------------- src/code/UninstallPSResource.cs | 2 ++ 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index dec8f20c5..31fc6f949 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -1,7 +1,7 @@ name: $(BuildDefinitionName)-$(date:yyMM).$(date:dd)$(rev:rrr) trigger: # Batch merge builds together while a merge build is running - batch: true + batch: false branches: include: - master @@ -339,7 +339,7 @@ stages: # imageName: macOS-10.14 - stage: Release - displayName: Release Package + displayName: Publish Package to PSGallery condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), eq(variables['Publish'], 'True')) jobs: - template: release.yml diff --git a/.ci/release.yml b/.ci/release.yml index cd925a477..19d7c5a35 100644 --- a/.ci/release.yml +++ b/.ci/release.yml @@ -1,47 +1,36 @@ parameters: jobName: release - imageName: windows-latest - displayName: 'Release PowerShellGet to NuGet' + displayName: 'Release PowerShellGet to PSGallery' jobs: - job: ${{ parameters.jobName }} pool: - vmImage: ${{ parameters.imageName }} + name: 1ES + demands: + - ImageOverride -equals MMS2019 displayName: ${{ parameters.displayName }} steps: - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet 5.6.0' - inputs: - checkLatest: false - version: 5.6.0 - - - task: DownloadBuildArtifacts@0 + + - task: DownloadPipelineArtifact@2 displayName: 'Download PowerShellGet module artifacts' inputs: - buildType: current - downloadType: specific - artifactName: '**/*.nupkg' - downloadPath: '$(System.ArtifactsDirectory)' + artifact: nugetpkg + patterns: '**/*.nupkg' + downloadPath: '$(Pipeline.Workspace)/nuget' - powershell: | - Get-ChildItem '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' -ErrorAction SilentlyContinue - # Get-ChildItem '$(System.ArtifactsDirectory)' -Recurse - displayName: 'Capture PowerShellGet module NuGet package' + $package = (Get-ChildItem '$(Pipeline.Workspace)/nuget/PowerShellGet.*.nupkg').FullName + $package + $vstsCommandString = "vso[task.setvariable variable=NugetPkgPath]${package}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: 'Capture PowerShellGet module NuGet package path and set environment variable' - # TODO: Need to create NuGet service connection - #- task: NuGetCommand@2 - # displayName: 'Push Microsoft.PowerShell.Store module artifacts to AzArtifactsFeed' - # inputs: - # command: push - # packagesToPush: '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' - # nuGetFeedType: external - # publishFeedCredentials: AzArtifactFeed - - #- task: NuGetCommand@2 - # displayName: 'Push Microsoft.PowerShell.Store module artifacts to PSGallery feed' - # inputs: - # command: push - # packagesToPush: '$(System.ArtifactsDirectory)/nupkg/PowerShellGet.*.nupkg' - # nuGetFeedType: external - # publishFeedCredentials: PHPowerShellGalleryFeed + - task: NuGetCommand@2 + displayName: 'Push Microsoft.PowerShell.Store module artifacts to PSGallery feed' + inputs: + command: push + packagesToPush: '$(NugetPkgPath)' + nuGetFeedType: external + publishFeedCredentials: PSGalleryPush diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 8e8b1fee9..487e14f05 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; From a84a04087cae601a999ae1d9fd7eb74900f626d9 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 13 Jul 2021 10:05:01 -0700 Subject: [PATCH 038/276] Fix release stage artifact name (#412) --- .ci/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/release.yml b/.ci/release.yml index 19d7c5a35..bc808d402 100644 --- a/.ci/release.yml +++ b/.ci/release.yml @@ -15,7 +15,7 @@ jobs: - task: DownloadPipelineArtifact@2 displayName: 'Download PowerShellGet module artifacts' inputs: - artifact: nugetpkg + artifact: nupkg patterns: '**/*.nupkg' downloadPath: '$(Pipeline.Workspace)/nuget' From a1337b80f347391c92f8901f90f1fe9338d3105a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 14 Jul 2021 17:32:29 -0400 Subject: [PATCH 039/276] Prerelease bug (#413) * parse prereleaseLabel and IsPrerelease properly and read/write this info to XML file * revert accidental edits made * make changes individually so dependency changes from Install PR don't get added * use PSREsourceInfo changes with dependency changes from Install PR * add newline * remove ScopeType enum and add in Install PR * update tests to get AdditionalMetadata IsPrerelease NormalizedVersion --- src/code/GetHelper.cs | 9 +- src/code/PSResourceInfo.cs | 203 +++++++++++++++++++++++-------------- src/code/Utils.cs | 35 +++++++ test/PSGetModuleInfo.xml | 7 +- test/PSGetTestUtils.psm1 | 9 +- 5 files changed, 176 insertions(+), 87 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 58a07ffbf..534862ce2 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -112,7 +112,10 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // if no version is specified, just delete the latest version Array.Sort(versionsDirs); - yield return (versionsDirs[versionsDirs.Length - 1]); + if (versionsDirs.Length > 0) + { + yield return versionsDirs[versionsDirs.Length - 1]; + } continue; } @@ -219,7 +222,7 @@ public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary 1 (because string contained '-' so couldn't be 0) + // versionString: "1.2.0-alpha1" pkgVersion = versionStringParsed[0]; prereleaseLabel = versionStringParsed[1]; } } + // at this point, version is normalized (i.e either "1.2.0" (if part of prerelease) or "1.2.0.0" otherwise) + // parse the pkgVersion parsed out above into a System.Version object if (!Version.TryParse(pkgVersion, out Version parsedVersion)) { prereleaseLabel = String.Empty; @@ -384,6 +392,8 @@ private static Version GetVersionInfo( } } + // version could not be parsed as string, it was written to XML file as a System.Version object + // V3 code briefly did so, I believe so we provide support for it prereleaseLabel = String.Empty; return GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); } @@ -414,6 +424,7 @@ public static bool TryConvert( Dependencies = ParseMetadataDependencies(metadataToParse), Description = ParseMetadataDescription(metadataToParse), IconUri = ParseMetadataIconUri(metadataToParse), + IsPrerelease = ParseMetadataIsPrerelease(metadataToParse), LicenseUri = ParseMetadataLicenseUri(metadataToParse), Name = ParseMetadataName(metadataToParse), PrereleaseLabel = ParsePrerelease(metadataToParse), @@ -527,82 +538,98 @@ private static Dependency[] GetDependencies(ArrayList dependencyInfos) foreach(PSObject dependencyObj in dependencyInfos) { - if (!(dependencyObj.BaseObject is Hashtable dependencyInfo)) + // The dependency object can be a string or a hashtable + // eg: + // RequiredModules = @('PSGetTestDependency1') + // RequiredModules = @(@{ModuleName='PackageManagement';ModuleVersion='1.0.0.1'}) + if (dependencyObj.BaseObject is Hashtable dependencyInfo) { - Dbg.Assert(false, "Dependencies BaseObject must be a Hashtable"); - continue; - } - - if (!dependencyInfo.ContainsKey("Name")) - { - Dbg.Assert(false, "Derived dependencies Hashtable must contain a Name key"); - continue; - } - - string dependencyName = (string) dependencyInfo["Name"]; - if (String.IsNullOrEmpty(dependencyName)) - { - Dbg.Assert(false, "Dependency Name must not be null or empty"); - continue; - } - - if (dependencyInfo.ContainsKey("RequiredVersion")) - { - if (!Utils.TryParseVersionOrVersionRange((string) dependencyInfo["RequiredVersion"], out VersionRange dependencyVersion)) + if (!dependencyInfo.ContainsKey("Name")) { - dependencyVersion = VersionRange.All; + Dbg.Assert(false, "Derived dependencies Hashtable must contain a Name key"); + continue; } - dependenciesFound.Add(new Dependency(dependencyName, dependencyVersion)); - continue; - } - - if (dependencyInfo.ContainsKey("MinimumVersion") || dependencyInfo.ContainsKey("MaximumVersion")) - { - NuGetVersion minimumVersion = null; - NuGetVersion maximumVersion = null; - bool includeMin = false; - bool includeMax = false; - - if (dependencyInfo.ContainsKey("MinimumVersion") && - !NuGetVersion.TryParse((string) dependencyInfo["MinimumVersion"], out minimumVersion)) + string dependencyName = (string)dependencyInfo["Name"]; + if (String.IsNullOrEmpty(dependencyName)) { - VersionRange dependencyAll = VersionRange.All; - dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + Dbg.Assert(false, "Dependency Name must not be null or empty"); continue; } - if (dependencyInfo.ContainsKey("MaximumVersion") && - !NuGetVersion.TryParse((string) dependencyInfo["MaximumVersion"], out maximumVersion)) + if (dependencyInfo.ContainsKey("RequiredVersion")) { - VersionRange dependencyAll = VersionRange.All; - dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + if (!Utils.TryParseVersionOrVersionRange((string)dependencyInfo["RequiredVersion"], out VersionRange dependencyVersion)) + { + dependencyVersion = VersionRange.All; + } + + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersion)); continue; } - if (minimumVersion != null) + if (dependencyInfo.ContainsKey("MinimumVersion") || dependencyInfo.ContainsKey("MaximumVersion")) { - includeMin = true; + NuGetVersion minimumVersion = null; + NuGetVersion maximumVersion = null; + bool includeMin = false; + bool includeMax = false; + + if (dependencyInfo.ContainsKey("MinimumVersion") && + !NuGetVersion.TryParse((string)dependencyInfo["MinimumVersion"], out minimumVersion)) + { + VersionRange dependencyAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + continue; + } + + if (dependencyInfo.ContainsKey("MaximumVersion") && + !NuGetVersion.TryParse((string)dependencyInfo["MaximumVersion"], out maximumVersion)) + { + VersionRange dependencyAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + continue; + } + + if (minimumVersion != null) + { + includeMin = true; + } + + if (maximumVersion != null) + { + includeMax = true; + } + + VersionRange dependencyVersionRange = new VersionRange( + minVersion: minimumVersion, + includeMinVersion: includeMin, + maxVersion: maximumVersion, + includeMaxVersion: includeMax); + + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRange)); + continue; } - if (maximumVersion != null) + // neither Required, Minimum or Maximum Version provided + VersionRange dependencyVersionRangeAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRangeAll)); + } + else if (dependencyObj.Properties["Name"] != null) + { + string name = dependencyObj.Properties["Name"].Value.ToString(); + + string version = string.Empty; + VersionRange versionRange = VersionRange.All; + + if (dependencyObj.Properties["VersionRange"] != null) { - includeMax = true; + version = dependencyObj.Properties["VersionRange"].Value.ToString(); + VersionRange.TryParse(version, out versionRange); } - VersionRange dependencyVersionRange = new VersionRange( - minVersion: minimumVersion, - includeMinVersion: includeMin, - maxVersion: maximumVersion, - includeMaxVersion: includeMax); - - dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRange)); - continue; + dependenciesFound.Add(new Dependency(name, versionRange)); } - - // neither Required, Minimum or Maximum Version provided - VersionRange dependencyVersionRangeAll = VersionRange.All; - dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRangeAll)); } return dependenciesFound.ToArray(); @@ -610,22 +637,7 @@ private static Dependency[] GetDependencies(ArrayList dependencyInfos) private static string ConcatenateVersionWithPrerelease(string version, string prerelease) { - // if no prerelease, just version suffices - if (String.IsNullOrEmpty(prerelease)) - { - return version; - } - - int numVersionDigits = version.Split('.').Count(); - if (numVersionDigits == 3) - { - // 0.5.3 -> version string , preview4 -> prerelease string , return: 5.3.0-preview4 - return version + "-" + prerelease; - } - - - // number of digits not equivalent to 3 was not supported in V2 - return version; + return Utils.GetNormalizedVersionString(version, prerelease); } @@ -671,6 +683,11 @@ private static Uri ParseMetadataIconUri(IPackageSearchMetadata pkg) return pkg.IconUrl; } + private static bool ParseMetadataIsPrerelease(IPackageSearchMetadata pkg) + { + return pkg.Identity?.Version?.IsPrerelease ?? false; + } + private static Uri ParseMetadataLicenseUri(IPackageSearchMetadata pkg) { return pkg.LicenseUrl; @@ -683,9 +700,9 @@ private static string ParseMetadataName(IPackageSearchMetadata pkg) private static string ParsePrerelease(IPackageSearchMetadata pkg) { - return pkg.Identity.Version.ReleaseLabels.Count() == 0 ? - String.Empty : - pkg.Identity.Version.ReleaseLabels.FirstOrDefault(); + return pkg.Identity.Version.ReleaseLabels.Count() > 0 ? + pkg.Identity.Version.ReleaseLabels.FirstOrDefault() : + String.Empty; } private static Uri ParseMetadataProjectUri(IPackageSearchMetadata pkg) @@ -773,7 +790,36 @@ private static Version ParseMetadataVersion(IPackageSearchMetadata pkg) private PSObject ConvertToCustomObject() { + // 1.0.0-alpha1 + // 1.0.0.0 + string NormalizedVersion = IsPrerelease ? ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel) : Version.ToString(); + var additionalMetadata = new PSObject(); + + if (AdditionalMetadata == null) + { + AdditionalMetadata = new Dictionary(); + } + + if (!AdditionalMetadata.ContainsKey(nameof(IsPrerelease))) + { + AdditionalMetadata.Add(nameof(IsPrerelease), IsPrerelease.ToString()); + } + else + { + AdditionalMetadata[nameof(IsPrerelease)] = IsPrerelease.ToString(); + } + + // This is added for V2, V3 does not need it. + if (!AdditionalMetadata.ContainsKey(nameof(NormalizedVersion))) + { + AdditionalMetadata.Add(nameof(NormalizedVersion), NormalizedVersion); + } + else + { + AdditionalMetadata[nameof(NormalizedVersion)] = NormalizedVersion; + } + foreach (var item in AdditionalMetadata) { additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); @@ -781,7 +827,7 @@ private PSObject ConvertToCustomObject() var psObject = new PSObject(); psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(Version), ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel))); + psObject.Properties.Add(new PSNoteProperty(nameof(Version), NormalizedVersion)); psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author ?? string.Empty)); @@ -789,12 +835,13 @@ private PSObject ConvertToCustomObject() psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(IsPrerelease), IsPrerelease)); psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); - psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); + psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes != null ? Includes.ConvertToHashtable() : null)); psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes ?? string.Empty)); psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 6e7dc45c1..bdd50b9c4 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -32,6 +32,41 @@ public static void WriteVerboseOnCmdlet( catch { } } + public static string GetNormalizedVersionString( + string versionString, + string prerelease + ) + { + // versionString may be like 1.2.0.0 or 1.2.0 + // prerelease may be null or "alpha1" + // possible passed in examples: + // versionString: "1.2.0" prerelease: "alpha1" + // versionString: "1.2.0" prerelease: "" <- doubtful though + // versionString: "1.2.0.0" prerelease: "alpha1" + // versionString: "1.2.0.0" prerelease: "" + + if (String.IsNullOrEmpty(prerelease)) + { + return versionString; + } + + int numVersionDigits = versionString.Split('.').Count(); + + if (numVersionDigits == 3) + { + // versionString: "1.2.0" prerelease: "alpha1" + return versionString + "-" + prerelease; + } + + else if (numVersionDigits == 4) + { + // versionString: "1.2.0.0" prerelease: "alpha1" + return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; + } + + return versionString; + } + public static string[] FilterOutWildcardNames( string[] pkgNames, out string[] errorMsgs) diff --git a/test/PSGetModuleInfo.xml b/test/PSGetModuleInfo.xml index 082a4ebac..8f7462319 100644 --- a/test/PSGetModuleInfo.xml +++ b/test/PSGetModuleInfo.xml @@ -7,13 +7,14 @@ Microsoft.PowerShell.SecretManagement - 1.0.0 + 1.1.0-preview2 Module This module provides a convenient way for a user to store and retrieve secrets. The secrets are_x000D__x000A_stored in registered extension vaults. An extension vault can store secrets locally or remotely._x000D__x000A_SecretManagement coordinates access to the secrets through the registered vaults._x000D__x000A__x000D__x000A_Go to GitHub for more information about the module and to submit issues:_x000D__x000A_https://github.com/powershell/SecretManagement Microsoft Corporation Microsoft Corporation (c) Microsoft Corporation. All rights reserved.
2021-03-25T18:08:10-07:00
+ true
2021-03-25T11:12:41.7662015-07:00
@@ -136,9 +137,9 @@ PSModule PSEdition_Core PSCmdlet_Register-SecretVault PSCommand_Register-SecretVault PSCmdlet_Unregister-SecretVault PSCommand_Unregister-SecretVault PSCmdlet_Get-SecretVault PSCommand_Get-SecretVault PSCmdlet_Set-SecretVaultDefault PSCommand_Set-SecretVaultDefault PSCmdlet_Test-SecretVault PSCommand_Test-SecretVault PSCmdlet_Set-Secret PSCommand_Set-Secret PSCmdlet_Set-SecretInfo PSCommand_Set-SecretInfo PSCmdlet_Get-Secret PSCommand_Get-Secret PSCmdlet_Get-SecretInfo PSCommand_Get-SecretInfo PSCmdlet_Remove-Secret PSCommand_Remove-Secret PSIncludes_Cmdlet False 2021-03-25T18:08:10Z - 1.0.0 + 1.1.0-preview2 Microsoft Corporation - false + true Module Microsoft.PowerShell.SecretManagement.nuspec|Microsoft.PowerShell.SecretManagement.dll|Microsoft.PowerShell.SecretManagement.format.ps1xml|Microsoft.PowerShell.SecretManagement.psd1|en-US\about_Microsoft.PowerShell.SecretManagement.help.txt|en-US\Microsoft.PowerShell.SecretManagement.dll-Help.xml a5c858f6-4a8e-41f1-b1ee-0ff8f6ad69d3 diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index 47ce9bcca..f3410ffaf 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -502,6 +502,7 @@ $($ReleaseNotes -join "`r`n") Checks that provided PSGetInfo object contents match the expected data from the test information file: PSGetModuleInfo.xml #> + function CheckForExpectedPSGetInfo { param ($psGetInfo) @@ -521,9 +522,9 @@ function CheckForExpectedPSGetInfo $psGetInfo.AdditionalMetadata['tags'] | Should -BeLike 'PSModule PSEdition_Core PSCmdlet_Register-SecretVault*' $psGetInfo.AdditionalMetadata['developmentDependency'] | Should -BeExactly 'False' $psGetInfo.AdditionalMetadata['updated'] | Should -BeExactly '2021-03-25T18:08:10Z' - $psGetInfo.AdditionalMetadata['NormalizedVersion'] | Should -BeExactly '1.0.0' + $psGetInfo.AdditionalMetadata['NormalizedVersion'] | Should -BeExactly '1.1.0-preview2' $psGetInfo.AdditionalMetadata['Authors'] | Should -BeExactly 'Microsoft Corporation' - $psGetInfo.AdditionalMetadata['IsPrerelease'] | Should -BeExactly 'false' + $psGetInfo.AdditionalMetadata['IsPrerelease'] | Should -Be $True $psGetInfo.AdditionalMetadata['ItemType'] | Should -BeExactly 'Module' $psGetInfo.AdditionalMetadata['FileList'] | Should -BeLike 'Microsoft.PowerShell.SecretManagement.nuspec|Microsoft.PowerShell.SecretManagement.dll*' $psGetInfo.AdditionalMetadata['GUID'] | Should -BeExactly 'a5c858f6-4a8e-41f1-b1ee-0ff8f6ad69d3' @@ -536,6 +537,8 @@ function CheckForExpectedPSGetInfo $psGetInfo.Dependencies | Should -HaveCount 0 $psGetInfo.Description | Should -BeLike 'This module provides a convenient way for a user to store*' $psGetInfo.IconUri | Should -BeNullOrEmpty + $psGetInfo.IsPrerelease | Should -Be $True + $psGetInfo.PrereleaseLabel | Should -Be "preview2" $psGetInfo.Includes.Cmdlet | Should -HaveCount 10 $psGetInfo.Includes.Cmdlet[0] | Should -BeExactly 'Register-SecretVault' $psGetInfo.InstalledDate.Year | Should -BeExactly 2021 @@ -552,5 +555,5 @@ function CheckForExpectedPSGetInfo $psGetInfo.Tags | Should -BeExactly @('PSModule', 'PSEdition_Core') $psGetInfo.Type | Should -BeExactly 'Module' $psGetInfo.UpdatedDate.Year | Should -BeExactly 1 - $psGetInfo.Version.ToString() | Should -BeExactly '1.0.0' + $psGetInfo.Version | Should -Be "1.1.0" } From 4f5d007414972218a4c2197f0794245770d6b72c Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 15 Jul 2021 08:21:47 -0700 Subject: [PATCH 040/276] Install refactor (#408) --- src/PowerShellGet.psd1 | 4 +- src/code/GetHelper.cs | 1 - src/code/InstallHelper.cs | 648 +++++++++++++++++++++++++++++++ src/code/InstallPSResource.cs | 170 ++++++++ src/code/PSRepositoryInfo.cs | 1 - src/code/PSResourceInfo.cs | 6 + src/code/PowerShellGet.csproj | 6 +- src/code/SavePSResource.cs | 181 +++++++++ src/code/Utils.cs | 641 +++++++++++++++++------------- test/InstallPSResource.Tests.ps1 | 233 +++++++++++ test/PSGetTestUtils.psm1 | 7 + test/SavePSResource.Tests.ps1 | 203 ++++++++++ 12 files changed, 1818 insertions(+), 283 deletions(-) create mode 100644 src/code/InstallHelper.cs create mode 100644 src/code/InstallPSResource.cs create mode 100644 src/code/SavePSResource.cs create mode 100644 test/InstallPSResource.Tests.ps1 create mode 100644 test/SavePSResource.Tests.ps1 diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 0ce94ad9a..ae027fb76 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -14,9 +14,9 @@ 'Find-PSResource', 'Get-InstalledPSResource', 'Get-PSResourceRepository', - # 'Install-PSResource', + 'Install-PSResource', 'Register-PSResourceRepository', - # 'Save-PSResource', + 'Save-PSResource', 'Set-PSResourceRepository', 'Publish-PSResource', 'Uninstall-PSResource', diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 534862ce2..f9c8c0f87 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -73,7 +73,6 @@ public List FilterPkgPathsByName(string[] names, List dirsToSear path => nameWildCardPattern.IsMatch( GetResourceNameFromPath(path)))); } - _cmdletPassedIn.WriteDebug(wildCardDirsToSearch.Any().ToString()); return wildCardDirsToSearch; } diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs new file mode 100644 index 000000000..8874ef180 --- /dev/null +++ b/src/code/InstallHelper.cs @@ -0,0 +1,648 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading; +using MoreLinq.Extensions; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.Packaging.PackageExtraction; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Install helper class + /// + internal class InstallHelper : PSCmdlet + { + private CancellationToken _cancellationToken; + private readonly bool _updatePkg; + private readonly bool _savePkg; + private readonly PSCmdlet _cmdletPassedIn; + List _pathsToInstallPkg; + VersionRange _versionRange; + bool _prerelease; + bool _acceptLicense; + bool _quiet; + bool _reinstall; + bool _force; + bool _trustRepository; + bool _noClobber; + PSCredential _credential; + string _specifiedPath; + bool _asNupkg; + bool _includeXML; + + public InstallHelper(bool updatePkg, bool savePkg, CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) + { + this._updatePkg = updatePkg; + this._savePkg = savePkg; + this._cancellationToken = cancellationToken; + this._cmdletPassedIn = cmdletPassedIn; + } + + public void InstallPackages( + string[] names, + VersionRange versionRange, + bool prerelease, + string[] repository, + bool acceptLicense, + bool quiet, + bool reinstall, + bool force, + bool trustRepository, + bool noClobber, + PSCredential credential, + string requiredResourceFile, + string requiredResourceJson, + Hashtable requiredResourceHash, + string specifiedPath, + bool asNupkg, + bool includeXML, + List pathsToInstallPkg) + { + _cmdletPassedIn.WriteDebug(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", + string.Join(",", names), + (_versionRange != null ? _versionRange.OriginalString : string.Empty), + prerelease.ToString(), + repository != null ? string.Join(",", repository) : string.Empty, + acceptLicense.ToString(), + quiet.ToString(), + reinstall.ToString(), + trustRepository.ToString(), + noClobber.ToString())); + + _versionRange = versionRange; + _prerelease = prerelease; + _acceptLicense = acceptLicense; + _quiet = quiet; + _reinstall = reinstall; + _force = force; + _trustRepository = trustRepository; + _noClobber = noClobber; + _credential = credential; + _specifiedPath = specifiedPath; + _asNupkg = asNupkg; + _includeXML = includeXML; + _pathsToInstallPkg = pathsToInstallPkg; + + // Go through the repositories and see which is the first repository to have the pkg version available + ProcessRepositories(names, repository, _trustRepository, _credential); + } + + // This method calls iterates through repositories (by priority order) to search for the pkgs to install + public void ProcessRepositories(string[] packageNames, string[] repository, bool trustRepository, PSCredential credential) + { + var listOfRepositories = RepositorySettings.Read(repository, out string[] _); + List packagesToInstall = packageNames.ToList(); + var yesToAll = false; + var noToAll = false; + var repositoryIsNotTrusted = "Untrusted repository"; + var queryInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; + + foreach (var repo in listOfRepositories) + { + // If no more packages to install, then return + if (!packagesToInstall.Any()) return; + + var sourceTrusted = false; + string repoName = repo.Name; + _cmdletPassedIn.WriteDebug(string.Format("Attempting to search for packages in '{0}'", repoName)); + + // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true + // OR the user issues trust interactively via console. + if (repo.Trusted == false && !trustRepository && !_force) + { + _cmdletPassedIn.WriteDebug("Checking if untrusted repository should be used"); + + if (!(yesToAll || noToAll)) + { + // Prompt for installation of package from untrusted repository + var message = string.Format(CultureInfo.InvariantCulture, queryInstallUntrustedPackage, repoName); + sourceTrusted = _cmdletPassedIn.ShouldContinue(message, repositoryIsNotTrusted, true, ref yesToAll, ref noToAll); + } + } + else + { + sourceTrusted = true; + } + + if (sourceTrusted || yesToAll) + { + _cmdletPassedIn.WriteDebug("Untrusted repository accepted as trusted source."); + + // If it can't find the pkg in one repository, it'll look for it in the next repo in the list + var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); + + + var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); + // Finds parent packages and dependencies + IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( + name: packageNames, + type: ResourceType.None, + version: _versionRange != null ? _versionRange.OriginalString : null, + prerelease: _prerelease, + tag: null, + repository: new string[] { repoName }, + credential: credential, + includeDependencies: true); + + foreach (PSResourceInfo a in pkgsFromRepoToInstall) + { + var test = a; + _cmdletPassedIn.WriteVerbose(a.Version.ToString()); + } + + // Select the first package from each name group, which is guaranteed to be the latest version. + // We should only have one version returned for each package name + // e.g.: + // PackageA (version 1.0) + // PackageB (version 2.0) + // PackageC (version 1.0) + pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( + m => new { m.Name }).Select( + group => group.First()).ToList(); + + if (!pkgsFromRepoToInstall.Any()) + { + _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); + // Check in the next repository + continue; + } + + // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) + if (!_reinstall) + { + // Removes all of the names that are already installed from the list of names to search for + pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); + } + + if (!pkgsFromRepoToInstall.Any()) + { + continue; + } + + List pkgsInstalled = InstallPackage(pkgsFromRepoToInstall, repoName, repo.Url.AbsoluteUri, credential, isLocalRepo); + + foreach (string name in pkgsInstalled) + { + packagesToInstall.Remove(name); + } + } + } + } + + // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install + public IEnumerable FilterByInstalledPkgs(IEnumerable packagesToInstall) + { + List pkgNames = new List(); + foreach (var pkg in packagesToInstall) + { + pkgNames.Add(pkg.Name); + } + + List _pathsToSearch = new List(); + GetHelper getHelper = new GetHelper(_cmdletPassedIn); + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // e.g.: + // ./InstallPackagePath1/PackageA + // ./InstallPackagePath1/PackageB + // ./InstallPackagePath2/PackageC + // ./InstallPackagePath3/PackageD + foreach (var path in _pathsToInstallPkg) + { + _pathsToSearch.AddRange(Directory.GetDirectories(path)); + } + + IEnumerable pkgsAlreadyInstalled = getHelper.FilterPkgPaths(pkgNames.ToArray(), _versionRange, _pathsToSearch); + + // If any pkg versions are already installed, write a message saying it is already installed and continue processing other pkg names + if (pkgsAlreadyInstalled.Any()) + { + foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) + { + _cmdletPassedIn.WriteWarning(string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", pkg.Name, pkg.Version)); + + // remove this pkg from the list of pkg names install + packagesToInstall.ToList().Remove(pkg); + } + } + + return packagesToInstall; + } + + private List InstallPackage(IEnumerable pkgsToInstall, string repoName, string repoUrl, PSCredential credential, bool isLocalRepo) + { + List pkgsSuccessfullyInstalled = new List(); + foreach (PSResourceInfo p in pkgsToInstall) + { + var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + try + { + // Create a temp directory to install to + var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly + // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator + // with a mask (bitwise complement of desired attributes combination). + // TODO: check the attributes and if it's read only then set it + // attribute may be inherited from the parent + // TODO: are there Linux accommodations we need to consider here? + dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; + + _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", p.Name)); + + // TODO: add progress bar here + + // Create PackageIdentity in order to download + string createFullVersion = p.Version.ToString(); + if (p.IsPrerelease) + { + createFullVersion = p.Version.ToString() + "-" + p.PrereleaseLabel; + } + + if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) + { + _cmdletPassedIn.WriteDebug(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", p.Name, p.Version.ToString())); + continue; + } + var pkgIdentity = new PackageIdentity(p.Name, pkgVersion); + var cacheContext = new SourceCacheContext(); + + if (isLocalRepo) + { + /* Download from a local repository -- this is slightly different process than from a server */ + var localResource = new FindLocalPackagesResourceV2(repoUrl); + var resource = new LocalDownloadResource(repoUrl, localResource); + + // Actually downloading the .nupkg from a local repo + var result = resource.GetDownloadResourceResultAsync( + identity: pkgIdentity, + downloadContext: new PackageDownloadContext(cacheContext), + globalPackagesFolder: tempInstallPath, + logger: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + + if (_asNupkg) // this is Save functionality + { + DirectoryInfo nupkgPath = new DirectoryInfo(((System.IO.FileStream)result.PackageStream).Name); + File.Copy(nupkgPath.FullName, Path.Combine(tempInstallPath, pkgIdentity.Id + pkgIdentity.Version + ".nupkg")); + + continue; + } + + // Create the package extraction context + PackageExtractionContext packageExtractionContext = new PackageExtractionContext( + packageSaveMode: PackageSaveMode.Nupkg, + xmlDocFileSaveMode: PackageExtractionBehavior.XmlDocFileSaveMode, + clientPolicyContext: null, + logger: NullLogger.Instance); + + // Extracting from .nupkg and placing files into tempInstallPath + result.PackageReader.CopyFiles( + destination: tempInstallPath, + packageFiles: result.PackageReader.GetFiles(), + extractFile: (new PackageFileExtractor(result.PackageReader.GetFiles(), packageExtractionContext.XmlDocFileSaveMode)).ExtractPackageFile, + logger: NullLogger.Instance, + token: _cancellationToken); + result.Dispose(); + } + else + { + /* Download from a non-local repository */ + // Set up NuGet API resource for download + PackageSource source = new PackageSource(repoUrl); + if (credential != null) + { + string password = new NetworkCredential(string.Empty, credential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, credential.UserName, password, true, null); + } + var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); + SourceRepository repository = new SourceRepository(source, provider); + + /* Download from a non-local repository -- ie server */ + var downloadResource = repository.GetResourceAsync().GetAwaiter().GetResult(); + DownloadResourceResult result = null; + try + { + result = downloadResource.GetDownloadResourceResultAsync( + identity: pkgIdentity, + downloadContext: new PackageDownloadContext(cacheContext), + globalPackagesFolder: tempInstallPath, + logger: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + } + catch (Exception e) + { + _cmdletPassedIn.WriteDebug(string.Format("Error attempting download: '{0}'", e.Message)); + } + finally + { + // Need to close the .nupkg + if (result != null) result.Dispose(); + } + } + + _cmdletPassedIn.WriteDebug(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); + + // Prompt if module requires license acceptance (need to read info license acceptance info from the module manifest) + // pkgIdentity.Version.Version gets the version without metadata or release labels. + + + string newVersion = pkgIdentity.Version.ToNormalizedString(); + + // + string normalizedVersionNoPrereleaseLabel = newVersion; + if (pkgIdentity.Version.IsPrerelease) + { + // 2.0.2 + normalizedVersionNoPrereleaseLabel = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); + } + //p.Version = new System.Version(normalizedVersionNoPrereleaseLabel); + + string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); + var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); + string moduleManifestVersion = string.Empty; + var scriptPath = Path.Combine(tempDirNameVersion, (p.Name + ".ps1")); + var isScript = File.Exists(scriptPath) ? true : false; + + if (!isScript) + { + var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); + + var parsedMetadataHashtable = Utils.ParseModuleManifest(moduleManifest, this); + moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; + + // Accept License verification + if (!_savePkg && !CallAcceptLicense(p, moduleManifest, tempInstallPath, newVersion)) + { + continue; + } + } + + // Delete the extra nupkg related files that are not needed and not part of the module/script + DeleteExtraneousFiles(tempInstallPath, pkgIdentity, tempDirNameVersion); + + string installPath; + if (_savePkg) + { + // For save the installation path is what is passed in via -Path + installPath = _pathsToInstallPkg.FirstOrDefault(); + } + else { + // PSModules: + /// ./Modules + /// ./Scripts + /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list + installPath = isScript ? _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)) + : _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)); + } + + if (_includeXML) + { + CreateMetadataXMLFile(tempDirNameVersion, installPath, repoName, p, isScript); + } + + MoveFilesIntoInstallPath(p, isScript, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); + + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}'", p.Name)); + pkgsSuccessfullyInstalled.Add(p.Name); + } + catch (Exception e) + { + _cmdletPassedIn.WriteDebug(string.Format("Unable to successfully install package '{0}': '{1}'", p.Name, e.Message)); + } + finally + { + // Delete the temp directory and all its contents + _cmdletPassedIn.WriteDebug(string.Format("Attempting to delete '{0}'", tempInstallPath)); + if (Directory.Exists(tempInstallPath)) + { + Directory.Delete(tempInstallPath, true); + } + } + } + + return pkgsSuccessfullyInstalled; + } + + private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string tempInstallPath, string newVersion) + { + var requireLicenseAcceptance = false; + var success = true; + + if (File.Exists(moduleManifest)) + { + using (StreamReader sr = new StreamReader(moduleManifest)) + { + var text = sr.ReadToEnd(); + + var pattern = "RequireLicenseAcceptance\\s*=\\s*\\$true"; + var patternToSkip1 = "#\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; + var patternToSkip2 = "\\*\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; + + Regex rgx = new Regex(pattern); + Regex rgxComment1 = new Regex(patternToSkip1); + Regex rgxComment2 = new Regex(patternToSkip2); + if (rgx.IsMatch(text) && !rgxComment1.IsMatch(text) && !rgxComment2.IsMatch(text)) + { + requireLicenseAcceptance = true; + } + } + + // Licesnse agreement processing + if (requireLicenseAcceptance) + { + // If module requires license acceptance and -AcceptLicense is not passed in, display prompt + if (!_acceptLicense) + { + var PkgTempInstallPath = Path.Combine(tempInstallPath, p.Name, newVersion); + var LicenseFilePath = Path.Combine(PkgTempInstallPath, "License.txt"); + + if (!File.Exists(LicenseFilePath)) + { + var exMessage = "License.txt not Found. License.txt must be provided when user license acceptance is required."; + var ex = new ArgumentException(exMessage); + var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); + + _cmdletPassedIn.WriteError(acceptLicenseError); + success = false; + } + + // Otherwise read LicenseFile + string licenseText = System.IO.File.ReadAllText(LicenseFilePath); + var acceptanceLicenseQuery = $"Do you accept the license terms for module '{p.Name}'."; + var message = licenseText + "`r`n" + acceptanceLicenseQuery; + + var title = "License Acceptance"; + var yesToAll = false; + var noToAll = false; + var shouldContinueResult = _cmdletPassedIn.ShouldContinue(message, title, true, ref yesToAll, ref noToAll); + + if (shouldContinueResult || yesToAll) + { + _acceptLicense = true; + } + } + + // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install + if (!_acceptLicense) + { + var message = $"License Acceptance is required for module '{p.Name}'. Please specify '-AcceptLicense' to perform this operation."; + var ex = new ArgumentException(message); + var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); + + _cmdletPassedIn.WriteError(acceptLicenseError); + success = false; + } + } + } + + return success; + } + + private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isScript) + { + // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" + // Modules will have the metadata file: "PSGetModuleInfo.xml" + var metadataXMLPath = isScript ? Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")) + : Path.Combine(dirNameVersion, "PSGetModuleInfo.xml"); + + pkg.InstalledDate = DateTime.Now; + pkg.InstalledLocation = installPath; + + // Write all metadata into metadataXMLPath + if (!pkg.TryWrite(metadataXMLPath, out string error)) + { + var message = string.Format("Error parsing metadata into XML: '{0}'", error); + var ex = new ArgumentException(message); + var ErrorParsingMetadata = new ErrorRecord(ex, "ErrorParsingMetadata", ErrorCategory.ParserError, null); + WriteError(ErrorParsingMetadata); + } + } + + private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgIdentity, string dirNameVersion) + { + // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module + var pkgIdString = pkgIdentity.ToString(); + var nupkgSHAToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.sha512").ToLower()); + var nuspecToDelete = Path.Combine(dirNameVersion, (pkgIdentity.Id + ".nuspec").ToLower()); + var nupkgToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg").ToLower()); + var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); + var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); + var packageDirToDelete = Path.Combine(dirNameVersion, "package"); + + // Unforunately have to check if each file exists because it may or may not be there + if (File.Exists(nupkgSHAToDelete)) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nupkgSHAToDelete)); + File.Delete(nupkgSHAToDelete); + } + if (File.Exists(nuspecToDelete)) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nuspecToDelete)); + File.Delete(nuspecToDelete); + } + if (File.Exists(nupkgToDelete)) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nupkgToDelete)); + File.Delete(nupkgToDelete); + } + if (File.Exists(contentTypesToDelete)) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", contentTypesToDelete)); + File.Delete(contentTypesToDelete); + } + if (Directory.Exists(relsDirToDelete)) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", relsDirToDelete)); + Directory.Delete(relsDirToDelete, true); + } + if (Directory.Exists(packageDirToDelete)) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", packageDirToDelete)); + Directory.Delete(packageDirToDelete, true); + } + } + + private void MoveFilesIntoInstallPath(PSResourceInfo p, bool isScript, bool isLocalRepo, string dirNameVersion, string tempInstallPath, string installPath, string newVersion, string moduleManifestVersion, string nupkgVersion, string versionWithoutPrereleaseTag, string scriptPath) + { + // Creating the proper installation path depending on whether pkg is a module or script + var newPathParent = isScript ? installPath : Path.Combine(installPath, p.Name); + var finalModuleVersionDir = isScript ? installPath : Path.Combine(installPath, p.Name, moduleManifestVersion); // versionWithoutPrereleaseTag + _cmdletPassedIn.WriteDebug(string.Format("Installation path is: '{0}'", finalModuleVersionDir)); + + // If script, just move the files over, if module, move the version directory over + var tempModuleVersionDir = (isScript || isLocalRepo) ? dirNameVersion + : Path.Combine(tempInstallPath, p.Name.ToLower(), newVersion); + _cmdletPassedIn.WriteVerbose(string.Format("Full installation path is: '{0}'", tempModuleVersionDir)); + + if (isScript) + { + if (!_savePkg) + { + // Need to delete old xml files because there can only be 1 per script + var scriptXML = p.Name + "_InstalledScriptInfo.xml"; + _cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); + if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting script metadata XML")); + File.Delete(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + } + + _cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); + File.Move(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + + // Need to delete old script file, if that exists + _cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); + if (File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))) + { + _cmdletPassedIn.WriteDebug(string.Format("Deleting script file")); + File.Delete(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + } + } + + _cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); + File.Move(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + } + else + { + // If new path does not exist + if (!Directory.Exists(newPathParent)) + { + _cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Directory.CreateDirectory(newPathParent); + Directory.Move(tempModuleVersionDir, finalModuleVersionDir); + } + else + { + _cmdletPassedIn.WriteDebug(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); + + // At this point if + if (Directory.Exists(finalModuleVersionDir)) + { + // Delete the directory path before replacing it with the new module + _cmdletPassedIn.WriteDebug(string.Format("Attempting to delete '{0}'", finalModuleVersionDir)); + Directory.Delete(finalModuleVersionDir, true); + } + + _cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Directory.Move(tempModuleVersionDir, finalModuleVersionDir); + } + } + } + } +} \ No newline at end of file diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs new file mode 100644 index 000000000..74f2068f0 --- /dev/null +++ b/src/code/InstallPSResource.cs @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.Management.Automation; +using System.Threading; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Install-PSResource cmdlet installs a resource. + /// It returns nothing. + /// + + [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, HelpUri = "")] + public sealed + class InstallPSResource : PSCmdlet + { + #region parameters + /// + /// Specifies the exact names of resources to install from a repository. + /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies the version or version range of the package to be installed + /// + [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// Specifies to allow installation of prerelease versions + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies the repositories from which to search for the resource to be installed. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies a user account that has rights to find a resource from a specific repository. + /// + [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + public PSCredential Credential { get; set; } + + /// + /// Specifies the scope of installation. + /// + [ValidateSet("CurrentUser", "AllUsers")] + [Parameter(ParameterSetName = NameParameterSet)] + public ScopeType Scope { get; set; } + + /// + /// Suppresses being prompted for untrusted sources. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Overwrites a previously installed resource with the same name and version. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Reinstall { get; set; } + + /// + /// Suppresses progress information. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Quiet { get; set; } + + /// + /// For modules that require a license, AcceptLicense automatically accepts the license agreement during installation. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter AcceptLicense { get; set; } + #endregion + + #region members + private const string NameParameterSet = "NameParameterSet"; + private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet"; + private const string RequiredResourceParameterSet = "RequiredResourceParameterSet"; + List _pathsToInstallPkg; + VersionRange _versionRange; + #endregion + + #region Methods + protected override void BeginProcessing() + { + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // An exact version will be formatted into a version range. + if (ParameterSetName.Equals(NameParameterSet) && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); + } + + protected override void ProcessRecord() + { + // Define the cancellation token. + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + + var installHelper = new InstallHelper(updatePkg: false, savePkg: false, cancellationToken: cancellationToken, cmdletPassedIn: this); + + switch (ParameterSetName) + { + case NameParameterSet: + installHelper.InstallPackages( + names: Name, + versionRange: _versionRange, + prerelease: Prerelease, + repository: Repository, + acceptLicense: AcceptLicense, + quiet: Quiet, + reinstall: Reinstall, + force: false, + trustRepository: TrustRepository, + noClobber: false, + credential: Credential, + requiredResourceFile: null, + requiredResourceJson: null, + requiredResourceHash: null, + specifiedPath: null, + asNupkg: false, + includeXML: true, + pathsToInstallPkg: _pathsToInstallPkg); + break; + + case RequiredResourceFileParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("RequiredResourceFileParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "CommandParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + case RequiredResourceParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("RequiredResourceParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "CommandParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + } + #endregion + } +} diff --git a/src/code/PSRepositoryInfo.cs b/src/code/PSRepositoryInfo.cs index b1d99eb08..ade75833e 100644 --- a/src/code/PSRepositoryInfo.cs +++ b/src/code/PSRepositoryInfo.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. - using System; using System.Management.Automation; diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index b4246ce28..afc63e78d 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -36,6 +36,12 @@ public enum VersionType MinimumVersion, RequiredVersion, MaximumVersion + } + + public enum ScopeType + { + CurrentUser, + AllUsers } #endregion diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 92dd42f81..63c5b0bd8 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -1,4 +1,4 @@ - + @@ -9,15 +9,14 @@ 3.0.0 3.0.0 netstandard2.0 + 8.0 - - @@ -28,7 +27,6 @@ - diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs new file mode 100644 index 000000000..626721530 --- /dev/null +++ b/src/code/SavePSResource.cs @@ -0,0 +1,181 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Threading; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Save-PSResource cmdlet saves a resource to a machine. + /// It returns nothing. + /// + + [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, HelpUri = "")] + public sealed + class SavePSResource : PSCmdlet + { + #region parameters + + /// + /// Specifies the exact names of resources to save from a repository. + /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies the version or version range of the package to be saved + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// Specifies to allow saveing of prerelease versions + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies the specific repositories to search within. + /// + [Parameter(ParameterSetName = NameParameterSet)] + // todo: add tab completion (look at get-psresourcerepository at the name parameter) + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies a user account that has rights to save a resource from a specific repository. + /// + [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + public PSCredential Credential { get; set; } + + /* + /// + /// Saves as a .nupkg + /// + [Parameter()] + public SwitchParameter AsNupkg { get; set; } + + /// + /// Saves the metadata XML file with the resource + /// + [Parameter()] + public SwitchParameter IncludeXML { get; set; } + */ + + /// + /// The destination where the resource is to be installed. Works for all resource types. + /// + [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] + [ValidateNotNullOrEmpty] + public string Path + { + get + { return _path; } + + set + { + string resolvedPath = string.Empty; + if (!string.IsNullOrEmpty(value)) + { + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + } + + // Path where resource is saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _path = resolvedPath; + } + } + } + private string _path; + + /// + /// Suppresses being prompted for untrusted sources. + /// + [Parameter()] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "InputObjectSet")] + [ValidateNotNullOrEmpty] + public object[] InputObject { set; get; } + #endregion + + #region members + private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectSet = "InputObjectSet"; + VersionRange _versionRange; + #endregion + + #region Methods + protected override void BeginProcessing() + { + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (ParameterSetName.Equals("NameParameterSet") && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + // If the user does not specify a path to save to, use the user's current working directory + if (string.IsNullOrWhiteSpace(_path)) + { + _path = SessionState.Path.CurrentLocation.Path; + } + } + + protected override void ProcessRecord() + { + // Define the cancellation token. + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + + var installHelper = new InstallHelper(updatePkg: false, savePkg: true, cancellationToken: cancellationToken, cmdletPassedIn: this); + + switch (ParameterSetName) + { + case NameParameterSet: + installHelper.InstallPackages( + names: Name, + versionRange: _versionRange, + prerelease: Prerelease, + repository: Repository, + acceptLicense: true, + quiet: true, + reinstall: true, + force: false, + trustRepository: TrustRepository, + noClobber: false, + credential: Credential, + requiredResourceFile: null, + requiredResourceJson: null, + requiredResourceHash: null, + specifiedPath: _path, + asNupkg: false, + includeXML: false, + pathsToInstallPkg: new List { _path } ); + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/code/Utils.cs b/src/code/Utils.cs index bdd50b9c4..04de32228 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,275 +1,366 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Collections.Generic; -using static System.Environment; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Runtime.InteropServices; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - internal static class Utils - { - public static void WriteVerboseOnCmdlet( - PSCmdlet cmdlet, - string message) - { - try - { - cmdlet.InvokeCommand.InvokeScript( - script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { message }); - } - catch { } - } - - public static string GetNormalizedVersionString( - string versionString, - string prerelease - ) - { - // versionString may be like 1.2.0.0 or 1.2.0 - // prerelease may be null or "alpha1" - // possible passed in examples: - // versionString: "1.2.0" prerelease: "alpha1" - // versionString: "1.2.0" prerelease: "" <- doubtful though - // versionString: "1.2.0.0" prerelease: "alpha1" - // versionString: "1.2.0.0" prerelease: "" - - if (String.IsNullOrEmpty(prerelease)) - { - return versionString; - } - - int numVersionDigits = versionString.Split('.').Count(); - - if (numVersionDigits == 3) - { - // versionString: "1.2.0" prerelease: "alpha1" - return versionString + "-" + prerelease; - } - - else if (numVersionDigits == 4) - { - // versionString: "1.2.0.0" prerelease: "alpha1" - return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; - } - - return versionString; - } - - public static string[] FilterOutWildcardNames( - string[] pkgNames, - out string[] errorMsgs) - { - List errorFreeNames = new List(); - List errorMsgList = new List(); - - foreach (string n in pkgNames) - { - bool isNameErrorProne = false; - if (WildcardPattern.ContainsWildcardCharacters(n)) - { - if (String.Equals(n, "*", StringComparison.InvariantCultureIgnoreCase)) - { - errorMsgList = new List(); // clear prior error messages - errorMsgList.Add("-Name '*' is not supported for Find-PSResource so all Name entries will be discarded."); - errorFreeNames = new List(); - break; - } - else if (n.Contains("?") || n.Contains("[")) - { - errorMsgList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for Find-PSResource so Name entry: {0} will be discarded.", n)); - isNameErrorProne = true; - } - } - - if (!isNameErrorProne) - { - errorFreeNames.Add(n); - } - } - - errorMsgs = errorMsgList.ToArray(); - return errorFreeNames.ToArray(); - } - - #region Public methods - - public static string TrimQuotes(string name) - { - return name.Trim('\'', '"'); - } - - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) - { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } - } - - if (!quotesNeeded) - { - return name; - } - - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i < list.Count; i++) - { - strArray[i] = list[i] as string; - } - - return strArray; - } - - public static bool TryParseVersionOrVersionRange( - string version, - out VersionRange versionRange) - { - versionRange = null; - - if (version == null) { return false; } - - - if (version.Trim().Equals("*")) - { - versionRange = VersionRange.All; - return true; - } - - // parse as NuGetVersion - if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) - { - versionRange = new VersionRange( - minVersion: nugetVersion, - includeMinVersion: true, - maxVersion: nugetVersion, - includeMaxVersion: true, - floatRange: null, - originalString: null); - return true; - } - - // parse as Version range - return VersionRange.TryParse(version, out versionRange); - } - - public static string GetInstalledPackageName(string pkgPath) - { - if (string.IsNullOrEmpty(pkgPath)) - { - return string.Empty; - } - - if (File.Exists(pkgPath)) - { - // ex: ./PowerShell/Scripts/TestScript.ps1 - return System.IO.Path.GetFileNameWithoutExtension(pkgPath); - } - else - { - // expecting the full version module path - // ex: ./PowerShell/Modules/TestModule/1.0.0 - return new DirectoryInfo(pkgPath).Parent.Name; - } - } - - public static List GetAllResourcePaths(PSCmdlet psCmdlet) - { - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - List resourcePaths = psModulePath.Split(';').ToList(); - List pathsToSearch = new List(); - var PSVersion6 = new Version(6, 0); - var isCorePS = psCmdlet.Host.Version >= PSVersion6; - string myDocumentsPath; - string programFilesPath; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and MacOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); - programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); - } - - // will search first in PSModulePath, then will search in default paths - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); - - // resourcePaths should now contain, eg: - // ./PowerShell/Scripts - // ./PowerShell/Modules - // add all module directories or script files - foreach (string path in resourcePaths) - { - psCmdlet.WriteDebug(string.Format("Retrieving directories in the path '{0}'", path)); - - if (path.EndsWith("Scripts")) - { - try - { - pathsToSearch.AddRange(Directory.GetFiles(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); - } - } - else - { - try - { - pathsToSearch.AddRange(Directory.GetDirectories(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); - } - } - } - - // resourcePaths should now contain eg: - // ./PowerShell/Scripts/Test-Script.ps1 - // ./PowerShell/Modules/TestModule - // need to use .ToList() to cast the IEnumerable to type List - pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - pathsToSearch.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); - - return pathsToSearch; - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using static System.Environment; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Runtime.InteropServices; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + internal static class Utils + { + public static void WriteVerboseOnCmdlet( + PSCmdlet cmdlet, + string message) + { + try + { + cmdlet.InvokeCommand.InvokeScript( + script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { message }); + } + catch { } + } + + public static string GetNormalizedVersionString( + string versionString, + string prerelease + ) + { + // versionString may be like 1.2.0.0 or 1.2.0 + // prerelease may be null or "alpha1" + // possible passed in examples: + // versionString: "1.2.0" prerelease: "alpha1" + // versionString: "1.2.0" prerelease: "" <- doubtful though + // versionString: "1.2.0.0" prerelease: "alpha1" + // versionString: "1.2.0.0" prerelease: "" + + if (String.IsNullOrEmpty(prerelease)) + { + return versionString; + } + + int numVersionDigits = versionString.Split('.').Count(); + + if (numVersionDigits == 3) + { + // versionString: "1.2.0" prerelease: "alpha1" + return versionString + "-" + prerelease; + } + + else if (numVersionDigits == 4) + { + // versionString: "1.2.0.0" prerelease: "alpha1" + return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; + } + + return versionString; + } + + public static string[] FilterOutWildcardNames( + string[] pkgNames, + out string[] errorMsgs) + { + List errorFreeNames = new List(); + List errorMsgList = new List(); + + foreach (string n in pkgNames) + { + bool isNameErrorProne = false; + if (WildcardPattern.ContainsWildcardCharacters(n)) + { + if (String.Equals(n, "*", StringComparison.InvariantCultureIgnoreCase)) + { + errorMsgList = new List(); // clear prior error messages + errorMsgList.Add("-Name '*' is not supported for Find-PSResource so all Name entries will be discarded."); + errorFreeNames = new List(); + break; + } + else if (n.Contains("?") || n.Contains("[")) + { + errorMsgList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for Find-PSResource so Name entry: {0} will be discarded.", n)); + isNameErrorProne = true; + } + } + + if (!isNameErrorProne) + { + errorFreeNames.Add(n); + } + } + + errorMsgs = errorMsgList.ToArray(); + return errorFreeNames.ToArray(); + } + + #region Public methods + + public static string TrimQuotes(string name) + { + return name.Trim('\'', '"'); + } + + public static string QuoteName(string name) + { + bool quotesNeeded = false; + foreach (var c in name) + { + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } + } + + if (!quotesNeeded) + { + return name; + } + + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) + { + strArray[i] = list[i] as string; + } + + return strArray; + } + + public static bool TryParseVersionOrVersionRange( + string version, + out VersionRange versionRange) + { + versionRange = null; + + if (version == null) { return false; } + + + if (version.Trim().Equals("*")) + { + versionRange = VersionRange.All; + return true; + } + + // parse as NuGetVersion + if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) + { + versionRange = new VersionRange( + minVersion: nugetVersion, + includeMinVersion: true, + maxVersion: nugetVersion, + includeMaxVersion: true, + floatRange: null, + originalString: version); + return true; + } + + // parse as Version range + return VersionRange.TryParse(version, out versionRange); + } + + public static string GetInstalledPackageName(string pkgPath) + { + if (string.IsNullOrEmpty(pkgPath)) + { + return string.Empty; + } + + if (File.Exists(pkgPath)) + { + // ex: ./PowerShell/Scripts/TestScript.ps1 + return System.IO.Path.GetFileNameWithoutExtension(pkgPath); + } + else + { + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; + } + } + + public static List GetAllResourcePaths(PSCmdlet psCmdlet) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + List resourcePaths = psModulePath.Split(';').ToList(); + List pathsToSearch = new List(); + var PSVersion6 = new Version(6, 0); + var isCorePS = psCmdlet.Host.Version >= PSVersion6; + string myDocumentsPath; + string programFilesPath; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; + + myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and MacOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); + programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); + } + + // will search first in PSModulePath, then will search in default paths + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); + + // resourcePaths should now contain, eg: + // ./PowerShell/Scripts + // ./PowerShell/Modules + // add all module directories or script files + foreach (string path in resourcePaths) + { + psCmdlet.WriteDebug(string.Format("Retrieving directories in the path '{0}'", path)); + + if (path.EndsWith("Scripts")) + { + try + { + pathsToSearch.AddRange(Directory.GetFiles(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); + } + } + else + { + try + { + pathsToSearch.AddRange(Directory.GetDirectories(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); + } + } + } + + // resourcePaths should now contain eg: + // ./PowerShell/Scripts/Test-Script.ps1 + // ./PowerShell/Modules/TestModule + // need to use .ToList() to cast the IEnumerable to type List + pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + pathsToSearch.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); + + return pathsToSearch; + } + + + // Find all potential installation paths given a scope + public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType scope) + { + List installationPaths = new List(); + var PSVersion6 = new Version(6, 0); + var isCorePS = psCmdlet.Host.Version >= PSVersion6; + string myDocumentsPath; + string programFilesPath; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; + + myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and MacOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); + programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); + } + + // The default user scope is CurrentUser + if (scope == ScopeType.AllUsers) + { + installationPaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); + installationPaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); + } + else { + installationPaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); + installationPaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); + } + + installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + installationPaths.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); + + return installationPaths; + } + + private static string GetResourceNameFromPath(string path) + { + // Resource paths may end in a directory or script file name. + // Directory name is the same as the resource name. + // Script file name is the resource name without the file extension. + // ./Modules/Microsoft.PowerShell.Test-Module : Microsoft.PowerShell.Test-Module + // ./Scripts/Microsoft.PowerShell.Test-Script.ps1 : Microsoft.PowerShell.Test-Script + var resourceName = Path.GetFileName(path); + return Path.GetExtension(resourceName).Equals(".ps1", StringComparison.OrdinalIgnoreCase) + ? Path.GetFileNameWithoutExtension(resourceName) : resourceName; + } + + public static Hashtable ParseModuleManifest(string moduleFileInfo, PSCmdlet cmdletPassedIn) + { + Hashtable parsedMetadataHash = new Hashtable(); + // A script will already have the metadata parsed into the parsedMetadatahash, + // a module will still need the module manifest to be parsed. + if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) + { + // Parse the module manifest + System.Management.Automation.Language.Token[] tokens; + ParseError[] errors; + var ast = Parser.ParseFile(moduleFileInfo, out tokens, out errors); + + if (errors.Length > 0) + { + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + } + else + { + var data = ast.Find(a => a is HashtableAst, false); + if (data != null) + { + parsedMetadataHash = (Hashtable)data.SafeGetValue(); + } + else + { + var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + } + } + } + + return parsedMetadataHash; + } + #endregion + } +} diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 new file mode 100644 index 000000000..0f4cd7a29 --- /dev/null +++ b/test/InstallPSResource.Tests.ps1 @@ -0,0 +1,233 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Install-PSResource for Module' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + $NuGetGalleryName = Get-NuGetGalleryName + Get-NewPSResourceRepositoryFile + Register-LocalRepos + } + + AfterEach { + Uninstall-PSResource "TestModule", "TestModule99", "myTestModule", "myTestModule2", "testModulePrerelease", + "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule" + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Install specific module resource by name" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.3.0" + } + + It "Install specific script resource by name" { + Install-PSResource -Name "TestTestScript" -Repository $TestGalleryName + $pkg = Get-InstalledPSResource "TestTestScript" + $pkg.Name | Should -Be "TestTestScript" + $pkg.Version | Should -Be "1.3.1.0" + } + + It "Install multiple resources by name" { + $pkgNames = @("TestModule","TestModule99") + Install-PSResource -Name $pkgNames -Repository $TestGalleryName + $pkg = Get-Module $pkgNames -ListAvailable + $pkg.Name | Should -Be $pkgNames + } + + + It "Should not install resource given nonexistant name" { + Install-PSResource -Name NonExistantModule -Repository $TestGalleryName + $pkg = Get-Module "NonExistantModule" -ListAvailable + $pkg.Name | Should -BeNullOrEmpty + } + + # Do some version testing, but Find-PSResource should be doing thorough testing + It "Should install resource given name and exact version" { + Install-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.2.0" + } + + It "Should install resource given name and exact version with bracket syntax" { + Install-PSResource -Name "TestModule" -Version "[1.2.0]" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.2.0" + } + + It "Should install resource given name and exact range inclusive [1.0.0, 1.1.1]" { + Install-PSResource -Name "TestModule" -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.1.1" + } + + It "Should install resource given name and exact range exclusive (1.0.0, 1.1.1)" { + Install-PSResource -Name "TestModule" -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.1" + } + + It "Should not install resource with incorrectly formatted version such as " -TestCases @( + @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, + @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + ) { + param($Version, $Description) + + Install-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName + $res = Get-Module "TestModule" -ListAvailable + $res | Should -BeNullOrEmpty + } + + It "Install resource when given Name, Version '*', should install the latest version" { + $pkg = Install-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.3.0" + } + + It "Install resource with latest (including prerelease) version given Prerelease parameter" { + $pkg = Install-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName + $pkg = Get-Module "TestModulePrerelease" -ListAvailable + $pkg.Name | Should -Be "TestModulePrerelease" + $pkg.Version | Should -Be "0.0.1" + $pkg.PrivateData.PSData.Prerelease | Should -Be "preview" + } + + It "Install a module with a dependency" { + $pkg = Install-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName + $pkg = Get-Module "PSGetTestModule" -ListAvailable + $pkg.Name | Should -Be "PSGetTestModule" + $pkg.Version | Should -Be "2.0.2" + $pkg.PrivateData.PSData.Prerelease | Should -Be "-alpha1" + + $pkg = Get-Module "PSGetTestDependency1" -ListAvailable + $pkg.Name | Should -Be "PSGetTestDependency1" + $pkg.Version | Should -Be "1.0.0" + } + + It "Install resource via InputObject by piping from Find-PSresource" { + Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Install-PSResource + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.3.0" + } + + # Windows only + It "Install resource under CurrentUser scope" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("Documents") | Should -Be $true + } + + # Windows only + It "Install resource under AllUsers scope" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("Program Files") | Should -Be $true + } + + # Windows only + It "Install resource under no specified scope" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("Documents") | Should -Be $true + } + + It "Should not install resource that is already installed" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -WarningVariable WarningVar -warningaction SilentlyContinue + $WarningVar | Should -Not -BeNullOrEmpty + } + + It "Reinstall resource that is already installed with -Reinstall parameter" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.3.0" + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Reinstall + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.3.0" + } + + It "Install resource that requires accept license with -AcceptLicense flag" { + Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName -AcceptLicense + $pkg = Get-InstalledPSResource "testModuleWithlicense" + $pkg.Name | Should -Be "testModuleWithlicense" + $pkg.Version | Should -Be "0.0.1.0" + } + + It "Install resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -TrustRepository + + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + + Set-PSResourceRepository PoshTestGallery -Trusted + } + + It "Install resource with cmdlet names from a module already installed (should clobber)" { + Install-PSResource -Name "myTestModule" -Repository $TestGalleryName + $pkg = Get-InstalledPSResource "myTestModule" + $pkg.Name | Should -Be "myTestModule" + $pkg.Version | Should -Be "0.0.3.0" + + Install-PSResource -Name "myTestModule2" -Repository $TestGalleryName + $pkg = Get-InstalledPSResource "myTestModule2" + $pkg.Name | Should -Be "myTestModule2" + $pkg.Version | Should -Be "0.0.1.0" + } + + It "Install resource from local repository given Repository parameter" { + $publishModuleName = "TestFindModule" + $repoName = "psgettestlocal" + Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName $repoName + Set-PSResourceRepository "psgettestlocal" -Trusted:$true + + Install-PSResource -Name $publishModuleName -Repository $repoName + $pkg = Get-Module $publishModuleName -ListAvailable + $pkg | Should -Not -BeNullOrEmpty + $pkg.Name | Should -Be $publishModuleName + } + +<# + # This needs to be manually tested due to prompt + It "Install resource that requires accept license without -AcceptLicense flag" { + Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName + $pkg = Get-InstalledPSResource "testModuleWithlicense" + $pkg.Name | Should -Be "testModuleWithlicense" + $pkg.Version | Should -Be "0.0.1.0" + } + + # This needs to be manually tested due to prompt + It "Install resource should prompt 'trust repository' if repository is not trusted" { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -confirm:$false + + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + + Set-PSResourceRepository PoshTestGallery -Trusted + } +#> +} diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index f3410ffaf..9f2bf557d 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -166,6 +166,13 @@ function Get-RemoveTestDirs { } } +function Create-TemporaryDirectory { + $path = [System.IO.Path]::GetTempPath() + $child = [System.Guid]::NewGuid() + + return New-Item -ItemType Directory -Path (Join-Path $path $child) +} + function Get-NewPSResourceRepositoryFile { # register our own repositories with desired priority $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 new file mode 100644 index 000000000..64a619f0a --- /dev/null +++ b/test/SavePSResource.Tests.ps1 @@ -0,0 +1,203 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Save-PSResource for PSResources' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + $NuGetGalleryName = Get-NuGetGalleryName + Get-NewPSResourceRepositoryFile + Register-LocalRepos + + $TempDir = Create-TemporaryDirectory + } + + AfterEach { + # Delete all files and subdirectories in $Tempdir, but keep the directory $Tempdir + try { + Get-ChildItem -Path $TempDir -Force | foreach { $_.Delete($true)} + } + catch { + Get-ChildItem -Path $TempDir -Force | foreach { $_.Delete()} + } + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Save specific module resource by name" { + Save-PSResource -Name "TestModule" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + } + + It "Save specific script resource by name" { + Save-PSResource -Name "TestTestScript" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestTestScript.ps1" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + } + + It "Save multiple resources by name" { + $pkgNames = @("TestModule","TestModule99") + Save-PSResource -Name $pkgNames -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be @("TestModule","TestModule99") + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + } + + It "Should not save resource given nonexistant name" { + Save-PSResource -Name NonExistantModule -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -BeNullOrEmpty + } + + # Do some version testing, but Find-PSResource should be doing thorough testing + It "Should save resource given name and exact version" { + Save-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.2.0" + } + + It "Should save resource given name and exact version with bracket syntax" { + Save-PSResource -Name "TestModule" -Version "[1.2.0]" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.2.0" + } + + It "Should save resource given name and exact range inclusive [1.0.0, 1.1.1]" { + Save-PSResource -Name "TestModule" -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.1.1" + } + + It "Should save resource given name and exact range exclusive (1.0.0, 1.1.1)" { + Save-PSResource -Name "TestModule" -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.1" + } + + It "Should not save resource with incorrectly formatted version such as " -TestCases @( + @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, + @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + ) { + param($Version, $Description) + + Save-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName -Path $TempDir + $res = Get-ChildItem $TempDir + $res | Should -BeNullOrEmpty + } + + It "Save resource when given Name, Version '*', should install the latest version" { + Save-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.3.0" + } + + It "Save resource with latest (including prerelease) version given Prerelease parameter" { + Save-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModulePrerelease" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "0.0.1" + } + + It "Save a module with a dependency" { + Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be @("PSGetTestDependency1","PSGetTestModule") + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + } + + It "Save resource via InputObject by piping from Find-PSresource" { + Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Save-PSResource -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.3.0" + } + + It "Save resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + + Save-PSResource -Name "TestModule" -Repository $TestGalleryName -TrustRepository -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgVersion = Get-ChildItem $pkg + $pkgVersion.Name | Should -Be "1.3.0" + + Set-PSResourceRepository PoshTestGallery -Trusted + } + + It "Save resource from local repository given Repository parameter" { + $publishModuleName = "TestFindModule" + $repoName = "psgettestlocal" + Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName $repoName + Set-PSResourceRepository "psgettestlocal" -Trusted:$true + + Save-PSResource -Name $publishModuleName -Repository $repoName -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be $publishModuleName + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + } + + It "Save specific module resource by name when no repository is specified" { + Set-PSResourceRepository "PoshTestGallery" -Trusted:$True + Set-PSResourceRepository "PSGallery" -Trusted:$True + Set-PSResourceRepository "psgettestlocal2" -Trusted:$True + + Save-PSResource -Name "TestModule" -Path $TempDir + $pkg = Get-ChildItem $TempDir + $pkg.Name | Should -Be "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + } + + It "Save specific module resource by name if no -Path param is specifed" { + Save-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-ChildItem . + + $pkg.Name | Should -Contain "TestModule" + (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + + # Delete all files and subdirectories in the current , but keep the directory $Tempdir + $pkgDir = Join-Path -Path . -ChildPath "TestModule" + Remove-Item $pkgDir -Recurse -Force + } + +<# + # This needs to be manually tested due to prompt + It "Install resource should prompt 'trust repository' if repository is not trusted" { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -confirm:$false + + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + + Set-PSResourceRepository PoshTestGallery -Trusted + } +#> +} \ No newline at end of file From 9e882f0d179af94c4e1609e3b15e09632e08e1e5 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 15 Jul 2021 16:14:49 -0700 Subject: [PATCH 041/276] Update PSResourceInfo type to have correct default property values (#414) --- src/PowerShellGet.psd1 | 2 +- src/code/GetHelper.cs | 12 +- src/code/GetInstalledPSResource.cs | 20 +- src/code/GetPSResourceRepository.cs | 2 +- src/code/InstallHelper.cs | 2 +- src/code/PSResourceInfo.cs | 1856 ++++++++++---------- src/code/UninstallPSResource.cs | 2 +- src/code/UnregisterPSResourceRepository.cs | 2 +- src/code/Utils.cs | 191 +- 9 files changed, 1093 insertions(+), 996 deletions(-) diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index ae027fb76..57fa37ce3 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -27,7 +27,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta10' + Prerelease = 'beta11' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index f9c8c0f87..6eae2e68a 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -93,15 +93,11 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // ./Modules/Test-Module/2.0.0 _cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); - string[] versionsDirs = new string[] { }; - try + string[] versionsDirs = Utils.GetSubDirectories(pkgPath); + if (versionsDirs.Length == 0) { - versionsDirs = Directory.GetDirectories(pkgPath); - } - catch (Exception e){ - _cmdletPassedIn.WriteVerbose(string.Format("Error retreiving directories from path '{0}': '{1}'", pkgPath, e.Message)); - - // skip to next iteration of the loop + _cmdletPassedIn.WriteVerbose( + $"No version subdirectories found for path: {pkgPath}"); continue; } diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index bf04c3485..db1974781 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -87,17 +87,19 @@ protected override void BeginProcessing() var resolvedPath = resolvedPaths[0].Path; WriteDebug(string.Format("Provided resolved path is '{0}'", resolvedPath)); - try + var versionPaths = Utils.GetSubDirectories(resolvedPath); + if (versionPaths.Length == 0) { - _pathsToSearch.AddRange(Directory.GetDirectories(resolvedPath)); - } - catch (Exception e) - { - var exMessage = String.Format("Error retrieving directories from provided path '{0}': '{1}'.", Path, e.Message); - var ex = new ArgumentException(exMessage); - var ErrorRetrievingDirectories = new ErrorRecord(ex, "ErrorRetrievingDirectories", ErrorCategory.ResourceUnavailable, null); - ThrowTerminatingError(ErrorRetrievingDirectories); + ThrowTerminatingError( + new ErrorRecord( + exception: new PSInvalidOperationException( + $"Error cannot find expected subdirectories in provided path: {Path}"), + "PathMissingExpectedSubdirectories", + ErrorCategory.InvalidOperation, + targetObject: null)); } + + _pathsToSearch.AddRange(versionPaths); } else { diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs index a000c8de0..05f168d58 100644 --- a/src/code/GetPSResourceRepository.cs +++ b/src/code/GetPSResourceRepository.cs @@ -31,7 +31,7 @@ class GetPSResourceRepository : PSCmdlet [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] - public string[] Name { get; set; } = new string[0]; + public string[] Name { get; set; } = Utils.EmptyStrArray; #endregion diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 8874ef180..b0bae2717 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -226,7 +226,7 @@ public IEnumerable FilterByInstalledPkgs(IEnumerable pkgsAlreadyInstalled = getHelper.FilterPkgPaths(pkgNames.ToArray(), _versionRange, _pathsToSearch); diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index afc63e78d..a70922618 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -1,901 +1,967 @@ -using System.Text.RegularExpressions; -using System.Linq; -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; -using System.Globalization; -using System.Management.Automation; -using NuGet.Packaging; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - #region Enums - - [Flags] - public enum ResourceType - { - // 00001 -> M - // 00100 -> C - // 00101 -> M, C - None = 0x0, - Module = 0x1, - Script = 0x2, - Command = 0x4, - DscResource = 0x8 - } - - public enum VersionType - { - Unknown, - MinimumVersion, - RequiredVersion, - MaximumVersion +using System.Text.RegularExpressions; +using System.Linq; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.Globalization; +using System.Management.Automation; +using NuGet.Packaging; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + #region Enums + + [Flags] + public enum ResourceType + { + // 00001 -> M + // 00100 -> C + // 00101 -> M, C + None = 0x0, + Module = 0x1, + Script = 0x2, + Command = 0x4, + DscResource = 0x8 + } + + public enum VersionType + { + Unknown, + MinimumVersion, + RequiredVersion, + MaximumVersion } public enum ScopeType { CurrentUser, AllUsers - } - - #endregion - - #region VersionInfo - - public sealed class VersionInfo - { - public VersionInfo( - VersionType versionType, - Version versionNum) - { - VersionType = versionType; - VersionNum = versionNum; - } - - public VersionType VersionType { get; } - public Version VersionNum { get; } - - public override string ToString() => $"{VersionType}: {VersionNum}"; - } - - #endregion - - #region ResourceIncludes - - public sealed class ResourceIncludes - { - #region Properties - - public string[] Cmdlet { get; } - - public string[] Command { get; } - - public string[] DscResource { get; } - - public string[] Function { get; } - - public string[] RoleCapability { get; } - - public string[] Workflow { get; } - - #endregion - - #region Constructor - - /// - /// Constructor - /// - /// Provided hashtable has form: - /// Key: Cmdlet - /// Value: ArrayList of Cmdlet name strings - /// Key: Command - /// Value: ArrayList of Command name strings - /// Key: DscResource - /// Value: ArrayList of DscResource name strings - /// Key: Function - /// Value: ArrayList of Function name strings - /// Key: RoleCapability (deprecated for PSGetV3) - /// Value: ArrayList of RoleCapability name strings - /// Key: Workflow (deprecated for PSGetV3) - /// Value: ArrayList of Workflow name strings - /// - /// Hashtable of PSGet includes - public ResourceIncludes(Hashtable includes) - { - if (includes == null) { return; } - - Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); - Command = GetHashTableItem(includes, nameof(Command)); - DscResource = GetHashTableItem(includes, nameof(DscResource)); - Function = GetHashTableItem(includes, nameof(Function)); - RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); - Workflow = GetHashTableItem(includes, nameof(Workflow)); - } - - #endregion - - #region Public methods - - public Hashtable ConvertToHashtable() - { - var hashtable = new Hashtable - { - { nameof(Cmdlet), Cmdlet }, - { nameof(Command), Command }, - { nameof(DscResource), DscResource }, - { nameof(Function), Function }, - { nameof(RoleCapability), RoleCapability }, - { nameof(Workflow), Workflow } - }; - - return hashtable; - } - - #endregion - - #region Private methods - - private string[] GetHashTableItem( - Hashtable table, - string name) - { - if (table.ContainsKey(name) && - table[name] is PSObject psObjectItem) - { - return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); - } - - return null; - } - - #endregion - } - - #endregion - - #region Dependency - - public sealed class Dependency - { - #region Properties - - public string Name { get; } - - public VersionRange VersionRange { get; } - - #endregion - - #region Constructor - - /// - /// Constructor - /// - /// - /// Hashtable of PSGet includes - public Dependency(string dependencyName, VersionRange dependencyVersionRange) - { - Name = dependencyName; - VersionRange = dependencyVersionRange; - } - - #endregion - } - - #endregion - - #region PSResourceInfo - - public sealed class PSResourceInfo - { - #region Properties - - public Dictionary AdditionalMetadata { get; set; } - public string Author { get; set; } - public string CompanyName { get; set; } - public string Copyright { get; set; } - public Dependency[] Dependencies { get; set; } - public string Description { get; set; } - public Uri IconUri { get; set; } - public ResourceIncludes Includes { get; set; } - public DateTime? InstalledDate { get; set; } - public string InstalledLocation { get; set; } - public bool IsPrerelease { get; set; } - public Uri LicenseUri { get; set; } - public string Name { get; set; } - public string PackageManagementProvider { get; set; } - public string PowerShellGetFormatVersion { get; set; } - public string PrereleaseLabel { get; set; } - public Uri ProjectUri { get; set; } - public DateTime? PublishedDate { get; set; } - public string ReleaseNotes { get; set; } - public string Repository { get; set; } - public string RepositorySourceLocation { get; set; } - public string[] Tags { get; set; } - public ResourceType Type { get; set; } - public DateTime? UpdatedDate { get; set; } - public Version Version { get; set; } - - #endregion - - #region Constructor - #endregion - - #region Private fields - private static readonly char[] Delimeter = {' ', ','}; - - #endregion - - #region Public static methods - - /// - /// Writes the PSGetResourceInfo properties to the specified file path as a - /// PowerShell serialized xml file, maintaining compatibility with - /// PowerShellGet v2 file format. - /// - public bool TryWrite( - string filePath, - out string errorMsg) - { - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - var infoXml = PSSerializer.Serialize( - source: ConvertToCustomObject(), - depth: 5); - - System.IO.File.WriteAllText( - path: filePath, - contents: infoXml); - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", - ex.Message); - - return false; - } - } - - /// - /// Reads a PSGet resource xml (PowerShell serialized) file and returns - /// a PSResourceInfo object containing the file contents. - /// - public static bool TryRead( - string filePath, - out PSResourceInfo psGetInfo, - out string errorMsg) - { - psGetInfo = null; - errorMsg = string.Empty; - - if (string.IsNullOrWhiteSpace(filePath)) - { - errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; - return false; - } - - try - { - // Read and deserialize information xml file. - var psObjectInfo = (PSObject) PSSerializer.Deserialize( - System.IO.File.ReadAllText( - filePath)); - - var additionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo); - Version version = GetVersionInfo(psObjectInfo, additionalMetadata, out string prereleaseLabel); - - psGetInfo = new PSResourceInfo - { - AdditionalMetadata = additionalMetadata, - Author = GetStringProperty(nameof(PSResourceInfo.Author), psObjectInfo), - CompanyName = GetStringProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), - Copyright = GetStringProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), - Dependencies = GetDependencies(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), - Description = GetStringProperty(nameof(PSResourceInfo.Description), psObjectInfo), - IconUri = GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), - Includes = new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), - InstalledDate = GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), - InstalledLocation = GetStringProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), - IsPrerelease = GetProperty(nameof(PSResourceInfo.IsPrerelease), psObjectInfo), - LicenseUri = GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), - Name = GetStringProperty(nameof(PSResourceInfo.Name), psObjectInfo), - PackageManagementProvider = GetStringProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), - PowerShellGetFormatVersion = GetStringProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), - PrereleaseLabel = prereleaseLabel, - ProjectUri = GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), - PublishedDate = GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), - ReleaseNotes = GetStringProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), - Repository = GetStringProperty(nameof(PSResourceInfo.Repository), psObjectInfo), - RepositorySourceLocation = GetStringProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), - Tags = Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), - // try to get the value of PSResourceInfo.Type property, if the value is null use ResourceType.Module as value - // this value will be used in Enum.TryParse. If Enum.TryParse returns false, use ResourceType.Module to set Type instead. - Type = Enum.TryParse( - GetProperty(nameof(PSResourceInfo.Type), psObjectInfo) ?? nameof(ResourceType.Module), - out ResourceType currentReadType) - ? currentReadType : ResourceType.Module, - UpdatedDate = GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), - Version = version - }; - - return true; - } - catch(Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", - ex.Message); - - return false; - } - } - - private static string GetStringProperty( - string name, - PSObject psObjectInfo) - { - return GetProperty(name, psObjectInfo) ?? string.Empty; - } - - private static Version GetVersionInfo( - PSObject psObjectInfo, - Dictionary additionalMetadata, - out string prereleaseLabel) - { - string versionString = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); - prereleaseLabel = String.Empty; - - if (!String.IsNullOrEmpty(versionString) || - additionalMetadata.TryGetValue("NormalizedVersion", out versionString)) - { - string pkgVersion = versionString; - if (versionString.Contains("-")) - { - // versionString: "1.2.0-alpha1" - string[] versionStringParsed = versionString.Split('-'); - if (versionStringParsed.Length == 1) - { - // versionString: "1.2.0-" (unlikely, at least should not be from our PSResourceInfo.TryWrite()) - pkgVersion = versionStringParsed[0]; - } - else - { - // versionStringParsed.Length > 1 (because string contained '-' so couldn't be 0) - // versionString: "1.2.0-alpha1" - pkgVersion = versionStringParsed[0]; - prereleaseLabel = versionStringParsed[1]; - } - } - - // at this point, version is normalized (i.e either "1.2.0" (if part of prerelease) or "1.2.0.0" otherwise) - // parse the pkgVersion parsed out above into a System.Version object - if (!Version.TryParse(pkgVersion, out Version parsedVersion)) - { - prereleaseLabel = String.Empty; - return null; - } - else - { - return parsedVersion; - } - } - - // version could not be parsed as string, it was written to XML file as a System.Version object - // V3 code briefly did so, I believe so we provide support for it - prereleaseLabel = String.Empty; - return GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); - } - - - public static bool TryConvert( - IPackageSearchMetadata metadataToParse, - out PSResourceInfo psGetInfo, - string repositoryName, - ResourceType? type, - out string errorMsg) - { - psGetInfo = null; - errorMsg = String.Empty; - - if (metadataToParse == null) - { - errorMsg = "TryConvertPSResourceInfo: Invalid IPackageSearchMetadata object. Object cannot be null."; - return false; - } - - try - { - psGetInfo = new PSResourceInfo - { - // not all of the properties of PSResourceInfo are filled as they are not there in metadata returned for Find-PSResource. - Author = ParseMetadataAuthor(metadataToParse), - Dependencies = ParseMetadataDependencies(metadataToParse), - Description = ParseMetadataDescription(metadataToParse), - IconUri = ParseMetadataIconUri(metadataToParse), - IsPrerelease = ParseMetadataIsPrerelease(metadataToParse), - LicenseUri = ParseMetadataLicenseUri(metadataToParse), - Name = ParseMetadataName(metadataToParse), - PrereleaseLabel = ParsePrerelease(metadataToParse), - ProjectUri = ParseMetadataProjectUri(metadataToParse), - PublishedDate = ParseMetadataPublishedDate(metadataToParse), - Repository = repositoryName, - Tags = ParseMetadataTags(metadataToParse), - Type = ParseMetadataType(metadataToParse, repositoryName, type), - Version = ParseMetadataVersion(metadataToParse) - }; - - return true; - } - catch (Exception ex) - { - errorMsg = string.Format( - CultureInfo.InvariantCulture, - @"TryReadPSGetInfo: Cannot parse PSResourceInfo from IPackageSearchMetadata with error: {0}", - ex.Message); - return false; - } - } - - #endregion - - #region Private static methods - - private static T ConvertToType(PSObject psObject) - { - // We only convert Dictionary types. - if (typeof(T) != typeof(Dictionary)) - { - return default(T); - } - - var dict = new Dictionary(); - foreach (var prop in psObject.Properties) - { - dict.Add(prop.Name, prop.Value.ToString()); - } - - return (T)Convert.ChangeType(dict, typeof(T)); - } - - private static T GetProperty( - string Name, - PSObject psObjectInfo) - { - var val = psObjectInfo.Properties[Name]?.Value; - if (val == null) - { - return default(T); - } - - switch (val) - { - case T valType: - return valType; - - case PSObject valPSObject: - switch (valPSObject.BaseObject) - { - case T valBase: - return valBase; - - case PSCustomObject _: - // A base object of PSCustomObject means this is additional metadata - // and type T should be Dictionary. - return ConvertToType(valPSObject); - - default: - return default(T); - } - - default: - return default(T); - } - } - - private static string GetPrereleaseLabel(Version version) - { - string versionAsString = version.ToString(); - - if (!versionAsString.Contains("-")) - { - // no prerelease label present - return String.Empty; - } - - string[] prereleaseParsed = versionAsString.Split('-'); - if (prereleaseParsed.Length <= 1) - { - return String.Empty; - } - - string prereleaseString = prereleaseParsed[1]; - Regex prereleasePattern = new Regex("^[a-zA-Z0-9]+$"); - if (!prereleasePattern.IsMatch(prereleaseString)) - { - return String.Empty; - } - - return prereleaseString; - } - - private static Dependency[] GetDependencies(ArrayList dependencyInfos) - { - List dependenciesFound = new List(); - if (dependencyInfos == null) { return dependenciesFound.ToArray(); } - - - foreach(PSObject dependencyObj in dependencyInfos) - { - // The dependency object can be a string or a hashtable - // eg: - // RequiredModules = @('PSGetTestDependency1') - // RequiredModules = @(@{ModuleName='PackageManagement';ModuleVersion='1.0.0.1'}) - if (dependencyObj.BaseObject is Hashtable dependencyInfo) - { - if (!dependencyInfo.ContainsKey("Name")) - { - Dbg.Assert(false, "Derived dependencies Hashtable must contain a Name key"); - continue; - } - - string dependencyName = (string)dependencyInfo["Name"]; - if (String.IsNullOrEmpty(dependencyName)) - { - Dbg.Assert(false, "Dependency Name must not be null or empty"); - continue; - } - - if (dependencyInfo.ContainsKey("RequiredVersion")) - { - if (!Utils.TryParseVersionOrVersionRange((string)dependencyInfo["RequiredVersion"], out VersionRange dependencyVersion)) - { - dependencyVersion = VersionRange.All; - } - - dependenciesFound.Add(new Dependency(dependencyName, dependencyVersion)); - continue; - } - - if (dependencyInfo.ContainsKey("MinimumVersion") || dependencyInfo.ContainsKey("MaximumVersion")) - { - NuGetVersion minimumVersion = null; - NuGetVersion maximumVersion = null; - bool includeMin = false; - bool includeMax = false; - - if (dependencyInfo.ContainsKey("MinimumVersion") && - !NuGetVersion.TryParse((string)dependencyInfo["MinimumVersion"], out minimumVersion)) - { - VersionRange dependencyAll = VersionRange.All; - dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); - continue; - } - - if (dependencyInfo.ContainsKey("MaximumVersion") && - !NuGetVersion.TryParse((string)dependencyInfo["MaximumVersion"], out maximumVersion)) - { - VersionRange dependencyAll = VersionRange.All; - dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); - continue; - } - - if (minimumVersion != null) - { - includeMin = true; - } - - if (maximumVersion != null) - { - includeMax = true; - } - - VersionRange dependencyVersionRange = new VersionRange( - minVersion: minimumVersion, - includeMinVersion: includeMin, - maxVersion: maximumVersion, - includeMaxVersion: includeMax); - - dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRange)); - continue; - } - - // neither Required, Minimum or Maximum Version provided - VersionRange dependencyVersionRangeAll = VersionRange.All; - dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRangeAll)); - } - else if (dependencyObj.Properties["Name"] != null) - { - string name = dependencyObj.Properties["Name"].Value.ToString(); - - string version = string.Empty; - VersionRange versionRange = VersionRange.All; - - if (dependencyObj.Properties["VersionRange"] != null) - { - version = dependencyObj.Properties["VersionRange"].Value.ToString(); - VersionRange.TryParse(version, out versionRange); - } - - dependenciesFound.Add(new Dependency(name, versionRange)); - } - } - - return dependenciesFound.ToArray(); - } - - private static string ConcatenateVersionWithPrerelease(string version, string prerelease) - { - return Utils.GetNormalizedVersionString(version, prerelease); - } - - - #region Parse Metadata private static methods - - private static string ParseMetadataAuthor(IPackageSearchMetadata pkg) - { - return pkg.Authors; - } - - private static Dependency[] ParseMetadataDependencies(IPackageSearchMetadata pkg) - { - List dependencies = new List(); - foreach(var pkgDependencyGroup in pkg.DependencySets) - { - foreach(var pkgDependencyItem in pkgDependencyGroup.Packages) - { - // check if version range is not null. In case we have package with dependency but no version specified - VersionRange depVersionRange; - if (pkgDependencyItem.VersionRange == null) - { - depVersionRange = VersionRange.All; - } - else - { - depVersionRange = pkgDependencyItem.VersionRange; - } - - Dependency currentDependency = new Dependency(pkgDependencyItem.Id, depVersionRange); - dependencies.Add(currentDependency); - } - } - return dependencies.ToArray(); - } - - private static string ParseMetadataDescription(IPackageSearchMetadata pkg) - { - return pkg.Description; - } - - private static Uri ParseMetadataIconUri(IPackageSearchMetadata pkg) - { - return pkg.IconUrl; - } - - private static bool ParseMetadataIsPrerelease(IPackageSearchMetadata pkg) - { - return pkg.Identity?.Version?.IsPrerelease ?? false; - } - - private static Uri ParseMetadataLicenseUri(IPackageSearchMetadata pkg) - { - return pkg.LicenseUrl; - } - - private static string ParseMetadataName(IPackageSearchMetadata pkg) - { - return pkg.Identity?.Id ?? string.Empty; - } - - private static string ParsePrerelease(IPackageSearchMetadata pkg) - { - return pkg.Identity.Version.ReleaseLabels.Count() > 0 ? - pkg.Identity.Version.ReleaseLabels.FirstOrDefault() : - String.Empty; - } - - private static Uri ParseMetadataProjectUri(IPackageSearchMetadata pkg) - { - return pkg.ProjectUrl; - } - - private static DateTime? ParseMetadataPublishedDate(IPackageSearchMetadata pkg) - { - DateTime? publishDate = null; - DateTimeOffset? pkgPublishedDate = pkg.Published; - if (pkgPublishedDate.HasValue) - { - publishDate = pkgPublishedDate.Value.DateTime; - } - return publishDate; - } - - private static string[] ParseMetadataTags(IPackageSearchMetadata pkg) - { - return pkg.Tags.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); - } - - private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, string repoName, ResourceType? pkgType) - { - // possible type combinations: - // M, C - // M, D - // M - // S - - string[] tags = ParseMetadataTags(pkg); - ResourceType currentPkgType = ResourceType.Module; - - // Check if package came from PSGalleryScripts repo- this indicates that it should have a PSScript tag - // (however some packages that had a wildcard in their name are missing PSScript or PSModule tags) - // but we were able to get the packages by using SearchAsync() with the appropriate Script or Module repository endpoint - // and can check repository endpoint to determine Type. - // Module packages missing tags are accounted for as the default case, and we account for scripts with the following check: - if ((pkgType == null && String.Equals("PSGalleryScripts", repoName, StringComparison.InvariantCultureIgnoreCase)) || - (pkgType != null && pkgType == ResourceType.Script)) - { - // it's a Script resource, so clear default Module tag because a Script resource cannot also be a Module resource - currentPkgType &= ~ResourceType.Module; - currentPkgType |= ResourceType.Script; - } - - // if Name contains wildcard, currently Script and Module tags should be set properly, but need to account for Command and DscResource types too - // if Name does not contain wildcard, GetMetadataAsync() was used, PSGallery only is searched (and pkg will successfully be found - // and returned from there) before PSGalleryScripts can be searched - foreach(string tag in tags) - { - if(String.Equals(tag, "PSScript", StringComparison.InvariantCultureIgnoreCase)) - { - // clear default Module tag, because a Script resource cannot be a Module resource also - currentPkgType &= ~ResourceType.Module; - currentPkgType |= ResourceType.Script; - } - if (tag.StartsWith("PSCommand_")) - { - currentPkgType |= ResourceType.Command; - } - if (String.Equals(tag, "PSIncludes_DscResource", StringComparison.InvariantCultureIgnoreCase)) - { - currentPkgType |= ResourceType.DscResource; - } - } - return currentPkgType; - } - - private static Version ParseMetadataVersion(IPackageSearchMetadata pkg) - { - if (pkg.Identity != null) - { - return pkg.Identity.Version.Version; - } - return null; - } - - #endregion - - #endregion - - #region Private methods - - private PSObject ConvertToCustomObject() - { - // 1.0.0-alpha1 - // 1.0.0.0 - string NormalizedVersion = IsPrerelease ? ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel) : Version.ToString(); - - var additionalMetadata = new PSObject(); - - if (AdditionalMetadata == null) - { - AdditionalMetadata = new Dictionary(); - } - - if (!AdditionalMetadata.ContainsKey(nameof(IsPrerelease))) - { - AdditionalMetadata.Add(nameof(IsPrerelease), IsPrerelease.ToString()); - } - else - { - AdditionalMetadata[nameof(IsPrerelease)] = IsPrerelease.ToString(); - } - - // This is added for V2, V3 does not need it. - if (!AdditionalMetadata.ContainsKey(nameof(NormalizedVersion))) - { - AdditionalMetadata.Add(nameof(NormalizedVersion), NormalizedVersion); - } - else - { - AdditionalMetadata[nameof(NormalizedVersion)] = NormalizedVersion; - } - - foreach (var item in AdditionalMetadata) - { - additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); - } - - var psObject = new PSObject(); - psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(Version), NormalizedVersion)); - psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); - psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(IsPrerelease), IsPrerelease)); - psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); - psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); - psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); - psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes != null ? Includes.ConvertToHashtable() : null)); - psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); - psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider ?? string.Empty)); - psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); - psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation ?? string.Empty)); - - return psObject; - } - - #endregion - } - - #endregion - - #region Test Hooks - - public static class TestHooks - { - public static PSObject ReadPSGetResourceInfo(string filePath) - { - if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - return PSObject.AsPSObject(psGetInfo); - } - - throw new PSInvalidOperationException(errorMsg); - } - - public static void WritePSGetResourceInfo( - string filePath, - PSObject psObjectGetInfo) - { - if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) - { - if (! psGetInfo.TryWrite(filePath, out string errorMsg)) - { - throw new PSInvalidOperationException(errorMsg); - } - - return; - } - - throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); - } - } - - #endregion -} + } + + #endregion + + #region VersionInfo + + public sealed class VersionInfo + { + public VersionInfo( + VersionType versionType, + Version versionNum) + { + VersionType = versionType; + VersionNum = versionNum; + } + + public VersionType VersionType { get; } + public Version VersionNum { get; } + + public override string ToString() => $"{VersionType}: {VersionNum}"; + } + + #endregion + + #region ResourceIncludes + + public sealed class ResourceIncludes + { + #region Properties + + public string[] Cmdlet { get; } + + public string[] Command { get; } + + public string[] DscResource { get; } + + public string[] Function { get; } + + public string[] RoleCapability { get; } + + public string[] Workflow { get; } + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// Provided hashtable has form: + /// Key: Cmdlet + /// Value: ArrayList of Cmdlet name strings + /// Key: Command + /// Value: ArrayList of Command name strings + /// Key: DscResource + /// Value: ArrayList of DscResource name strings + /// Key: Function + /// Value: ArrayList of Function name strings + /// Key: RoleCapability (deprecated for PSGetV3) + /// Value: ArrayList of RoleCapability name strings + /// Key: Workflow (deprecated for PSGetV3) + /// Value: ArrayList of Workflow name strings + /// + /// Hashtable of PSGet includes + internal ResourceIncludes(Hashtable includes) + { + if (includes == null) { return; } + + Cmdlet = GetHashTableItem(includes, nameof(Cmdlet)); + Command = GetHashTableItem(includes, nameof(Command)); + DscResource = GetHashTableItem(includes, nameof(DscResource)); + Function = GetHashTableItem(includes, nameof(Function)); + RoleCapability = GetHashTableItem(includes, nameof(RoleCapability)); + Workflow = GetHashTableItem(includes, nameof(Workflow)); + } + + internal ResourceIncludes() + { + Cmdlet = Utils.EmptyStrArray; + Command = Utils.EmptyStrArray; + DscResource = Utils.EmptyStrArray; + Function = Utils.EmptyStrArray; + RoleCapability = Utils.EmptyStrArray; + Workflow = Utils.EmptyStrArray; + } + + #endregion + + #region Public methods + + public Hashtable ConvertToHashtable() + { + var hashtable = new Hashtable + { + { nameof(Cmdlet), Cmdlet }, + { nameof(Command), Command }, + { nameof(DscResource), DscResource }, + { nameof(Function), Function }, + { nameof(RoleCapability), RoleCapability }, + { nameof(Workflow), Workflow } + }; + + return hashtable; + } + + #endregion + + #region Private methods + + private string[] GetHashTableItem( + Hashtable table, + string name) + { + if (table.ContainsKey(name) && + table[name] is PSObject psObjectItem) + { + return Utils.GetStringArray(psObjectItem.BaseObject as ArrayList); + } + + return null; + } + + #endregion + } + + #endregion + + #region Dependency + + public sealed class Dependency + { + #region Properties + + public string Name { get; } + + public VersionRange VersionRange { get; } + + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// + /// Hashtable of PSGet includes + public Dependency(string dependencyName, VersionRange dependencyVersionRange) + { + Name = dependencyName; + VersionRange = dependencyVersionRange; + } + + #endregion + } + + #endregion + + #region PSResourceInfo + + public sealed class PSResourceInfo + { + #region Properties + + public Dictionary AdditionalMetadata { get; } + public string Author { get; } + public string CompanyName { get; } + public string Copyright { get; } + public Dependency[] Dependencies { get; } + public string Description { get; } + public Uri IconUri { get; } + public ResourceIncludes Includes { get; } + public DateTime? InstalledDate { get; internal set; } + public string InstalledLocation { get; internal set; } + public bool IsPrerelease { get; } + public Uri LicenseUri { get; } + public string Name { get; } + public string PackageManagementProvider { get; } + public string PowerShellGetFormatVersion { get; } + public string PrereleaseLabel { get; } + public Uri ProjectUri { get; } + public DateTime? PublishedDate { get; } + public string ReleaseNotes { get; } + public string Repository { get; } + public string RepositorySourceLocation { get; } + public string[] Tags { get; } + public ResourceType Type { get; } + public DateTime? UpdatedDate { get; } + public Version Version { get; } + + #endregion + + #region Constructors + + private PSResourceInfo() { } + + private PSResourceInfo( + Dictionary additionalMetadata, + string author, + string companyName, + string copyright, + Dependency[] dependencies, + string description, + Uri iconUri, + ResourceIncludes includes, + DateTime? installedDate, + string installedLocation, + bool isPrelease, + Uri licenseUri, + string name, + string packageManagementProvider, + string powershellGetFormatVersion, + string prereleaseLabel, + Uri projectUri, + DateTime? publishedDate, + string releaseNotes, + string repository, + string repositorySourceLocation, + string[] tags, + ResourceType type, + DateTime? updatedDate, + Version version) + { + AdditionalMetadata = additionalMetadata ?? new Dictionary(); + Author = author ?? string.Empty; + CompanyName = companyName ?? string.Empty; + Copyright = copyright ?? string.Empty; + Dependencies = dependencies ?? new Dependency[0]; + Description = description ?? string.Empty; + IconUri = iconUri; + Includes = includes ?? new ResourceIncludes(); + InstalledDate = installedDate; + InstalledLocation = installedLocation ?? string.Empty; + IsPrerelease = isPrelease; + LicenseUri = licenseUri; + Name = name ?? string.Empty; + PackageManagementProvider = packageManagementProvider ?? string.Empty; + PowerShellGetFormatVersion = powershellGetFormatVersion ?? string.Empty; + PrereleaseLabel = prereleaseLabel ?? string.Empty; + ProjectUri = projectUri; + PublishedDate = publishedDate; + ReleaseNotes = releaseNotes ?? string.Empty; + Repository = repository ?? string.Empty; + RepositorySourceLocation = repositorySourceLocation ?? string.Empty; + Tags = tags ?? Utils.EmptyStrArray; + Type = type; + UpdatedDate = updatedDate; + Version = version ?? new Version(); + } + + #endregion + + #region Private fields + private static readonly char[] Delimeter = {' ', ','}; + + #endregion + + #region Public static methods + + /// + /// Writes the PSGetResourceInfo properties to the specified file path as a + /// PowerShell serialized xml file, maintaining compatibility with + /// PowerShellGet v2 file format. + /// + public bool TryWrite( + string filePath, + out string errorMsg) + { + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryWritePSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + var infoXml = PSSerializer.Serialize( + source: ConvertToCustomObject(), + depth: 5); + + System.IO.File.WriteAllText( + path: filePath, + contents: infoXml); + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryWritePSGetInfo: Cannot convert and write the PowerShellGet information to file, with error: {0}", + ex.Message); + + return false; + } + } + + /// + /// Reads a PSGet resource xml (PowerShell serialized) file and returns + /// a PSResourceInfo object containing the file contents. + /// + public static bool TryRead( + string filePath, + out PSResourceInfo psGetInfo, + out string errorMsg) + { + psGetInfo = null; + errorMsg = string.Empty; + + if (string.IsNullOrWhiteSpace(filePath)) + { + errorMsg = "TryReadPSGetInfo: Invalid file path. Filepath cannot be empty or whitespace."; + return false; + } + + try + { + // Read and deserialize information xml file. + var psObjectInfo = (PSObject) PSSerializer.Deserialize( + System.IO.File.ReadAllText( + filePath)); + + var additionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo); + Version version = GetVersionInfo(psObjectInfo, additionalMetadata, out string prereleaseLabel); + + psGetInfo = new PSResourceInfo( + additionalMetadata: additionalMetadata, + author: GetStringProperty(nameof(PSResourceInfo.Author), psObjectInfo), + companyName: GetStringProperty(nameof(PSResourceInfo.CompanyName), psObjectInfo), + copyright: GetStringProperty(nameof(PSResourceInfo.Copyright), psObjectInfo), + dependencies: GetDependencies(GetProperty(nameof(PSResourceInfo.Dependencies), psObjectInfo)), + description: GetStringProperty(nameof(PSResourceInfo.Description), psObjectInfo), + iconUri: GetProperty(nameof(PSResourceInfo.IconUri), psObjectInfo), + includes: new ResourceIncludes(GetProperty(nameof(PSResourceInfo.Includes), psObjectInfo)), + installedDate: GetProperty(nameof(PSResourceInfo.InstalledDate), psObjectInfo), + installedLocation: GetStringProperty(nameof(PSResourceInfo.InstalledLocation), psObjectInfo), + isPrelease: GetProperty(nameof(PSResourceInfo.IsPrerelease), psObjectInfo), + licenseUri: GetProperty(nameof(PSResourceInfo.LicenseUri), psObjectInfo), + name: GetStringProperty(nameof(PSResourceInfo.Name), psObjectInfo), + packageManagementProvider: GetStringProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), + powershellGetFormatVersion: GetStringProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), + prereleaseLabel: prereleaseLabel, + projectUri: GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), + publishedDate: GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), + releaseNotes: GetStringProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), + repository: GetStringProperty(nameof(PSResourceInfo.Repository), psObjectInfo), + repositorySourceLocation: GetStringProperty(nameof(PSResourceInfo.RepositorySourceLocation), psObjectInfo), + tags: Utils.GetStringArray(GetProperty(nameof(PSResourceInfo.Tags), psObjectInfo)), + type: Enum.TryParse( + GetProperty(nameof(PSResourceInfo.Type), psObjectInfo) ?? nameof(ResourceType.Module), + out ResourceType currentReadType) + ? currentReadType : ResourceType.Module, + updatedDate: GetProperty(nameof(PSResourceInfo.UpdatedDate), psObjectInfo), + version: version); + + return true; + } + catch(Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot read the PowerShellGet information file with error: {0}", + ex.Message); + + return false; + } + } + + private static string GetStringProperty( + string name, + PSObject psObjectInfo) + { + return GetProperty(name, psObjectInfo) ?? string.Empty; + } + + private static Version GetVersionInfo( + PSObject psObjectInfo, + Dictionary additionalMetadata, + out string prereleaseLabel) + { + string versionString = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); + prereleaseLabel = String.Empty; + + if (!String.IsNullOrEmpty(versionString) || + additionalMetadata.TryGetValue("NormalizedVersion", out versionString)) + { + string pkgVersion = versionString; + if (versionString.Contains("-")) + { + // versionString: "1.2.0-alpha1" + string[] versionStringParsed = versionString.Split('-'); + if (versionStringParsed.Length == 1) + { + // versionString: "1.2.0-" (unlikely, at least should not be from our PSResourceInfo.TryWrite()) + pkgVersion = versionStringParsed[0]; + } + else + { + // versionStringParsed.Length > 1 (because string contained '-' so couldn't be 0) + // versionString: "1.2.0-alpha1" + pkgVersion = versionStringParsed[0]; + prereleaseLabel = versionStringParsed[1]; + } + } + + // at this point, version is normalized (i.e either "1.2.0" (if part of prerelease) or "1.2.0.0" otherwise) + // parse the pkgVersion parsed out above into a System.Version object + if (!Version.TryParse(pkgVersion, out Version parsedVersion)) + { + prereleaseLabel = String.Empty; + return null; + } + else + { + return parsedVersion; + } + } + + // version could not be parsed as string, it was written to XML file as a System.Version object + // V3 code briefly did so, I believe so we provide support for it + prereleaseLabel = String.Empty; + return GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); + } + + + public static bool TryConvert( + IPackageSearchMetadata metadataToParse, + out PSResourceInfo psGetInfo, + string repositoryName, + ResourceType? type, + out string errorMsg) + { + psGetInfo = null; + errorMsg = String.Empty; + + if (metadataToParse == null) + { + errorMsg = "TryConvertPSResourceInfo: Invalid IPackageSearchMetadata object. Object cannot be null."; + return false; + } + + try + { + psGetInfo = new PSResourceInfo( + additionalMetadata: null, + author: ParseMetadataAuthor(metadataToParse), + companyName: null, + copyright: null, + dependencies: ParseMetadataDependencies(metadataToParse), + description: ParseMetadataDescription(metadataToParse), + iconUri: ParseMetadataIconUri(metadataToParse), + includes: null, + installedDate: null, + installedLocation: null, + isPrelease: ParseMetadataIsPrerelease(metadataToParse), + licenseUri: ParseMetadataLicenseUri(metadataToParse), + name: ParseMetadataName(metadataToParse), + packageManagementProvider: null, + powershellGetFormatVersion: null, + prereleaseLabel: ParsePrerelease(metadataToParse), + projectUri: ParseMetadataProjectUri(metadataToParse), + publishedDate: ParseMetadataPublishedDate(metadataToParse), + releaseNotes: null, + repository: repositoryName, + repositorySourceLocation: null, + tags: ParseMetadataTags(metadataToParse), + type: ParseMetadataType(metadataToParse, repositoryName, type), + updatedDate: null, + version: ParseMetadataVersion(metadataToParse)); + + return true; + } + catch (Exception ex) + { + errorMsg = string.Format( + CultureInfo.InvariantCulture, + @"TryReadPSGetInfo: Cannot parse PSResourceInfo from IPackageSearchMetadata with error: {0}", + ex.Message); + return false; + } + } + + #endregion + + #region Private static methods + + private static T ConvertToType(PSObject psObject) + { + // We only convert Dictionary types. + if (typeof(T) != typeof(Dictionary)) + { + return default(T); + } + + var dict = new Dictionary(); + foreach (var prop in psObject.Properties) + { + dict.Add(prop.Name, prop.Value.ToString()); + } + + return (T)Convert.ChangeType(dict, typeof(T)); + } + + private static T GetProperty( + string Name, + PSObject psObjectInfo) + { + var val = psObjectInfo.Properties[Name]?.Value; + if (val == null) + { + return default(T); + } + + switch (val) + { + case T valType: + return valType; + + case PSObject valPSObject: + switch (valPSObject.BaseObject) + { + case T valBase: + return valBase; + + case PSCustomObject _: + // A base object of PSCustomObject means this is additional metadata + // and type T should be Dictionary. + return ConvertToType(valPSObject); + + default: + return default(T); + } + + default: + return default(T); + } + } + + private static string GetPrereleaseLabel(Version version) + { + string versionAsString = version.ToString(); + + if (!versionAsString.Contains("-")) + { + // no prerelease label present + return String.Empty; + } + + string[] prereleaseParsed = versionAsString.Split('-'); + if (prereleaseParsed.Length <= 1) + { + return String.Empty; + } + + string prereleaseString = prereleaseParsed[1]; + Regex prereleasePattern = new Regex("^[a-zA-Z0-9]+$"); + if (!prereleasePattern.IsMatch(prereleaseString)) + { + return String.Empty; + } + + return prereleaseString; + } + + private static Dependency[] GetDependencies(ArrayList dependencyInfos) + { + List dependenciesFound = new List(); + if (dependencyInfos == null) { return dependenciesFound.ToArray(); } + + + foreach(PSObject dependencyObj in dependencyInfos) + { + // The dependency object can be a string or a hashtable + // eg: + // RequiredModules = @('PSGetTestDependency1') + // RequiredModules = @(@{ModuleName='PackageManagement';ModuleVersion='1.0.0.1'}) + if (dependencyObj.BaseObject is Hashtable dependencyInfo) + { + if (!dependencyInfo.ContainsKey("Name")) + { + Dbg.Assert(false, "Derived dependencies Hashtable must contain a Name key"); + continue; + } + + string dependencyName = (string)dependencyInfo["Name"]; + if (String.IsNullOrEmpty(dependencyName)) + { + Dbg.Assert(false, "Dependency Name must not be null or empty"); + continue; + } + + if (dependencyInfo.ContainsKey("RequiredVersion")) + { + if (!Utils.TryParseVersionOrVersionRange((string)dependencyInfo["RequiredVersion"], out VersionRange dependencyVersion)) + { + dependencyVersion = VersionRange.All; + } + + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersion)); + continue; + } + + if (dependencyInfo.ContainsKey("MinimumVersion") || dependencyInfo.ContainsKey("MaximumVersion")) + { + NuGetVersion minimumVersion = null; + NuGetVersion maximumVersion = null; + bool includeMin = false; + bool includeMax = false; + + if (dependencyInfo.ContainsKey("MinimumVersion") && + !NuGetVersion.TryParse((string)dependencyInfo["MinimumVersion"], out minimumVersion)) + { + VersionRange dependencyAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + continue; + } + + if (dependencyInfo.ContainsKey("MaximumVersion") && + !NuGetVersion.TryParse((string)dependencyInfo["MaximumVersion"], out maximumVersion)) + { + VersionRange dependencyAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyAll)); + continue; + } + + if (minimumVersion != null) + { + includeMin = true; + } + + if (maximumVersion != null) + { + includeMax = true; + } + + VersionRange dependencyVersionRange = new VersionRange( + minVersion: minimumVersion, + includeMinVersion: includeMin, + maxVersion: maximumVersion, + includeMaxVersion: includeMax); + + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRange)); + continue; + } + + // neither Required, Minimum or Maximum Version provided + VersionRange dependencyVersionRangeAll = VersionRange.All; + dependenciesFound.Add(new Dependency(dependencyName, dependencyVersionRangeAll)); + } + else if (dependencyObj.Properties["Name"] != null) + { + string name = dependencyObj.Properties["Name"].Value.ToString(); + + string version = string.Empty; + VersionRange versionRange = VersionRange.All; + + if (dependencyObj.Properties["VersionRange"] != null) + { + version = dependencyObj.Properties["VersionRange"].Value.ToString(); + VersionRange.TryParse(version, out versionRange); + } + + dependenciesFound.Add(new Dependency(name, versionRange)); + } + } + + return dependenciesFound.ToArray(); + } + + private static string ConcatenateVersionWithPrerelease(string version, string prerelease) + { + return Utils.GetNormalizedVersionString(version, prerelease); + } + + + #region Parse Metadata private static methods + + private static string ParseMetadataAuthor(IPackageSearchMetadata pkg) + { + return pkg.Authors; + } + + private static Dependency[] ParseMetadataDependencies(IPackageSearchMetadata pkg) + { + List dependencies = new List(); + foreach(var pkgDependencyGroup in pkg.DependencySets) + { + foreach(var pkgDependencyItem in pkgDependencyGroup.Packages) + { + // check if version range is not null. In case we have package with dependency but no version specified + VersionRange depVersionRange; + if (pkgDependencyItem.VersionRange == null) + { + depVersionRange = VersionRange.All; + } + else + { + depVersionRange = pkgDependencyItem.VersionRange; + } + + Dependency currentDependency = new Dependency(pkgDependencyItem.Id, depVersionRange); + dependencies.Add(currentDependency); + } + } + return dependencies.ToArray(); + } + + private static string ParseMetadataDescription(IPackageSearchMetadata pkg) + { + return pkg.Description; + } + + private static Uri ParseMetadataIconUri(IPackageSearchMetadata pkg) + { + return pkg.IconUrl; + } + + private static bool ParseMetadataIsPrerelease(IPackageSearchMetadata pkg) + { + return pkg.Identity?.Version?.IsPrerelease ?? false; + } + + private static Uri ParseMetadataLicenseUri(IPackageSearchMetadata pkg) + { + return pkg.LicenseUrl; + } + + private static string ParseMetadataName(IPackageSearchMetadata pkg) + { + return pkg.Identity?.Id ?? string.Empty; + } + + private static string ParsePrerelease(IPackageSearchMetadata pkg) + { + return pkg.Identity.Version.ReleaseLabels.Count() > 0 ? + pkg.Identity.Version.ReleaseLabels.FirstOrDefault() : + String.Empty; + } + + private static Uri ParseMetadataProjectUri(IPackageSearchMetadata pkg) + { + return pkg.ProjectUrl; + } + + private static DateTime? ParseMetadataPublishedDate(IPackageSearchMetadata pkg) + { + DateTime? publishDate = null; + DateTimeOffset? pkgPublishedDate = pkg.Published; + if (pkgPublishedDate.HasValue) + { + publishDate = pkgPublishedDate.Value.DateTime; + } + return publishDate; + } + + private static string[] ParseMetadataTags(IPackageSearchMetadata pkg) + { + return pkg.Tags.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + } + + private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, string repoName, ResourceType? pkgType) + { + // possible type combinations: + // M, C + // M, D + // M + // S + + string[] tags = ParseMetadataTags(pkg); + ResourceType currentPkgType = ResourceType.Module; + + // Check if package came from PSGalleryScripts repo- this indicates that it should have a PSScript tag + // (however some packages that had a wildcard in their name are missing PSScript or PSModule tags) + // but we were able to get the packages by using SearchAsync() with the appropriate Script or Module repository endpoint + // and can check repository endpoint to determine Type. + // Module packages missing tags are accounted for as the default case, and we account for scripts with the following check: + if ((pkgType == null && String.Equals("PSGalleryScripts", repoName, StringComparison.InvariantCultureIgnoreCase)) || + (pkgType != null && pkgType == ResourceType.Script)) + { + // it's a Script resource, so clear default Module tag because a Script resource cannot also be a Module resource + currentPkgType &= ~ResourceType.Module; + currentPkgType |= ResourceType.Script; + } + + // if Name contains wildcard, currently Script and Module tags should be set properly, but need to account for Command and DscResource types too + // if Name does not contain wildcard, GetMetadataAsync() was used, PSGallery only is searched (and pkg will successfully be found + // and returned from there) before PSGalleryScripts can be searched + foreach(string tag in tags) + { + if(String.Equals(tag, "PSScript", StringComparison.InvariantCultureIgnoreCase)) + { + // clear default Module tag, because a Script resource cannot be a Module resource also + currentPkgType &= ~ResourceType.Module; + currentPkgType |= ResourceType.Script; + } + if (tag.StartsWith("PSCommand_")) + { + currentPkgType |= ResourceType.Command; + } + if (String.Equals(tag, "PSIncludes_DscResource", StringComparison.InvariantCultureIgnoreCase)) + { + currentPkgType |= ResourceType.DscResource; + } + } + return currentPkgType; + } + + private static Version ParseMetadataVersion(IPackageSearchMetadata pkg) + { + if (pkg.Identity != null) + { + return pkg.Identity.Version.Version; + } + return null; + } + + #endregion + + #endregion + + #region Private methods + + private PSObject ConvertToCustomObject() + { + // 1.0.0-alpha1 + // 1.0.0.0 + string NormalizedVersion = IsPrerelease ? ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel) : Version.ToString(); + + var additionalMetadata = new PSObject(); + + if (!AdditionalMetadata.ContainsKey(nameof(IsPrerelease))) + { + AdditionalMetadata.Add(nameof(IsPrerelease), IsPrerelease.ToString()); + } + else + { + AdditionalMetadata[nameof(IsPrerelease)] = IsPrerelease.ToString(); + } + + // This is added for V2, V3 does not need it. + if (!AdditionalMetadata.ContainsKey(nameof(NormalizedVersion))) + { + AdditionalMetadata.Add(nameof(NormalizedVersion), NormalizedVersion); + } + else + { + AdditionalMetadata[nameof(NormalizedVersion)] = NormalizedVersion; + } + + foreach (var item in AdditionalMetadata) + { + additionalMetadata.Properties.Add(new PSNoteProperty(item.Key, item.Value)); + } + + var psObject = new PSObject(); + psObject.Properties.Add(new PSNoteProperty(nameof(Name), Name)); + psObject.Properties.Add(new PSNoteProperty(nameof(Version), NormalizedVersion)); + psObject.Properties.Add(new PSNoteProperty(nameof(Type), Type)); + psObject.Properties.Add(new PSNoteProperty(nameof(Description), Description)); + psObject.Properties.Add(new PSNoteProperty(nameof(Author), Author)); + psObject.Properties.Add(new PSNoteProperty(nameof(CompanyName), CompanyName)); + psObject.Properties.Add(new PSNoteProperty(nameof(Copyright), Copyright)); + psObject.Properties.Add(new PSNoteProperty(nameof(PublishedDate), PublishedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledDate), InstalledDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(IsPrerelease), IsPrerelease)); + psObject.Properties.Add(new PSNoteProperty(nameof(UpdatedDate), UpdatedDate)); + psObject.Properties.Add(new PSNoteProperty(nameof(LicenseUri), LicenseUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(ProjectUri), ProjectUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(IconUri), IconUri)); + psObject.Properties.Add(new PSNoteProperty(nameof(Tags), Tags)); + psObject.Properties.Add(new PSNoteProperty(nameof(Includes), Includes.ConvertToHashtable())); + psObject.Properties.Add(new PSNoteProperty(nameof(PowerShellGetFormatVersion), PowerShellGetFormatVersion)); + psObject.Properties.Add(new PSNoteProperty(nameof(ReleaseNotes), ReleaseNotes)); + psObject.Properties.Add(new PSNoteProperty(nameof(Dependencies), Dependencies)); + psObject.Properties.Add(new PSNoteProperty(nameof(RepositorySourceLocation), RepositorySourceLocation)); + psObject.Properties.Add(new PSNoteProperty(nameof(Repository), Repository)); + psObject.Properties.Add(new PSNoteProperty(nameof(PackageManagementProvider), PackageManagementProvider)); + psObject.Properties.Add(new PSNoteProperty(nameof(AdditionalMetadata), additionalMetadata)); + psObject.Properties.Add(new PSNoteProperty(nameof(InstalledLocation), InstalledLocation)); + + return psObject; + } + + #endregion + } + + #endregion + + #region Test Hooks + + public static class TestHooks + { + public static PSObject ReadPSGetResourceInfo(string filePath) + { + if (PSResourceInfo.TryRead(filePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + return PSObject.AsPSObject(psGetInfo); + } + + throw new PSInvalidOperationException(errorMsg); + } + + public static void WritePSGetResourceInfo( + string filePath, + PSObject psObjectGetInfo) + { + if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) + { + if (! psGetInfo.TryWrite(filePath, out string errorMsg)) + { + throw new PSInvalidOperationException(errorMsg); + } + + return; + } + + throw new PSArgumentException("psObjectGetInfo argument is not a PSGetResourceInfo type."); + } + } + + #endregion +} diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 487e14f05..60dda60c7 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -201,7 +201,7 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) // finally: check to see if there's anything left in the parent directory, if not, delete that as well try { - if (Directory.GetDirectories(dir.Parent.FullName).Length == 0) + if (Utils.GetSubDirectories(dir.Parent.FullName).Length == 0) { Directory.Delete(dir.Parent.FullName, true); } diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index 12afc4e14..2da1a284a 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -29,7 +29,7 @@ class UnregisterPSResourceRepository : PSCmdlet ValueFromPipelineByPropertyName = true)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] - public string[] Name { get; set; } = new string[0]; + public string[] Name { get; set; } = Utils.EmptyStrArray; #endregion diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 04de32228..050c286e8 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -16,55 +16,53 @@ namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { internal static class Utils { - public static void WriteVerboseOnCmdlet( - PSCmdlet cmdlet, - string message) + #region String fields + + public static readonly string[] EmptyStrArray = Array.Empty(); + + #endregion + + #region String methods + + public static string TrimQuotes(string name) { - try - { - cmdlet.InvokeCommand.InvokeScript( - script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { message }); - } - catch { } + return name.Trim('\'', '"'); } - public static string GetNormalizedVersionString( - string versionString, - string prerelease - ) + public static string QuoteName(string name) { - // versionString may be like 1.2.0.0 or 1.2.0 - // prerelease may be null or "alpha1" - // possible passed in examples: - // versionString: "1.2.0" prerelease: "alpha1" - // versionString: "1.2.0" prerelease: "" <- doubtful though - // versionString: "1.2.0.0" prerelease: "alpha1" - // versionString: "1.2.0.0" prerelease: "" - - if (String.IsNullOrEmpty(prerelease)) + bool quotesNeeded = false; + foreach (var c in name) { - return versionString; + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } } - int numVersionDigits = versionString.Split('.').Count(); - - if (numVersionDigits == 3) + if (!quotesNeeded) { - // versionString: "1.2.0" prerelease: "alpha1" - return versionString + "-" + prerelease; + return name; } - else if (numVersionDigits == 4) + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) { - // versionString: "1.2.0.0" prerelease: "alpha1" - return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; + strArray[i] = list[i] as string; } - return versionString; + return strArray; } public static string[] FilterOutWildcardNames( @@ -102,48 +100,43 @@ public static string[] FilterOutWildcardNames( errorMsgs = errorMsgList.ToArray(); return errorFreeNames.ToArray(); } + + #endregion - #region Public methods + #region Version methods - public static string TrimQuotes(string name) + public static string GetNormalizedVersionString( + string versionString, + string prerelease) { - return name.Trim('\'', '"'); - } + // versionString may be like 1.2.0.0 or 1.2.0 + // prerelease may be null or "alpha1" + // possible passed in examples: + // versionString: "1.2.0" prerelease: "alpha1" + // versionString: "1.2.0" prerelease: "" <- doubtful though + // versionString: "1.2.0.0" prerelease: "alpha1" + // versionString: "1.2.0.0" prerelease: "" - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) + if (String.IsNullOrEmpty(prerelease)) { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } + return versionString; } - if (!quotesNeeded) + int numVersionDigits = versionString.Split('.').Count(); + + if (numVersionDigits == 3) { - return name; + // versionString: "1.2.0" prerelease: "alpha1" + return versionString + "-" + prerelease; } - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i < list.Count; i++) + else if (numVersionDigits == 4) { - strArray[i] = list[i] as string; + // versionString: "1.2.0.0" prerelease: "alpha1" + return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; } - return strArray; + return versionString; } public static bool TryParseVersionOrVersionRange( @@ -178,6 +171,34 @@ public static bool TryParseVersionOrVersionRange( return VersionRange.TryParse(version, out versionRange); } + #endregion + + #region Path methods + + public static string[] GetSubDirectories(string dirPath) + { + try + { + return Directory.GetDirectories(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string[] GetDirectoryFiles(string dirPath) + { + try + { + return Directory.GetFiles(dirPath); + } + catch + { + return EmptyStrArray; + } + } + public static string GetInstalledPackageName(string pkgPath) { if (string.IsNullOrEmpty(pkgPath)) @@ -240,7 +261,7 @@ public static List GetAllResourcePaths(PSCmdlet psCmdlet) { try { - pathsToSearch.AddRange(Directory.GetFiles(path)); + pathsToSearch.AddRange(GetDirectoryFiles(path)); } catch (Exception e) { @@ -251,7 +272,7 @@ public static List GetAllResourcePaths(PSCmdlet psCmdlet) { try { - pathsToSearch.AddRange(Directory.GetDirectories(path)); + pathsToSearch.AddRange(GetSubDirectories(path)); } catch (Exception e) { @@ -270,7 +291,6 @@ public static List GetAllResourcePaths(PSCmdlet psCmdlet) return pathsToSearch; } - // Find all potential installation paths given a scope public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType scope) { @@ -311,17 +331,9 @@ public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType return installationPaths; } - private static string GetResourceNameFromPath(string path) - { - // Resource paths may end in a directory or script file name. - // Directory name is the same as the resource name. - // Script file name is the resource name without the file extension. - // ./Modules/Microsoft.PowerShell.Test-Module : Microsoft.PowerShell.Test-Module - // ./Scripts/Microsoft.PowerShell.Test-Script.ps1 : Microsoft.PowerShell.Test-Script - var resourceName = Path.GetFileName(path); - return Path.GetExtension(resourceName).Equals(".ps1", StringComparison.OrdinalIgnoreCase) - ? Path.GetFileNameWithoutExtension(resourceName) : resourceName; - } + #endregion + + #region Manifest methods public static Hashtable ParseModuleManifest(string moduleFileInfo, PSCmdlet cmdletPassedIn) { @@ -361,6 +373,27 @@ public static Hashtable ParseModuleManifest(string moduleFileInfo, PSCmdlet cmdl return parsedMetadataHash; } + + #endregion + + #region Misc methods + + public static void WriteVerboseOnCmdlet( + PSCmdlet cmdlet, + string message) + { + try + { + cmdlet.InvokeCommand.InvokeScript( + script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { message }); + } + catch { } + } + #endregion } } From e1d2b2fed190443d916b1b822c76bb7d659e94a8 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 16 Jul 2021 14:55:05 -0700 Subject: [PATCH 042/276] Fix save psresource tests by using TestDrive (#415) * Fix save psresource tests by using TestDrive * Fix failing tests on WindowsPowerShell --- src/code/FindPSResource.cs | 2 +- src/code/GetHelper.cs | 35 +++--- src/code/InstallHelper.cs | 2 +- src/code/InstallPSResource.cs | 12 +- src/code/PublishPSResource.cs | 22 ++-- src/code/SavePSResource.cs | 34 +++--- src/code/UninstallPSResource.cs | 4 +- test/InstallPSResource.Tests.ps1 | 2 +- test/PSGetTestUtils.psm1 | 7 -- test/SavePSResource.Tests.ps1 | 189 +++++++++++++++---------------- 10 files changed, 157 insertions(+), 152 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 1c9bf2dbc..12b3f4cb7 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -16,7 +16,6 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// It returns PSResourceInfo objects which describe each resource item found. /// Other parameters allow the returned results to be filtered by item Type and Tag. ///
- [Cmdlet(VerbsCommon.Find, "PSResource", DefaultParameterSetName = ResourceNameParameterSet, @@ -25,6 +24,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets public sealed class FindPSResource : PSCmdlet { #region Members + private const string ResourceNameParameterSet = "ResourceNameParameterSet"; private const string CommandNameParameterSet = "CommandNameParameterSet"; private const string DscResourceNameParameterSet = "DscResourceNameParameterSet"; diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 6eae2e68a..f32d8a03f 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -140,7 +140,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li else if (File.Exists(pkgPath)) { // if it's a script - if (versionRange == VersionRange.All) + if (versionRange == null || versionRange == VersionRange.All) { // yield results then continue with this iteration of the loop yield return pkgPath; @@ -178,41 +178,38 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // Create package object for each found resource directory public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary scriptDictionary) { - string xmlFilePath; - var parentDir = new DirectoryInfo(pkgPath).Parent; - - // find package name - string pkgName = Utils.GetInstalledPackageName(pkgPath); - _cmdletPassedIn.WriteDebug(string.Format("OutputPackageObject:: package name is {0}.", pkgName)); - // Find xml file - // if the package path is in the deserialized script dictionary, just return that + // If the package path is in the deserialized script dictionary, just return that if (scriptDictionary.ContainsKey(pkgPath)) { return scriptDictionary[pkgPath]; } - // else if the pkgName from pkgpath is a script, find the xml file - else if (File.Exists(pkgPath)) + + // If the pkgName from pkgpath is a script, find the xml file + string pkgName = Utils.GetInstalledPackageName(pkgPath); + string xmlFilePath; + if (File.Exists(pkgPath)) { - xmlFilePath = System.IO.Path.Combine(parentDir.ToString(), "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); + // Package path is a script file + xmlFilePath = System.IO.Path.Combine( + (new DirectoryInfo(pkgPath).Parent).FullName, + "InstalledScriptInfos", + $"{pkgName}_InstalledScriptInfo.xml"); } - // else we assume it's a module, and look for the xml path that way else { + // Otherwise assume it's a module, and look for the xml path that way xmlFilePath = System.IO.Path.Combine(pkgPath, "PSGetModuleInfo.xml"); } // Read metadata from XML and parse into PSResourceInfo object _cmdletPassedIn.WriteVerbose(string.Format("Reading package metadata from: '{0}'", xmlFilePath)); - if (!TryRead(xmlFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - _cmdletPassedIn.WriteVerbose(errorMsg); - } - else + if (TryRead(xmlFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) { - _cmdletPassedIn.WriteDebug(string.Format("Found module XML: '{0}'", xmlFilePath)); return psGetInfo; } + _cmdletPassedIn.WriteVerbose( + $"Reading metadata for package {pkgName} failed with error: {errorMsg}"); return null; } diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index b0bae2717..1bde963d9 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -418,7 +418,7 @@ private List InstallPackage(IEnumerable pkgsToInstall, s MoveFilesIntoInstallPath(p, isScript, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); - _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}'", p.Name)); + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", p.Name, installPath)); pkgsSuccessfullyInstalled.Add(p.Name); } catch (Exception e) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 74f2068f0..3d750ad01 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -19,7 +19,8 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets public sealed class InstallPSResource : PSCmdlet { - #region parameters + #region Parameters + /// /// Specifies the exact names of resources to install from a repository. /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. @@ -85,17 +86,21 @@ class InstallPSResource : PSCmdlet /// [Parameter(ParameterSetName = NameParameterSet)] public SwitchParameter AcceptLicense { get; set; } + #endregion - #region members + #region Members + private const string NameParameterSet = "NameParameterSet"; private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet"; private const string RequiredResourceParameterSet = "RequiredResourceParameterSet"; List _pathsToInstallPkg; VersionRange _versionRange; + #endregion - #region Methods + #region Method overrides + protected override void BeginProcessing() { // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. @@ -165,6 +170,7 @@ protected override void ProcessRecord() break; } } + #endregion } } diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index d8dca1118..5afc9ed62 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -25,10 +25,8 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// /// Publishes a module, script, or nupkg to a designated repository. /// - [Cmdlet(VerbsData.Publish, "PSResource", SupportsShouldProcess = true, - HelpUri = "")] - public sealed - class PublishPSResource : PSCmdlet + [Cmdlet(VerbsData.Publish, "PSResource", SupportsShouldProcess = true)] + public sealed class PublishPSResource : PSCmdlet { #region Parameters @@ -44,6 +42,7 @@ class PublishPSResource : PSCmdlet ///
[Parameter()] [ValidateNotNullOrEmpty] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] public string Repository { get; set; } /// @@ -168,12 +167,16 @@ public PSCredential ProxyCredential { #endregion - #region members + #region Members + private NuGetVersion _pkgVersion; private string _pkgName; private static char[] _PathSeparators = new [] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; + #endregion + #region Method overrides + protected override void ProcessRecord() { string moduleManifestOrScriptPath; @@ -318,7 +321,6 @@ protected override void ProcessRecord() string repositoryUrl = repository.Url.AbsoluteUri; - // Check if dependencies already exist within the repo if: // 1) the resource to publish has dependencies and // 2) the -SkipDependenciesCheck flag is not passed in @@ -390,6 +392,10 @@ protected override void ProcessRecord() } } + #endregion + + #region Private methods + private bool IsValidModuleManifest(string moduleManifestPath) { var isValid = false; @@ -608,7 +614,7 @@ private string CreateNuspec( Powershell_black_64.png https://github.com/PowerShell/PowerShell Example description here - Microsoft Corporation. All rights reserved. + Copyright (c) Microsoft Corporation. All rights reserved. en-US PowerShell @@ -923,4 +929,6 @@ private void PushNupkg(string outputNupkgDir, string repoUrl) } } } + + #endregion } diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 626721530..ef89b431f 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -16,12 +16,18 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// The Save-PSResource cmdlet saves a resource to a machine. /// It returns nothing. /// - - [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, HelpUri = "")] - public sealed - class SavePSResource : PSCmdlet + [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] + public sealed class SavePSResource : PSCmdlet { - #region parameters + #region Members + + private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectSet = "InputObjectSet"; + VersionRange _versionRange; + + #endregion + + #region Parameters /// /// Specifies the exact names of resources to save from a repository. @@ -50,6 +56,7 @@ class SavePSResource : PSCmdlet [Parameter(ParameterSetName = NameParameterSet)] // todo: add tab completion (look at get-psresourcerepository at the name parameter) [ValidateNotNullOrEmpty] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] public string[] Repository { get; set; } /// @@ -108,23 +115,21 @@ public string Path /// /// Used for pipeline input. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "InputObjectSet")] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = InputObjectSet)] [ValidateNotNullOrEmpty] public object[] InputObject { set; get; } - #endregion - #region members - private const string NameParameterSet = "NameParameterSet"; - private const string InputObjectSet = "InputObjectSet"; - VersionRange _versionRange; #endregion - #region Methods + #region Method overrides + protected override void BeginProcessing() { // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. // an exact version will be formatted into a version range. - if (ParameterSetName.Equals("NameParameterSet") && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + if (ParameterSetName.Equals("NameParameterSet") && + Version != null && + !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) { var exMessage = "Argument for -Version parameter is not in the proper format."; var ex = new ArgumentException(exMessage); @@ -176,6 +181,7 @@ protected override void ProcessRecord() break; } } + #endregion } -} \ No newline at end of file +} diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 60dda60c7..717b07358 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -188,12 +188,12 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) } DirectoryInfo dir = new DirectoryInfo(pkgPath); - dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; + dir.Attributes &= ~FileAttributes.ReadOnly; try { // delete recursively - dir.Delete(true); + Directory.Delete(pkgPath, recursive: true); WriteVerbose(string.Format("Successfully uninstalled '{0}' from path '{1}'", pkgName, dir.FullName)); successfullyUninstalledPkg = true; diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 0f4cd7a29..e8f604166 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -15,7 +15,7 @@ Describe 'Test Install-PSResource for Module' { AfterEach { Uninstall-PSResource "TestModule", "TestModule99", "myTestModule", "myTestModule2", "testModulePrerelease", - "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule" + "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule" -Force -ErrorAction SilentlyContinue } AfterAll { diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index 9f2bf557d..f3410ffaf 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -166,13 +166,6 @@ function Get-RemoveTestDirs { } } -function Create-TemporaryDirectory { - $path = [System.IO.Path]::GetTempPath() - $child = [System.Guid]::NewGuid() - - return New-Item -ItemType Directory -Path (Join-Path $path $child) -} - function Get-NewPSResourceRepositoryFile { # register our own repositories with desired priority $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 64a619f0a..6a20641e3 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -12,17 +12,13 @@ Describe 'Test Save-PSResource for PSResources' { Get-NewPSResourceRepositoryFile Register-LocalRepos - $TempDir = Create-TemporaryDirectory + $SaveDir = Join-Path $TestDrive 'SavedResources' + New-Item -Item Directory $SaveDir -Force } AfterEach { - # Delete all files and subdirectories in $Tempdir, but keep the directory $Tempdir - try { - Get-ChildItem -Path $TempDir -Force | foreach { $_.Delete($true)} - } - catch { - Get-ChildItem -Path $TempDir -Force | foreach { $_.Delete()} - } + # Delte contents of save directory + Remove-Item -Path (Join-Path $SaveDir '*') -Recurse -Force -ErrorAction SilentlyContinue } AfterAll { @@ -30,68 +26,65 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save specific module resource by name" { - Save-PSResource -Name "TestModule" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + Save-PSResource -Name "TestModule" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 } It "Save specific script resource by name" { - Save-PSResource -Name "TestTestScript" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestTestScript.ps1" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + Save-PSResource -Name "TestTestScript" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestTestScript.ps1" + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 } It "Save multiple resources by name" { $pkgNames = @("TestModule","TestModule99") - Save-PSResource -Name $pkgNames -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be @("TestModule","TestModule99") - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + Save-PSResource -Name $pkgNames -Repository $TestGalleryName -Path $SaveDir + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "TestModule" -or $_.Name -eq "TestModule99" } + $pkgDirs.Count | Should -Be 2 + (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 + (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 } It "Should not save resource given nonexistant name" { - Save-PSResource -Name NonExistantModule -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -BeNullOrEmpty + Save-PSResource -Name NonExistentModule -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "NonExistentModule" + $pkgDir.Name | Should -BeNullOrEmpty } # Do some version testing, but Find-PSResource should be doing thorough testing It "Should save resource given name and exact version" { - Save-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.2.0" + Save-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.2.0" } It "Should save resource given name and exact version with bracket syntax" { - Save-PSResource -Name "TestModule" -Version "[1.2.0]" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.2.0" + Save-PSResource -Name "TestModule" -Version "[1.2.0]" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.2.0" } It "Should save resource given name and exact range inclusive [1.0.0, 1.1.1]" { - Save-PSResource -Name "TestModule" -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.1.1" + Save-PSResource -Name "TestModule" -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.1.1" } It "Should save resource given name and exact range exclusive (1.0.0, 1.1.1)" { - Save-PSResource -Name "TestModule" -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.1" + Save-PSResource -Name "TestModule" -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.1" } It "Should not save resource with incorrectly formatted version such as " -TestCases @( @@ -100,56 +93,55 @@ Describe 'Test Save-PSResource for PSResources' { ) { param($Version, $Description) - Save-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName -Path $TempDir - $res = Get-ChildItem $TempDir - $res | Should -BeNullOrEmpty + Save-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -BeNullOrEmpty } It "Save resource when given Name, Version '*', should install the latest version" { - Save-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.3.0" + Save-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" } It "Save resource with latest (including prerelease) version given Prerelease parameter" { - Save-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModulePrerelease" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "0.0.1" + Save-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModulePrerelease" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "0.0.1" } It "Save a module with a dependency" { - Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be @("PSGetTestDependency1","PSGetTestModule") - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } + $pkgDirs.Count | Should -Be 2 + (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 + (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 } It "Save resource via InputObject by piping from Find-PSresource" { - Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Save-PSResource -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.3.0" + Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" } It "Save resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { - Set-PSResourceRepository PoshTestGallery -Trusted:$false - - Save-PSResource -Name "TestModule" -Repository $TestGalleryName -TrustRepository -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 - $pkgVersion = Get-ChildItem $pkg - $pkgVersion.Name | Should -Be "1.3.0" - - Set-PSResourceRepository PoshTestGallery -Trusted + try { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + Save-PSResource -Name "TestModule" -Repository $TestGalleryName -TrustRepository -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" + } + finally { + Set-PSResourceRepository PoshTestGallery -Trusted + } } It "Save resource from local repository given Repository parameter" { @@ -158,10 +150,10 @@ Describe 'Test Save-PSResource for PSResources' { Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName $repoName Set-PSResourceRepository "psgettestlocal" -Trusted:$true - Save-PSResource -Name $publishModuleName -Repository $repoName -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be $publishModuleName - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + Save-PSResource -Name $publishModuleName -Repository $repoName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $publishModuleName + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } It "Save specific module resource by name when no repository is specified" { @@ -169,23 +161,26 @@ Describe 'Test Save-PSResource for PSResources' { Set-PSResourceRepository "PSGallery" -Trusted:$True Set-PSResourceRepository "psgettestlocal2" -Trusted:$True - Save-PSResource -Name "TestModule" -Path $TempDir - $pkg = Get-ChildItem $TempDir - $pkg.Name | Should -Be "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + Save-PSResource -Name "TestModule" -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } +<# + # Tests should not write to module directory It "Save specific module resource by name if no -Path param is specifed" { Save-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-ChildItem . - - $pkg.Name | Should -Contain "TestModule" - (Get-ChildItem $pkg).Count | Should -BeGreaterThan 0 + $pkgDir = Get-ChildItem -Path . | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 - # Delete all files and subdirectories in the current , but keep the directory $Tempdir - $pkgDir = Join-Path -Path . -ChildPath "TestModule" - Remove-Item $pkgDir -Recurse -Force + # Delete all files and subdirectories in the current , but keep the directory $SaveDir + if (Test-Path -Path $pkgDir.FullName) { + Remove-Item -Path $pkgDir.FullName -Recurse -Force -ErrorAction SilentlyContinue + } } +#> <# # This needs to be manually tested due to prompt From dba3c432e83ae03d5e5db90f32848ce34f9d28fe Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 16 Jul 2021 19:08:47 -0400 Subject: [PATCH 043/276] Get helper sort (#416) * getHelper should sort by package version in descending order, uninstall remove all versions * resolve merge conflicts * update comment * remove comment * remove other comment * revert accidental change to GetInstalledPSResource * revert last change to GetInstalled * remove styling changes accidentally done * GetHelper should not take VersionRange == null * remove verbose statement * remove extra line added --- src/code/GetHelper.cs | 19 +++++++------------ src/code/InstallPSResource.cs | 6 ++++++ src/code/UninstallPSResource.cs | 16 +++++++++++----- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index f32d8a03f..b451f3227 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; using System.IO; using System.Linq; using System.Management.Automation; @@ -80,6 +81,8 @@ public List FilterPkgPathsByName(string[] names, List dirsToSear // Filter by user provided version public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, List dirsToSearch) { + Dbg.Assert(versionRange != null, "Version Range cannot be null"); + // if no version is specified, just get the latest version foreach (string pkgPath in dirsToSearch) { @@ -94,6 +97,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li _cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); string[] versionsDirs = Utils.GetSubDirectories(pkgPath); + if (versionsDirs.Length == 0) { _cmdletPassedIn.WriteVerbose( @@ -101,18 +105,9 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li continue; } - // versionRange should not be null if the cmdlet is Get-InstalledPSResource - if (versionRange == null) - { - // if no version is specified, just delete the latest version - Array.Sort(versionsDirs); - - if (versionsDirs.Length > 0) - { - yield return versionsDirs[versionsDirs.Length - 1]; - } - continue; - } + // sort and reverse to get package versions in descending order to maintain consistency with V2 + Array.Sort(versionsDirs); + Array.Reverse(versionsDirs); foreach (string versionPath in versionsDirs) { diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 3d750ad01..62e07785e 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -114,6 +114,12 @@ protected override void BeginProcessing() ThrowTerminatingError(IncorrectVersionFormat); } + // if no Version specified, install latest version for the package + if (Version == null) + { + _versionRange = VersionRange.All; + } + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 717b07358..822e746c4 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { - /// + /// /// Uninstall-PSResource uninstalls a package found in a module or script installation path. /// [Cmdlet(VerbsLifecycle.Uninstall, "PSResource", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true, HelpUri = "")] @@ -27,7 +27,7 @@ public sealed class UninstallPSResource : PSCmdlet [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } - + /// /// Specifies the version or version range of the package to be uninstalled. /// @@ -69,6 +69,12 @@ protected override void BeginProcessing() ThrowTerminatingError(IncorrectVersionFormat); } + // if no Version specified, uninstall all versions for the package + if (Version == null) + { + _versionRange = VersionRange.All; + } + _pathsToSearch = Utils.GetAllResourcePaths(this); } @@ -119,7 +125,7 @@ protected override void ProcessRecord() break; } } - + private bool UninstallPkgHelper() { @@ -186,7 +192,7 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) { return false; } - + DirectoryInfo dir = new DirectoryInfo(pkgPath); dir.Attributes &= ~FileAttributes.ReadOnly; @@ -221,7 +227,7 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) var ErrorDeletingDirectory = new ErrorRecord(ex, "ErrorDeletingDirectory", ErrorCategory.PermissionDenied, null); WriteError(ErrorDeletingDirectory); } - + return successfullyUninstalledPkg; } From 30a34e08c357b0c5e5ba602a128914ead833a1cf Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 16 Jul 2021 16:28:33 -0700 Subject: [PATCH 044/276] Workaround .Net Framework file system bugs (#417) --- src/code/InstallHelper.cs | 8 ++-- src/code/UninstallPSResource.cs | 3 +- src/code/Utils.cs | 80 +++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 1bde963d9..d699e1ead 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -604,7 +604,7 @@ private void MoveFilesIntoInstallPath(PSResourceInfo p, bool isScript, bool isLo } _cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); - File.Move(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); // Need to delete old script file, if that exists _cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); @@ -616,7 +616,7 @@ private void MoveFilesIntoInstallPath(PSResourceInfo p, bool isScript, bool isLo } _cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); - File.Move(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); } else { @@ -625,7 +625,7 @@ private void MoveFilesIntoInstallPath(PSResourceInfo p, bool isScript, bool isLo { _cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); Directory.CreateDirectory(newPathParent); - Directory.Move(tempModuleVersionDir, finalModuleVersionDir); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); } else { @@ -640,7 +640,7 @@ private void MoveFilesIntoInstallPath(PSResourceInfo p, bool isScript, bool isLo } _cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Directory.Move(tempModuleVersionDir, finalModuleVersionDir); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); } } } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 822e746c4..782fe3db7 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -198,8 +198,7 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) try { - // delete recursively - Directory.Delete(pkgPath, recursive: true); + Utils.DeleteDirectory(pkgPath); WriteVerbose(string.Format("Successfully uninstalled '{0}' from path '{1}'", pkgName, dir.FullName)); successfullyUninstalledPkg = true; diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 050c286e8..32fba5a11 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -395,5 +395,85 @@ public static void WriteVerboseOnCmdlet( } #endregion + + + #region Directory and File + + /// + /// Deletes a directory and its contents + /// + public static void DeleteDirectory(string dirPath) + { + foreach (var dirFilePath in Directory.GetFiles(dirPath)) + { + File.Delete(dirFilePath); + } + + foreach (var dirSubPath in Directory.GetDirectories(dirPath)) + { + DeleteDirectory(dirSubPath); + } + + Directory.Delete(dirPath); + } + + /// + /// Moves files from source to destination locations. + /// Works over different file volumes. + /// + public static void MoveFiles( + string sourceFilePath, + string destFilePath, + bool overwrite = true) + { + File.Copy(sourceFilePath, destFilePath, overwrite); + File.Delete(sourceFilePath); + } + + /// + /// Moves the directory, including contents, from source to destination locations. + /// Works over different file volumes. + /// + public static void MoveDirectory( + string sourceDirPath, + string destDirPath, + bool overwrite = true) + { + CopyDirContents(sourceDirPath, destDirPath, overwrite); + DeleteDirectory(sourceDirPath); + } + + private static void CopyDirContents( + string sourceDirPath, + string destDirPath, + bool overwrite) + { + if (Directory.Exists(destDirPath)) + { + if (!overwrite) + { + throw new PSInvalidOperationException( + $"Cannot move directory because destination directory already exists: '{destDirPath}'"); + } + + DeleteDirectory(destDirPath); + } + + Directory.CreateDirectory(destDirPath); + + foreach (var filePath in Directory.GetFiles(sourceDirPath)) + { + var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + File.Copy(filePath, destFilePath); + } + + foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); + } + } + + #endregion } } From e20fedc6d71661f8cbecc7b0fbce55bd96cc5682 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 19 Jul 2021 16:13:43 -0700 Subject: [PATCH 045/276] Fix linux path (#418) * Fix non-Windows paths and tests * Enable tests on linux CI * Disable tests on Unbuntu --- .ci/ci.yml | 6 +-- src/code/InstallHelper.cs | 18 ++++++-- src/code/Utils.cs | 71 ++++++++++++++------------------ test/InstallPSResource.Tests.ps1 | 6 +-- 4 files changed, 53 insertions(+), 48 deletions(-) diff --git a/.ci/ci.yml b/.ci/ci.yml index 9df554fec..7cecb9d49 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -126,11 +126,11 @@ stages: # - template: test.yml # parameters: # jobName: TestPkgUbuntu16 -# displayName: PowerShell Core on Ubuntu 16.04 -# imageName: ubuntu-16.04 +# displayName: PowerShell Core on Ubuntu +# imageName: ubuntu-latest # - template: test.yml # parameters: # jobName: TestPkgWinMacOS # displayName: PowerShell Core on macOS -# imageName: macOS-10.14 +# imageName: macOS-latest diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index d699e1ead..a2a728833 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -578,17 +578,29 @@ private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgId } } - private void MoveFilesIntoInstallPath(PSResourceInfo p, bool isScript, bool isLocalRepo, string dirNameVersion, string tempInstallPath, string installPath, string newVersion, string moduleManifestVersion, string nupkgVersion, string versionWithoutPrereleaseTag, string scriptPath) + private void MoveFilesIntoInstallPath( + PSResourceInfo p, + bool isScript, + bool isLocalRepo, + string dirNameVersion, + string tempInstallPath, + string installPath, + string newVersion, + string moduleManifestVersion, + string nupkgVersion, + string versionWithoutPrereleaseTag, + string scriptPath) { // Creating the proper installation path depending on whether pkg is a module or script var newPathParent = isScript ? installPath : Path.Combine(installPath, p.Name); var finalModuleVersionDir = isScript ? installPath : Path.Combine(installPath, p.Name, moduleManifestVersion); // versionWithoutPrereleaseTag - _cmdletPassedIn.WriteDebug(string.Format("Installation path is: '{0}'", finalModuleVersionDir)); // If script, just move the files over, if module, move the version directory over var tempModuleVersionDir = (isScript || isLocalRepo) ? dirNameVersion : Path.Combine(tempInstallPath, p.Name.ToLower(), newVersion); - _cmdletPassedIn.WriteVerbose(string.Format("Full installation path is: '{0}'", tempModuleVersionDir)); + + _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); if (isScript) { diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 32fba5a11..b36e80130 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -221,27 +221,14 @@ public static string GetInstalledPackageName(string pkgPath) public static List GetAllResourcePaths(PSCmdlet psCmdlet) { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); List resourcePaths = psModulePath.Split(';').ToList(); List pathsToSearch = new List(); - var PSVersion6 = new Version(6, 0); - var isCorePS = psCmdlet.Host.Version >= PSVersion6; - string myDocumentsPath; - string programFilesPath; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and MacOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); - programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); - } // will search first in PSModulePath, then will search in default paths resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); @@ -294,33 +281,20 @@ public static List GetAllResourcePaths(PSCmdlet psCmdlet) // Find all potential installation paths given a scope public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType scope) { - List installationPaths = new List(); - var PSVersion6 = new Version(6, 0); - var isCorePS = psCmdlet.Host.Version >= PSVersion6; - string myDocumentsPath; - string programFilesPath; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = isCorePS ? "PowerShell" : "WindowsPowerShell"; - - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and MacOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "Powershell"); - programFilesPath = System.IO.Path.Combine("usr", "local", "share", "Powershell"); - } + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); // The default user scope is CurrentUser + var installationPaths = new List(); if (scope == ScopeType.AllUsers) { installationPaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); installationPaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); } - else { + else + { installationPaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); installationPaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); } @@ -331,6 +305,26 @@ public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType return installationPaths; } + private readonly static Version PSVersion6 = new Version(6, 0); + private static void GetStandardPlatformPaths( + PSCmdlet psCmdlet, + out string myDocumentsPath, + out string programFilesPath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; + myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and macOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "powershell"); + programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); + } + } + #endregion #region Manifest methods @@ -396,7 +390,6 @@ public static void WriteVerboseOnCmdlet( #endregion - #region Directory and File /// diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index e8f604166..56238bfef 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -125,7 +125,7 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under CurrentUser scope" { + It "Install resource under CurrentUser scope" -Skip:(!$IsWindows) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" @@ -133,7 +133,7 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under AllUsers scope" { + It "Install resource under AllUsers scope" -Skip:(!$IsWindows) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" @@ -141,7 +141,7 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under no specified scope" { + It "Install resource under no specified scope" -Skip:(!$IsWindows) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" From b7bb562fa3858b500061aab324d9af4c4a7e375e Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 19 Jul 2021 19:22:52 -0400 Subject: [PATCH 046/276] Prerelease version tag (#419) fix typo in debug message --- src/code/InstallHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index a2a728833..1679c06fa 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -77,7 +77,7 @@ public void InstallPackages( _cmdletPassedIn.WriteDebug(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", string.Join(",", names), - (_versionRange != null ? _versionRange.OriginalString : string.Empty), + (versionRange != null ? versionRange.OriginalString : string.Empty), prerelease.ToString(), repository != null ? string.Join(",", repository) : string.Empty, acceptLicense.ToString(), From 8d0408f4e89e0645510abdda3156640a40c03402 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 27 Jul 2021 12:06:22 -0700 Subject: [PATCH 047/276] Create private cancellation token in InstallHelper (#422) --- src/code/InstallHelper.cs | 7 +++++-- src/code/InstallPSResource.cs | 7 +------ src/code/SavePSResource.cs | 6 +----- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 1679c06fa..87d624e9d 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -46,11 +46,14 @@ internal class InstallHelper : PSCmdlet bool _asNupkg; bool _includeXML; - public InstallHelper(bool updatePkg, bool savePkg, CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) + public InstallHelper(bool updatePkg, bool savePkg, PSCmdlet cmdletPassedIn) { + // Define the cancellation token. + CancellationTokenSource source = new CancellationTokenSource(); + _cancellationToken = source.Token; + this._updatePkg = updatePkg; this._savePkg = savePkg; - this._cancellationToken = cancellationToken; this._cmdletPassedIn = cmdletPassedIn; } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 62e07785e..51a7a3fc8 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -59,7 +59,6 @@ class InstallPSResource : PSCmdlet /// /// Specifies the scope of installation. /// - [ValidateSet("CurrentUser", "AllUsers")] [Parameter(ParameterSetName = NameParameterSet)] public ScopeType Scope { get; set; } @@ -125,11 +124,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - // Define the cancellation token. - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - - var installHelper = new InstallHelper(updatePkg: false, savePkg: false, cancellationToken: cancellationToken, cmdletPassedIn: this); + var installHelper = new InstallHelper(updatePkg: false, savePkg: false, cmdletPassedIn: this); switch (ParameterSetName) { diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index ef89b431f..a68496dd6 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -146,11 +146,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - // Define the cancellation token. - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - - var installHelper = new InstallHelper(updatePkg: false, savePkg: true, cancellationToken: cancellationToken, cmdletPassedIn: this); + var installHelper = new InstallHelper(updatePkg: false, savePkg: true, cmdletPassedIn: this); switch (ParameterSetName) { From a60cbf103a4c5ae051dd0175ca0de6ab040937b8 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 27 Jul 2021 14:56:47 -0700 Subject: [PATCH 048/276] Remove unneeded PR trigger and enable tests on Linux and macOS platforms (#424) * Remove unneeded PR trigger * Enable tests on Linux and macOS --- .ci/ci.yml | 20 ++++++++++---------- .ci/ci_auto.yml | 22 +++++++++++----------- .ci/ci_release.yml | 34 +++++++++++++--------------------- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/.ci/ci.yml b/.ci/ci.yml index 7cecb9d49..b4126ca56 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -123,14 +123,14 @@ stages: imageName: windows-latest powershellExecutable: powershell -# - template: test.yml -# parameters: -# jobName: TestPkgUbuntu16 -# displayName: PowerShell Core on Ubuntu -# imageName: ubuntu-latest + - template: test.yml + parameters: + jobName: TestPkgUbuntu16 + displayName: PowerShell Core on Ubuntu + imageName: ubuntu-latest -# - template: test.yml -# parameters: -# jobName: TestPkgWinMacOS -# displayName: PowerShell Core on macOS -# imageName: macOS-latest + - template: test.yml + parameters: + jobName: TestPkgWinMacOS + displayName: PowerShell Core on macOS + imageName: macOS-latest diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 9080e4dc1..2facb5286 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -320,14 +320,14 @@ stages: imageName: windows-latest powershellExecutable: powershell -# - template: test.yml -# parameters: -# jobName: TestPkgUbuntu16 -# displayName: PowerShell Core on Ubuntu 16.04 -# imageName: ubuntu-16.04 - -# - template: test.yml -# parameters: -# jobName: TestPkgWinMacOS -# displayName: PowerShell Core on macOS -# imageName: macOS-10.14 + - template: test.yml + parameters: + jobName: TestPkgUbuntu16 + displayName: PowerShell Core on Ubuntu 16.04 + imageName: ubuntu-16.04 + + - template: test.yml + parameters: + jobName: TestPkgWinMacOS + displayName: PowerShell Core on macOS + imageName: macOS-10.14 diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 31fc6f949..457544d32 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -1,14 +1,6 @@ name: $(BuildDefinitionName)-$(date:yyMM).$(date:dd)$(rev:rrr) -trigger: - # Batch merge builds together while a merge build is running - batch: false - branches: - include: - - master -pr: - branches: - include: - - master +trigger: none +pr: none variables: - group: ESRP @@ -326,17 +318,17 @@ stages: imageName: windows-latest powershellExecutable: powershell -# - template: test.yml -# parameters: -# jobName: TestPkgUbuntu16 -# displayName: PowerShell Core on Ubuntu 16.04 -# imageName: ubuntu-16.04 - -# - template: test.yml -# parameters: -# jobName: TestPkgWinMacOS -# displayName: PowerShell Core on macOS -# imageName: macOS-10.14 + - template: test.yml + parameters: + jobName: TestPkgUbuntu16 + displayName: PowerShell Core on Ubuntu 16.04 + imageName: ubuntu-16.04 + + - template: test.yml + parameters: + jobName: TestPkgWinMacOS + displayName: PowerShell Core on macOS + imageName: macOS-10.14 - stage: Release displayName: Publish Package to PSGallery From 6345479606120861e2853fc6b8926287944e997f Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 27 Jul 2021 15:29:18 -0700 Subject: [PATCH 049/276] Update README.md (#423) --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1c523bb33..997deab3a 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,7 @@ Please note, the repository for previous versions of PowerShellGet has a new loc Introduction ============ -PowerShellGet is a PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts. - -PowerShellGet module is also integrated with the PackageManagement module as a provider, users can also use the PackageManagement cmdlets for discovering, installing and updating the PowerShell artifacts like Modules and Scripts. +PowerShellGet is a PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, Scripts, and DSC Resources. Documentation ============= @@ -28,8 +26,7 @@ to reference the documentation for previous versions of PowerShellGet. Requirements ============ -- Windows PowerShell 5.0 or newer. -- PowerShell Core. +- PowerShell 5.0 or higher. Get PowerShellGet Module ======================== @@ -68,9 +65,6 @@ if ((Get-Module -Name PSPackageProject -ListAvailable).Count -eq 0) { ```powershell # Build for the netstandard2.0 framework PS C:\Repos\PowerShellGet> .\build.ps1 -Clean -Build -BuildConfiguration Debug -BuildFramework netstandard2.0 - -# Build for the net472 framework -PS C:\Repos\PowerShellGet> .\build.ps1 -Build -BuildConfiguration Debug -BuildFramework net472 ``` * Publish the module to a local repository @@ -98,4 +92,4 @@ C:\> Import-Module C:\Repos\PowerShellGet\out\PowerShellGet\PowerShellGet.psd1 **Note** PowerShellGet consists of .NET binaries and so can be imported into a PowerShell session only once. Since the PSPackageProject module, used to build the module, has a dependency on earlier versions of PowerShellGet, the newly built module cannot be imported into that session. -The new module can only be imported into a new session that has no prior imported PowerShellGet module. +The new module can only be imported into a new session that has no prior imported PowerShellGet module. You will recieve warning messages in the console if you encounter this issue. From 365fe4750b2c834224934a0c3ad682553be9fea6 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 27 Jul 2021 16:13:38 -0700 Subject: [PATCH 050/276] Add updates to complete Tests for Install, Save, Publish, Get-Installed, and Uninstall tests. (#420) --- src/code/UninstallPSResource.cs | 54 +++--- test/GetInstalledPSResource.Tests.ps1 | 52 +++--- test/InstallPSResource.Tests.ps1 | 33 +++- test/PSGetTestUtils.psm1 | 10 +- test/UninstallPSResource.Tests.ps1 | 236 +++++++++++--------------- 5 files changed, 199 insertions(+), 186 deletions(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 782fe3db7..0a69e4617 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -154,27 +154,33 @@ private bool UninstallPkgHelper() continue; } + ErrorRecord errRecord = null; if (pkgPath.EndsWith(".ps1")) { - successfullyUninstalled = UninstallScriptHelper(pkgPath, pkgName); + successfullyUninstalled = UninstallScriptHelper(pkgPath, pkgName, out errRecord); } else { - successfullyUninstalled = UninstallModuleHelper(pkgPath, pkgName); + successfullyUninstalled = UninstallModuleHelper(pkgPath, pkgName, out errRecord); } // if we can't find the resource, write non-terminating error and return - if (!successfullyUninstalled) + if (!successfullyUninstalled || errRecord != null) { - string message = Version == null || Version.Trim().Equals("*") ? - string.Format("Could not find any version of the resource '{0}' in any path", pkgName) : - string.Format("Could not find verison '{0}' of the resource '{1}' in any path", Version, pkgName); - - WriteError(new ErrorRecord( - new PSInvalidOperationException(message), - "ErrorRetrievingSpecifiedResource", - ErrorCategory.ObjectNotFound, - this)); + if (errRecord == null) + { + string message = Version == null || Version.Trim().Equals("*") ? + string.Format("Could not find any version of the resource '{0}' in any path", pkgName) : + string.Format("Could not find verison '{0}' of the resource '{1}' in any path", Version, pkgName); + + errRecord = new ErrorRecord( + new PSInvalidOperationException(message), + "ErrorRetrievingSpecifiedResource", + ErrorCategory.ObjectNotFound, + this); + } + + WriteError(errRecord); } } @@ -182,13 +188,14 @@ private bool UninstallPkgHelper() } /* uninstalls a module */ - private bool UninstallModuleHelper(string pkgPath, string pkgName) + private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorRecord errRecord) { + errRecord = null; var successfullyUninstalledPkg = false; // if -Force is not specified and the pkg is a dependency for another package, // an error will be written and we return false - if (!Force && CheckIfDependency(pkgName)) + if (!Force && CheckIfDependency(pkgName, out errRecord)) { return false; } @@ -216,7 +223,7 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) var exMessage = String.Format("Parent directory '{0}' could not be deleted: {1}", dir.Parent.FullName, e.Message); var ex = new ArgumentException(exMessage); var ErrorDeletingParentDirectory = new ErrorRecord(ex, "ErrorDeletingParentDirectory", ErrorCategory.InvalidArgument, null); - WriteError(ErrorDeletingParentDirectory); + errRecord = ErrorDeletingParentDirectory; } } catch (Exception err) { @@ -224,15 +231,16 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName) var exMessage = String.Format("Directory '{0}' could not be deleted: {1}", dir.FullName, err.Message); var ex = new ArgumentException(exMessage); var ErrorDeletingDirectory = new ErrorRecord(ex, "ErrorDeletingDirectory", ErrorCategory.PermissionDenied, null); - WriteError(ErrorDeletingDirectory); + errRecord = ErrorDeletingDirectory; } return successfullyUninstalledPkg; } /* uninstalls a script */ - private bool UninstallScriptHelper(string pkgPath, string pkgName) + private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorRecord errRecord) { + errRecord = null; var successfullyUninstalledPkg = false; // delete the appropriate file @@ -258,21 +266,22 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName) var exMessage = String.Format("Script metadata file '{0}' could not be deleted: {1}", scriptXML, e.Message); var ex = new ArgumentException(exMessage); var ErrorDeletingScriptMetadataFile = new ErrorRecord(ex, "ErrorDeletingScriptMetadataFile", ErrorCategory.PermissionDenied, null); - WriteError(ErrorDeletingScriptMetadataFile); + errRecord = ErrorDeletingScriptMetadataFile; } } catch (Exception err){ var exMessage = String.Format("Script '{0}' could not be deleted: {1}", pkgPath, err.Message); var ex = new ArgumentException(exMessage); var ErrorDeletingScript = new ErrorRecord(ex, "ErrorDeletingScript", ErrorCategory.PermissionDenied, null); - WriteError(ErrorDeletingScript); + errRecord = ErrorDeletingScript; } return successfullyUninstalledPkg; } - private bool CheckIfDependency(string pkgName) + private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) { + errRecord = null; // this is a primitive implementation // TODO: implement a dependencies database for querying dependency info // cannot uninstall a module if another module is dependent on it @@ -296,7 +305,7 @@ private bool CheckIfDependency(string pkgName) var exMessage = String.Format("Error checking if resource is a dependency: {0}. If you would still like to uninstall, rerun the command with -Force", e.Message); var ex = new ArgumentException(exMessage); var DependencyCheckError = new ErrorRecord(ex, "DependencyCheckError", ErrorCategory.OperationStopped, null); - WriteError(DependencyCheckError); + errRecord = DependencyCheckError; } if (pkgsWithRequiredModules.Any()) @@ -307,7 +316,8 @@ private bool CheckIfDependency(string pkgName) var exMessage = String.Format("Cannot uninstall '{0}', the following package(s) take a dependency on this package: {1}. If you would still like to uninstall, rerun the command with -Force", pkgName, strUniquePkgNames); var ex = new ArgumentException(exMessage); var PackageIsaDependency = new ErrorRecord(ex, "PackageIsaDependency", ErrorCategory.OperationStopped, null); - WriteError(PackageIsaDependency); + errRecord = PackageIsaDependency; + return true; } } diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 3b9665a46..937ab4e72 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -1,7 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -<# // Temporarily commenting out until Install-PSResource is complete Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Get-InstalledPSResource for Module' { @@ -10,8 +9,11 @@ Describe 'Test Get-InstalledPSResource for Module' { $TestGalleryName = Get-PoshTestGalleryName Get-NewPSResourceRepositoryFile - Register-PSRepository $TestGalleryName -SourceLocation "https://www.poshtestgallery.com/api/v2" - Install-Module ContosoServer -Repository $TestGalleryName + Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository + Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "2.0" + Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "1.5" + Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "1.0" + Install-PSResource TestTestScript -Repository $TestGalleryName -TrustRepository } AfterAll { @@ -25,39 +27,40 @@ Describe 'Test Get-InstalledPSResource for Module' { It "Get specific module resource by name" { $pkg = Get-InstalledPSResource -Name ContosoServer - $pkg.Name | Should -Be "ContosoServer" + $pkg.Name | Should -Contain "ContosoServer" } It "Get specific script resource by name" { - $pkg = Get-InstalledPSResource -Name adsql - $pkg.Name | Should -Be "adsql" + $pkg = Get-InstalledPSResource -Name TestTestScript + $pkg.Name | Should -Be "TestTestScript" } It "Get resource when given Name to " -TestCases @( - @{Name="*ShellG*"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard at beginning and end of name: *ShellG*"}, - @{Name="PowerShell*"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard at end of name: PowerShellG*"}, - @{Name="*ShellGet"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard at beginning of name: *ShellGet"}, - @{Name="Power*Get"; ExpectedName="PowerShellGet"; Reason="validate name, with wildcard in middle of name: Power*Get"} + @{Name="*tosoSer*"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard at beginning and end of name: *tosoSer*"}, + @{Name="ContosoSer*"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard at end of name: ContosoSer*"}, + @{Name="*tosoServer"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard at beginning of name: *tosoServer"}, + @{Name="Cont*erver"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard in middle of name: Cont*erver"} ) { param($Version, $ExpectedVersion) $pkgs = Get-InstalledPSResource -Name $Name - $pkgs.Name | Should -Be "PowerShellGet" + $pkgs.Name | Should -Contain "ContosoServer" } - It "Get resource when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { +$testCases = + @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, + @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion=@("2.5.0.0", "2.0.0.0", "1.5.0.0", "1.0.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion=@("2.0.0.0", "1.5.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion=@("2.5.0.0", "2.0.0.0", "1.5.0.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion=@("2.5.0.0", "2.0.0.0", "1.5.0.0", "1.0.0.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,1.5.0.0]"; ExpectedVersion=@("1.5.0.0", "1.0.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion=@("2.0.0.0", "1.5.0.0", "1.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + + It "Get resource when given Name to " -TestCases $testCases { param($Version, $ExpectedVersion) $pkgs = Get-InstalledPSResource -Name "ContosoServer" -Version $Version - $pkgs.Name | Should -Be "ContosoServer" + $pkgs.Name | Should -Contain "ContosoServer" $pkgs.Version | Should -Be $ExpectedVersion } @@ -100,8 +103,7 @@ Describe 'Test Get-InstalledPSResource for Module' { } It "Get resources when given Name, and Version is '*'" { - $pkgs = Get-InstalledPSResource -Name Carbon -Version "*" + $pkgs = Get-InstalledPSResource -Name ContosoServer -Version "*" $pkgs.Count | Should -BeGreaterOrEqual 2 } } -#> \ No newline at end of file diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 56238bfef..0a3a245c8 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -125,7 +125,7 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under CurrentUser scope" -Skip:(!$IsWindows) { + It "Install resource under CurrentUser scope - Windows only" -Skip:(!(Get-IsWindows)) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" @@ -133,7 +133,7 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under AllUsers scope" -Skip:(!$IsWindows) { + It "Install resource under AllUsers scope - Windows only" -Skip:(!(Get-IsWindows)) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" @@ -141,13 +141,40 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under no specified scope" -Skip:(!$IsWindows) { + It "Install resource under no specified scope - Windows only" -Skip:(!(Get-IsWindows)) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" $pkg.Path.Contains("Documents") | Should -Be $true } + # Unix only + # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' + It "Install resource under CurrentUser scope - Unix only" -Skip:(Get-IsWindows) { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("/home/") | Should -Be $true + } + + # Unix only + # Expected path should be similar to: '/usr/local/share/powershell/Modules' + It "Install resource under AllUsers scope - Unix only" -Skip:(Get-IsWindows) { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("/usr/") | Should -Be $true + } + + # Unix only + # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' + It "Install resource under no specified scope - Unix only" -Skip:(Get-IsWindows) { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("/home/") | Should -Be $true + } + It "Should not install resource that is already installed" { Install-PSResource -Name "TestModule" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index f3410ffaf..4cae5c5ec 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -7,7 +7,11 @@ $script:EnvPATHValueBackup = $null $script:PowerShellGet = 'PowerShellGet' $script:IsInbox = $PSHOME.EndsWith('\WindowsPowerShell\v1.0', [System.StringComparison]::OrdinalIgnoreCase) -$script:IsWindows = (-not (Get-Variable -Name IsWindows -ErrorAction Ignore)) -or $IsWindows +$script:IsWindows = $IsWindows +if ($IsWindows -eq $null) { + $script:IsWindows = ($PSVersionTable.PSVersion.Major -eq 5) +} + $script:IsLinux = (Get-Variable -Name IsLinux -ErrorAction Ignore) -and $IsLinux $script:IsMacOS = (Get-Variable -Name IsMacOS -ErrorAction Ignore) -and $IsMacOS $script:IsCoreCLR = $PSVersionTable.ContainsKey('PSEdition') -and $PSVersionTable.PSEdition -eq 'Core' @@ -96,6 +100,10 @@ $script:moduleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:CurrentPSGetFormatVersion = "1.0" $script:PSGetFormatVersionPrefix = "PowerShellGetFormatVersion_" +function Get-IsWindows { + return $script:IsWindows +} + function Get-AllUsersModulesPath { return $script:ProgramFilesModulesPath } diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index a1258d3ef..511f43016 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -1,7 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -<#// Temporarily comment out tests until Install-PSResource is complete Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Uninstall-PSResource for Modules' { @@ -10,180 +9,147 @@ Describe 'Test Uninstall-PSResource for Modules' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName Get-NewPSResourceRepositoryFile + $res = Uninstall-PSResource -name ContosoServer -Version "*" + } + BeforeEach{ + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue } - AfterAll { Get-RevertPSResourceRepositoryFile } It "Uninstall a specific module by name" { - $pkg = Uninstall-PSResource -name Bicep + $res = Uninstall-PSResource -name ContosoServer + Get-Module ContosoServer -ListAvailable | Should -Be $null } It "Uninstall a list of modules by name" { - $pkg = Uninstall-PSResource -Name BaseTestPackage, bicep - } + $null = Install-PSResource BaseTestPackage -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - It "Uninstall a module when given name and specifying all versions" { - $res = Uninstall-PSResource -Name "Carbon" -version "*" - $res | Should -BeNullOrEmpty + $res = Uninstall-PSResource -Name BaseTestPackage, ContosoServer + Get-Module ContosoServer, BaseTestPackage -ListAvailable | Should -be $null } - It "Uninstall module when given Name and specifying exact version" { - $res = Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" - $res | Should -BeNullOrEmpty - } - - It "Uninstall module when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Uninstall-PSResource -Name "Pester" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "Pester" - $res.Version | Should -Be $ExpectedVersion - } - - It "Do not uninstall module with incorrectly formatted version such as " -TestCases @( - @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, - @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, - @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) + It "Uninstall a specific script by name" { + $null = Install-PSResource Test-RPC -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - $res = $null - try { - $res = Uninstall-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty + $pkg = Uninstall-PSResource -name Test-RPC } - It "Does not uninstall when given Name and an invalid version" { - $res = Uninstall-PSResource -Name "ContosoServer" -Version "(0.0.0.1)" - $res | Should -BeNullOrEmpty + It "Uninstall a list of scripts by name" { + $null = Install-PSResource adsql, airoute -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + + $pkg = Uninstall-PSResource -Name adsql, airoute } - It "Uninstall lastest version of a particular module " { - # test_module resource's latest version is a prerelease version, before that it has a non-prerelease version - $res = Uninstall-PSResource -Name "test_module" - $res.Version | Should -Be "5.0.0.0" + It "Uninstall a module when given name and specifying all versions" { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - $resPrerelease = Uninstall-PSResource -Name "test_module" -Prerelease - $resPrerelease.Version | Should -Be "5.2.5.0" + $res = Uninstall-PSResource -Name ContosoServer -version "*" + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain "1.0.0" + $pkgs.Version | Should -Not -Contain "1.5.0" + $pkgs.Version | Should -Not -Contain "2.0.0" + $pkgs.Version | Should -Not -Contain "2.5.0" } - It "Uninstall module using -WhatIf, should not uninstall the module" { - $res = Uninstall-PSResource -Name "ActiveDirectoryTools" -WhatIf - } + It "Uninstall a module when given name and using the default version (ie all versions, not explicitly specified)" { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - It "Do not Uninstall module that is a dependency for another module" { - $res = Uninstall-PSResource -Name "PackageManagement" + $res = Uninstall-PSResource -Name ContosoServer + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain "1.0.0" + $pkgs.Version | Should -Not -Contain "1.5.0" + $pkgs.Version | Should -Not -Contain "2.0.0" + $pkgs.Version | Should -Not -Contain "2.5.0" } - It "Uninstall module that is a dependency for another module using -Force" { - $res = Uninstall-PSResource -Name "PackageManagement" -Force + It "Uninstall module when given Name and specifying exact version" { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + + $res = Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain "1.0.0" + } + + $testCases = @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, + @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, + @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + + It "Uninstall module when given Name to " -TestCases $testCases { + param($Version, $ExpectedVersion) + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + + $res = Uninstall-PSResource -Name ContosoServer -Version $Version + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain $Version } -} + $testCases2 = @{Version='[1.*.0]'; Description="version with wilcard in middle"}, + @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, + @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.5.0.]'; Description="version with missing digit at end"}, + @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} -Describe 'Test Uninstall-PSResource for Scripts' { + It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases2 { + param($Version, $Description) - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - Get-NewPSResourceRepositoryFile + {Uninstall-PSResource -Name "ContosoServer" -Version $Version} | Should -Throw "Argument for -Version parameter is not in the proper format." } - AfterAll { - Get-RevertPSResourceRepositoryFile - } + $testCases3 = @{Version='(2.5.0.0)'; Description="exclusive version (8.1.0.0)"}, + @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"} - It "Uninstall a specific script by name" { - $pkg = Uninstall-PSResource -name Test-RPC - } + It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases3 { + param($Version, $Description) - It "Uninstall a list of scripts by name" { - $pkg = Uninstall-PSResource -Name adsql, airoute - } + Uninstall-PSResource -Name "ContosoServer" -Version $Version - It "Uninstall a script when given name and specifying all versions" { - $res = Uninstall-PSResource -Name "NetworkingDSC" -version "*" - $res | Should -BeNullOrEmpty + $pkg = Get-Module ContosoServer -ListAvailable + $pkg.Version | Should -Be "2.5" } - It "Uninstall script when given Name and specifying exact version" { - $res = Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" - $res | Should -BeNullOrEmpty - } + It "Uninstall module using -WhatIf, should not uninstall the module" { + $res = Uninstall-PSResource -Name "ContosoServer" -WhatIf - It "Does not uninstall a script when given Name and a version that does not exist" { - $res = Uninstall-PSResource -Name "ContosoServer" -Version "3.0.0" - $res | Should -BeNullOrEmpty + $pkg = Get-Module ContosoServer -ListAvailable + $pkg.Version | Should -Be "2.5" } - It "Uninstall script when given Name to " -TestCases @( - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - ) { - param($Version, $ExpectedVersion) - $res = Uninstall-PSResource -Name "Pester" -Version $Version -Repository $TestGalleryName - $res.Name | Should -Be "Pester" - $res.Version | Should -Be $ExpectedVersion - } - - It "Do not uninstall module with incorrectly formatted version such as " -TestCases @( - @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, - @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"}, - @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, - @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} - ) { - param($Version, $Description) + It "Do not Uninstall module that is a dependency for another module" { + $null = Install-PSResource "test_module" -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name "RequiredModule1" -ErrorVariable ev -ErrorAction SilentlyContinue - $res = $null - try { - $res = Uninstall-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore - } - catch {} - - $res | Should -BeNullOrEmpty - } + $pkg = Get-Module "RequiredModule1" -ListAvailable + $pkg | Should -Not -Be $null - It "Does not uninstall when given Name and an invalid version" { - $res = Uninstall-PSResource -Name "ContosoServer" -Version "(0.0.0.1)" - $res | Should -BeNullOrEmpty + $ev | Should -Be "Cannot uninstall 'RequiredModule1', the following package(s) take a dependency on this package: test_module. If you would still like to uninstall, rerun the command with -Force" } - It "Uninstall script using -WhatIf" { - $res = Uninstall-PSResource -Name "ActiveDirectoryTools" -WhatIf + It "Uninstall module that is a dependency for another module using -Force" { + $null = Install-PSResource "test_module" -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + + $res = Uninstall-PSResource -Name "RequiredModule1" -Force + + $pkg = Get-Module "RequiredModule1" -ListAvailable + $pkg | Should -Be $null } } -#> \ No newline at end of file From 27acdc17aa6cc837bf2f05ca826be4a933302510 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 28 Jul 2021 19:41:14 -0400 Subject: [PATCH 051/276] Ensure URI creation is cross platform compatible (#421) * change URI creation, and resolve Unix tests --- src/code/RegisterPSResourceRepository.cs | 44 ++++++--------- src/code/SetPSResourceRepository.cs | 59 +++++++++++---------- src/code/Utils.cs | 50 +++++++++++++++++ test/RegisterPSResourceRepository.Tests.ps1 | 34 ++++++++---- test/SetPSResourceRepository.Tests.ps1 | 32 +++++++---- 5 files changed, 144 insertions(+), 75 deletions(-) diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index a31c110a8..d019071c6 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -34,6 +34,7 @@ class RegisterPSResourceRepository : PSCmdlet private const string NameParameterSet = "NameParameterSet"; private const string PSGalleryParameterSet = "PSGalleryParameterSet"; private const string RepositoriesParameterSet = "RepositoriesParameterSet"; + private Uri _url; #endregion @@ -51,25 +52,7 @@ class RegisterPSResourceRepository : PSCmdlet /// [Parameter(Mandatory = true, Position = 1, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] - public Uri URL - { - get - { return _url; } - - set - { - if (!Uri.TryCreate(value, string.Empty, out Uri url)) - { - var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0}", value); - var ex = new ArgumentException(message); - var moduleManifestNotFound = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(moduleManifestNotFound); - } - - _url = url; - } - } - private Uri _url; + public string URL { get; set; } /// /// When specified, registers PSGallery repository. @@ -156,9 +139,17 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: + if (!Utils.TryCreateValidUrl(urlString: URL, + cmdletPassedIn: this, + urlResult: out _url, + errorRecord: out ErrorRecord errorRecord)) + { + ThrowTerminatingError(errorRecord); + } + try { - items.Add(NameParameterSetHelper(Name, URL, Priority, Trusted)); + items.Add(NameParameterSetHelper(Name, _url, Priority, Trusted)); } catch (Exception e) { @@ -334,13 +325,12 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } - if (!Uri.TryCreate(repo["URL"].ToString(), UriKind.Absolute, out Uri repoURL)) + if (!Utils.TryCreateValidUrl(urlString: repo["Url"].ToString(), + cmdletPassedIn: this, + urlResult: out Uri repoURL, + errorRecord: out ErrorRecord errorRecord)) { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Invalid url, unable to create"), - "InvalidUrlScheme", - ErrorCategory.InvalidArgument, - this)); + WriteError(errorRecord); return null; } @@ -372,6 +362,6 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) } } - #endregion + #endregion } } diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index c3f161333..5f674f02f 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -27,6 +27,7 @@ class SetPSResourceRepository : PSCmdlet private const string NameParameterSet = "NameParameterSet"; private const string RepositoriesParameterSet = "RepositoriesParameterSet"; private const int DefaultPriority = -1; + private Uri _url; #endregion #region Parameters @@ -45,25 +46,7 @@ class SetPSResourceRepository : PSCmdlet /// [Parameter(ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] - public Uri URL - { - get - { return _url; } - - set - { - if (!Uri.TryCreate(value, string.Empty, out Uri url)) - { - var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not a valid url: {0}", value); - var ex = new ArgumentException(message); - var urlErrorRecord = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(urlErrorRecord); - } - - _url = url; - } - } - private Uri _url; + public string URL { get; set; } /// /// Specifies a hashtable of repositories and is used to register multiple repositories at once. @@ -129,6 +112,15 @@ protected override void BeginProcessing() protected override void ProcessRecord() { + if (MyInvocation.BoundParameters.ContainsKey(nameof(URL))) + { + bool isUrlValid = Utils.TryCreateValidUrl(URL, this, out _url, out ErrorRecord errorRecord); + if (!isUrlValid) + { + ThrowTerminatingError(errorRecord); + } + } + List items = new List(); switch(ParameterSetName) @@ -136,7 +128,7 @@ protected override void ProcessRecord() case NameParameterSet: try { - items.Add(UpdateRepositoryStoreHelper(Name, URL, Priority, Trusted)); + items.Add(UpdateRepositoryStoreHelper(Name, _url, Priority, Trusted)); } catch (Exception e) { @@ -243,15 +235,28 @@ private List RepositoriesParameterSetHelper() private PSRepositoryInfo RepoValidationHelper(Hashtable repo) { WriteDebug(String.Format("Parsing through repository: {0}", repo["Name"])); + Uri repoURL = null; - if (repo.ContainsKey("Url") && !Uri.TryCreate(repo["URL"].ToString(), UriKind.Absolute, out repoURL)) + if (repo.ContainsKey("Url")) { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Invalid Url, unable to parse and create Uri"), - "InvalidUrl", - ErrorCategory.InvalidArgument, - this)); - return null; + if (String.IsNullOrEmpty(repo["Url"].ToString())) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Repository url cannot be null if provided"), + "NullURLForRepositoriesParameterSetUpdate", + ErrorCategory.InvalidArgument, + this)); + return null; + } + + if (!Utils.TryCreateValidUrl(urlString: repo["Url"].ToString(), + cmdletPassedIn: this, + urlResult: out repoURL, + errorRecord: out ErrorRecord errorRecord)) + { + WriteError(errorRecord); + return null; + } } bool repoTrusted = false; diff --git a/src/code/Utils.cs b/src/code/Utils.cs index b36e80130..492d07025 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -11,6 +11,7 @@ using System.Management.Automation.Language; using System.Runtime.InteropServices; using NuGet.Versioning; +using System.Globalization; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -171,6 +172,55 @@ public static bool TryParseVersionOrVersionRange( return VersionRange.TryParse(version, out versionRange); } + #endregion + + #region Url methods + + public static bool TryCreateValidUrl( + string urlString, + PSCmdlet cmdletPassedIn, + out Uri urlResult, + out ErrorRecord errorRecord + ) + { + errorRecord = null; + + if (!urlString.StartsWith(Uri.UriSchemeHttps) && + !urlString.StartsWith(Uri.UriSchemeHttp) && + !urlString.StartsWith(Uri.UriSchemeFtp)) + { + // url string could be of type (potentially) UriSchemeFile or invalid type + // can't check for UriSchemeFile because relative paths don't qualify as UriSchemeFile + try + { + // this is needed for a relative path urlstring. Does not throw error for an absolute path + urlString = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(urlString)[0].Path; + + } + catch (Exception) + { + // this should only be reached if the url string is invalid + // i.e www.google.com + var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0} and must be of Uri Scheme: HTTP, HTTPS, FTP or File", urlString); + var ex = new ArgumentException(message); + errorRecord = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); + urlResult = null; + return false; + } + } + + bool tryCreateResult = Uri.TryCreate(urlString, UriKind.Absolute, out urlResult); + if (!tryCreateResult) + { + var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0}", urlString); + var ex = new ArgumentException(message); + errorRecord = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); + urlResult = null; + } + + return tryCreateResult; + } + #endregion #region Path methods diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index 58c1e4c90..fd4204774 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -13,6 +13,8 @@ Describe "Test Register-PSResourceRepository" { $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) Get-NewTestDirs($tmpDirPaths) + + $relativeCurrentPath = Get-Location } AfterEach { Get-RevertPSResourceRepositoryFile @@ -26,7 +28,7 @@ Describe "Test Register-PSResourceRepository" { It "register repository given Name, URL (bare minimum for NameParmaterSet)" { $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -PassThru $res.Name | Should -Be "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } @@ -34,7 +36,7 @@ Describe "Test Register-PSResourceRepository" { It "register repository with Name, URL, Trusted (NameParameterSet)" { $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -Trusted -PassThru $res.Name | Should -Be "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 50 } @@ -42,7 +44,7 @@ Describe "Test Register-PSResourceRepository" { It "register repository given Name, URL, Trusted, Priority (NameParameterSet)" { $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -Trusted -Priority 20 -PassThru $res.Name | Should -Be "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 20 } @@ -82,17 +84,17 @@ Describe "Test Register-PSResourceRepository" { Register-PSResourceRepository -Repositories $arrayOfHashtables $res = Get-PSResourceRepository -Name "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False $res.Priority | Should -Be 50 $res2 = Get-PSResourceRepository -Name "testRepository2" - $res2.URL | Should -Contain $tmpDir2Path + $res2.URL.LocalPath | Should -Contain $tmpDir2Path $res2.Trusted | Should -Be True $res2.Priority | Should -Be 50 $res3 = Get-PSResourceRepository -Name "testRepository3" - $res3.URL | Should -Contain $tmpDir3Path + $res3.URL.LocalPath | Should -Contain $tmpDir3Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 20 } @@ -123,23 +125,23 @@ Describe "Test Register-PSResourceRepository" { $res1.Priority | Should -Be 50 $res2 = Get-PSResourceRepository -Name "testRepository" - $res2.URL | Should -Contain $tmpDir1Path + $res2.URL.LocalPath | Should -Contain $tmpDir1Path $res2.Trusted | Should -Be False $res2.Priority | Should -Be 50 $res3 = Get-PSResourceRepository -Name "testRepository2" - $res3.URL | Should -Contain $tmpDir2Path + $res3.URL.LocalPath | Should -Contain $tmpDir2Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 50 $res4 = Get-PSResourceRepository -Name "testRepository3" - $res4.URL | Should -Contain $tmpDir3Path + $res4.URL.LocalPath | Should -Contain $tmpDir3Path $res4.Trusted | Should -Be True $res4.Priority | Should -Be 20 } It "not register repository when Name is provided but URL is not" { - {Register-PSResourceRepository -Name "testRepository" -URL "" -ErrorAction Stop} | Should -Throw -ErrorId "InvalidUrl,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + {Register-PSResourceRepository -Name "testRepository" -URL "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } It "not register repository when Name is empty but URL is provided" { @@ -193,7 +195,7 @@ Describe "Test Register-PSResourceRepository" { $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = "PSGallery"; URL = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, @{Type = "-URL not specified"; IncorrectHashTable = @{Name = "testRepository"}; ErrorId = "NullURLForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = "testRepository"; URL="www.google.com"}; ErrorId = "InvalidUrlScheme,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = "testRepository"; URL="www.google.com"}; ErrorId = "InvalidUrl,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { param($Type, $IncorrectHashTable, $ErrorId) @@ -218,4 +220,14 @@ Describe "Test Register-PSResourceRepository" { $res3.Name | Should -Be "PSGallery" $res3.Priority | Should -Be 30 } + + It "should register repository with relative location provided as URL" { + Register-PSResourceRepository -Name "testRepository" -URL "./" + $res = Get-PSResourceRepository -Name "testRepository" + + $res.Name | Should -Be "testRepository" + $res.URL.LocalPath | Should -Contain $relativeCurrentPath + $res.Trusted | Should -Be False + $res.Priority | Should -Be 50 + } } diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index 24cb5dfc3..c302c3d79 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -3,7 +3,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force -Describe "Test Register-PSResourceRepository" { +Describe "Test Set-PSResourceRepository" { BeforeEach { $PSGalleryName = Get-PSGalleryName $PSGalleryURL = Get-PSGalleryLocation @@ -13,6 +13,8 @@ Describe "Test Register-PSResourceRepository" { $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) Get-NewTestDirs($tmpDirPaths) + + $relativeCurrentPath = Get-Location } AfterEach { Get-RevertPSResourceRepositoryFile @@ -28,7 +30,7 @@ Describe "Test Register-PSResourceRepository" { Set-PSResourceRepository -Name "testRepository" -URL $tmpDir2Path $res = Get-PSResourceRepository -Name "testRepository" $res.Name | Should -Be "testRepository" - $res.URL | Should -Contain $tmpDir2Path + $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False } @@ -38,7 +40,7 @@ Describe "Test Register-PSResourceRepository" { Set-PSResourceRepository -Name "testRepository" -Priority 25 $res = Get-PSResourceRepository -Name "testRepository" $res.Name | Should -Be "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False } @@ -48,7 +50,7 @@ Describe "Test Register-PSResourceRepository" { Set-PSResourceRepository -Name "testRepository" -Trusted $res = Get-PSResourceRepository -Name "testRepository" $res.Name | Should -Be "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be True } @@ -59,8 +61,8 @@ Describe "Test Register-PSResourceRepository" { } $testCases = @{Type = "contains *"; Name = "test*Repository"; ErrorId = "ErrorInNameParameterSet"}, - @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorInNameParameterSet"}, - @{Type = "is null"; Name = $null; ErrorId = "ParameterArgumentValidationError"} + @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorInNameParameterSet"}, + @{Type = "is null"; Name = $null; ErrorId = "ParameterArgumentValidationError"} It "not set repository and throw error given Name (NameParameterSet)" -TestCases $testCases { param($Type, $Name) @@ -88,7 +90,7 @@ Describe "Test Register-PSResourceRepository" { $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name "testRepository" - $res.URL | Should -Contain $tmpDir3Path + $res.URL.LocalPath | Should -Contain $tmpDir3Path $res.Trusted | Should -Be False $res2 = Get-PSResourceRepository -Name "testRepository2" @@ -110,13 +112,13 @@ Describe "Test Register-PSResourceRepository" { Set-PSResourceRepository -Repositories $arrayOfHashtables $res = Get-PSResourceRepository -Name "testRepository1" $res.Name | Should -Be "testRepository1" - $res.URL | Should -Contain $tmpDir2Path + $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False $res2 = Get-PSResourceRepository -Name "testRepository2" $res2.Name | Should -Be "testRepository2" - $res2.URL | Should -Contain $tmpDir2Path + $res2.URL.LocalPath | Should -Contain $tmpDir2Path $res2.Priority | Should -Be 25 $res2.Trusted | Should -Be False @@ -148,8 +150,18 @@ Describe "Test Register-PSResourceRepository" { $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name "testRepository" - $res.URL | Should -Contain $tmpDir1Path + $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False } + + It "should set repository with relative URL provided" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Set-PSResourceRepository -Name "testRepository" -URL $relativeCurrentPath + $res = Get-PSResourceRepository -Name "testRepository" + $res.Name | Should -Be "testRepository" + $res.URL.LocalPath | Should -Contain $relativeCurrentPath + $res.Trusted | Should -Be False + $res.Priority | Should -Be 50 + } } From 0b2c32057871534729ed996868392627c92d2c94 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 28 Jul 2021 17:37:42 -0700 Subject: [PATCH 052/276] Add fix for failing unix tests (#426) --- test/InstallPSResource.Tests.ps1 | 45 +++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 0a3a245c8..33bc966af 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -154,16 +154,7 @@ Describe 'Test Install-PSResource for Module' { Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("/home/") | Should -Be $true - } - - # Unix only - # Expected path should be similar to: '/usr/local/share/powershell/Modules' - It "Install resource under AllUsers scope - Unix only" -Skip:(Get-IsWindows) { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("/usr/") | Should -Be $true + $pkg.Path.Contains("$env:HOME/.local") | Should -Be $true } # Unix only @@ -172,7 +163,7 @@ Describe 'Test Install-PSResource for Module' { Install-PSResource -Name "TestModule" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("/home/") | Should -Be $true + $pkg.Path.Contains("$env:HOME/.local") | Should -Be $true } It "Should not install resource that is already installed" { @@ -235,8 +226,36 @@ Describe 'Test Install-PSResource for Module' { $pkg | Should -Not -BeNullOrEmpty $pkg.Name | Should -Be $publishModuleName } +} + +<# Temporarily commented until -Tag is implemented for this Describe block +Describe 'Test Install-PSResource for interactive and root user scenarios' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + $NuGetGalleryName = Get-NuGetGalleryName + Get-NewPSResourceRepositoryFile + Register-LocalRepos + } + + AfterEach { + Uninstall-PSResource "TestModule", "testModuleWithlicense" -Force -ErrorAction SilentlyContinue + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + # Unix only manual test + # Expected path should be similar to: '/usr/local/share/powershell/Modules' + It "Install resource under AllUsers scope - Unix only" -Skip:(Get-IsWindows) { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Path.Contains("/usr/") | Should -Be $true + } -<# # This needs to be manually tested due to prompt It "Install resource that requires accept license without -AcceptLicense flag" { Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName @@ -256,5 +275,5 @@ Describe 'Test Install-PSResource for Module' { Set-PSResourceRepository PoshTestGallery -Trusted } -#> } +#> From 4001d129398de3e71b6cb1e86daddd26d1f57e9c Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 29 Jul 2021 15:17:08 -0400 Subject: [PATCH 053/276] Update cmdlet (#407) * Set up CI with Azure Pipelines [skip ci] * Set up CI with Azure Pipelines [skip ci] * Set up CI with Azure Pipelines [skip ci] * create new src directory * create new test directory * Begin refactoring Install * Fix bug in GetHelper class related to debug statement * Major refactors to Install helper * Update utils class * incorporate bug fixes * Add install bug fixes and tests * Update project to C# 7.2 * Add scope tests * create new src directory * made changes to paths created in InstallHelper and use Scope as string * Incorporate bug fixes for accept license, scripts, and installation paths * Add more install tests * remove comments used for debugging earlier * Clean up code and tests * remove some files accidentally added * Change scope to be a an Enum type * Delete azure-pipelines-1.yml * Delete azure-pipelines-2.yml * Delete azure-pipelines.yml * Address bugs introduced from changing Scope type to enum * Incorporate review feedback, clean up code a bit * Remove input object parameter * Remove string comparison in install helper Co-authored-by: Paul Higinbotham * Update src/code/PSResourceInfo.cs Co-authored-by: Paul Higinbotham * Address some code review suggestions * Add comments and incorporate other code review changes * add tests for Update * Add save functionality * Update InstallHelper with Save changes * remove NoClobber as Update parameter * Update src/code/InstallPSResource.cs Co-authored-by: Paul Higinbotham * Incorporate further code review changes * add IsPRerelease to AdditionalMetadata * resolve prerelease label issue * fix merge conflicts in tests * pull in Install test from master * pull in PSGetTestUtils form master * add helper for filtering wildcards that handles * * fix failing tests * resolve feedback from PR * add code to skip if not windows tests * rename Utils helper method and remove unecessary comments * add SupportShouldProcess * fix tests for updating with Scope, and use Get-InstalledPSResource instead of Get-Module * revert change to TryParseVersionOrVersionRange * remove cancellationToken * remove PSGalleryName variable not needed * update design and help docs for UpdatePSResource * remove comments from Update tests * remove call to Register-LocalRepo helper as is not needed * add test for AcceptLicense paramter * update test with AcceptLicense * update Install test for AcceptLicense * add whatIf test to update * resolve PR feedback and add skip to Unix AllUsers scope tests * remove references to NameParameterSet * add fix for failing MacOS tests Co-authored-by: alerickson <25858831+alerickson@users.noreply.github.com> Co-authored-by: Amber Erickson Co-authored-by: Paul Higinbotham --- Docs/UpdatePSResource.md | 36 +--- help/Update-PSResource.md | 77 +++---- src/PowerShellGet.psd1 | 4 +- src/code/UpdatePSResource.cs | 219 +++++++++++++++++++ src/code/Utils.cs | 48 ++++- test/InstallPSResource.Tests.ps1 | 2 +- test/UpdatePSResource.Tests.ps1 | 347 +++++++++++++++++++++++++++++++ 7 files changed, 652 insertions(+), 81 deletions(-) create mode 100644 src/code/UpdatePSResource.cs create mode 100644 test/UpdatePSResource.Tests.ps1 diff --git a/Docs/UpdatePSResource.md b/Docs/UpdatePSResource.md index c22376c9d..dceff9cd7 100644 --- a/Docs/UpdatePSResource.md +++ b/Docs/UpdatePSResource.md @@ -9,16 +9,11 @@ Other parameters allow the returned results to be further filtered. ### NameParameterSet (Default) ``` PowerShell -[[-Name] ] [-Version ] [-Prerelease] [-Scope ] +[[-Name] ] [-Version ] [-Prerelease] [-Scope ] [-Repository ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-NoClobber] [-WhatIf] [-Confirm] [] ``` -### InputObjectParameterSet -``` PowerShell -[[-InputObject] [-WhatIf] [-Confirm] [] -``` - ## Parameters ### -Name @@ -74,8 +69,8 @@ Parameter Sets: NameParameterSet Specifies the scope of the resource to update. ```yml -Type: string -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: NameParameterSet AllowedValues: 'CurrentUser','AllUsers' ``` @@ -85,7 +80,7 @@ Suppresses being prompted for untrusted sources. ```yml Type: SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Parameter Sets: NameParameterSet ``` ### -Credential @@ -115,22 +110,11 @@ Type: SwitchParameter Parameter Sets: (All) ``` -### -NoClobber - -Prevents updating modules that have the same cmdlets as a differently named module already - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - - ### Outputs No output. ## Notes -Input object still needs to be implemented. Should a -PassThru parameter be added? @@ -138,7 +122,7 @@ Should a -PassThru parameter be added? Most update tests can be performed on a local repository. -Some tests should be performed on remote repository (PSGallery) to verify remote operation, but can be limited. +Some tests should be performed on remote repository (PoshTestGallery) to verify remote operation, but can be limited. ### -Name param @@ -149,11 +133,6 @@ Some tests should be performed on remote repository (PSGallery) to verify remote - Errors: Not found (single name, wildcard, multiple name) - Errors: Repository: Invalid name, connection error, etc -### -Type InputObject - -- Validate pipeline input -- Errors: The object passed in is not the correct type - ### -Version param - Validate the resource is updated to the correct version @@ -193,11 +172,6 @@ Some tests should be performed on remote repository (PSGallery) to verify remote - Validate that modules which require license agreements are approved without a prompt -### -NoClobber - -- Validate that resources are not overwritten when flag is passed - - ## Work Items ### Create cmdlet and parameter sets diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 70478254c..158815573 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -8,39 +8,45 @@ schema: 2.0.0 # Update-PSResource ## SYNOPSIS -{{ Fill in the Synopsis }} +Updates a package already installed on the user's machine. ## SYNTAX ### NameParameterSet (Default) ``` Update-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-NoClobber] - [-WhatIf] [-Confirm] [] -``` - -### RequiredResourceFileParameterSet -``` -Update-PSResource [-Scope ] [-TrustRepository] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] - [] + [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -{{ Fill in the Description }} +The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. +It updates an already installed package based on the -Name parameter argument. +It does not return an object. Other parameters allow the package to be updated to be further filtered. ## EXAMPLES ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Get-InstalledPSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.2.0 test + + Update-PSResource -Name "TestModule" + Get-InstalledPSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.3.0 test + TestModule 1.2.0 test + ``` -{{ Add example description here }} +In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. ## PARAMETERS ### -AcceptLicense -{{ Fill AcceptLicense Description }} +For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. ```yaml Type: System.Management.Automation.SwitchParameter @@ -55,7 +61,7 @@ Accept wildcard characters: False ``` ### -Credential -{{ Fill Credential Description }} +Specifies optional credentials to be used when accessing a private repository. ```yaml Type: System.Management.Automation.PSCredential @@ -65,12 +71,12 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` ### -Name -{{ Fill Name Description }} +Specifies name of a resource or resources to update. ```yaml Type: System.String[] @@ -79,28 +85,13 @@ Aliases: Required: True Position: 0 -Default value: None +Default value: "*" Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` - -### -NoClobber -{{ Fill NoClobber Description }} - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -Prerelease -{{ Fill Prerelease Description }} +When specified, allows updating to a prerelease version. ```yaml Type: System.Management.Automation.SwitchParameter @@ -115,7 +106,7 @@ Accept wildcard characters: False ``` ### -Quiet -{{ Fill Quiet Description }} +Supresses progress information. ```yaml Type: System.Management.Automation.SwitchParameter @@ -130,7 +121,8 @@ Accept wildcard characters: False ``` ### -Repository -{{ Fill Repository Description }} +Specifies one or more repository names to update packages from. +If not specified, search for packages to update will include all currently registered repositories in order of highest priority. ```yaml Type: System.String[] @@ -145,10 +137,10 @@ Accept wildcard characters: False ``` ### -Scope -{{ Fill Scope Description }} +Specifies the scope of the resource to update. ```yaml -Type: System.String +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType Parameter Sets: (All) Aliases: Accepted values: CurrentUser, AllUsers @@ -161,7 +153,7 @@ Accept wildcard characters: False ``` ### -TrustRepository -{{ Fill TrustRepository Description }} +Specifies optional credentials to be used when accessing a private repository. ```yaml Type: System.Management.Automation.SwitchParameter @@ -176,7 +168,7 @@ Accept wildcard characters: False ``` ### -Version -{{ Fill Version Description }} +Specifies the version the resource is to be updated to. ```yaml Type: System.String @@ -228,15 +220,10 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.String[] -### System.Management.Automation.PSCredential - ## OUTPUTS -### System.Object - ## NOTES ## RELATED LINKS []() - diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 57fa37ce3..1fa277441 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -20,8 +20,8 @@ 'Set-PSResourceRepository', 'Publish-PSResource', 'Uninstall-PSResource', - 'Unregister-PSResourceRepository') - # 'Update-PSResource') + 'Unregister-PSResourceRepository', + 'Update-PSResource') VariablesToExport = 'PSGetPath' AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs new file mode 100644 index 000000000..de6bacac7 --- /dev/null +++ b/src/code/UpdatePSResource.cs @@ -0,0 +1,219 @@ +using System.Collections.Specialized; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using Dbg = System.Diagnostics.Debug; +using System.Linq; +using System.Management.Automation; +using System.Text; +using System.Threading; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. + /// It updates an already installed package based on the -Name parameter argument. + /// It does not return an object. Other parameters allow the package to be updated to be further filtered. + /// + + [Cmdlet(VerbsData.Update, + "PSResource", + SupportsShouldProcess = true)] + public sealed class UpdatePSResource : PSCmdlet + { + #region Members + private List _pathsToInstallPkg; + + #endregion + + #region Parameters + + /// + /// Specifies name of a resource or resources to update. + /// Accepts wildcard characters. + /// + [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set ; } = new string[] {"*"}; + + /// + /// Specifies the version the resource is to be updated to. + /// + [Parameter] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// When specified, allows updating to a prerelease version. + /// + [Parameter] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies one or more repository names to update packages from. + /// If not specified, search will include all currently registered repositories in order of highest priority. + /// + [Parameter] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies the scope of the resource to update. + /// + [Parameter] + public ScopeType Scope { get; set; } + + /// + /// When specified, supresses being prompted for untrusted sources. + /// + [Parameter] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Specifies optional credentials to be used when accessing a private repository. + /// + [Parameter] + public PSCredential Credential { get; set; } + + /// + /// Supresses progress information. + /// + [Parameter] + public SwitchParameter Quiet { get; set; } + + /// + /// For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + /// + [Parameter] + public SwitchParameter AcceptLicense { get; set; } + + /// + /// When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + /// + [Parameter] + public SwitchParameter Force { get; set; } + + #endregion + + #region Override Methods + + protected override void BeginProcessing() + { + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); + } + + protected override void ProcessRecord() + { + VersionRange versionRange; + + // handle case where Version == null + if (Version == null) { + versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out versionRange)) + { + // Only returns false if the range was incorrectly formatted and couldn't be parsed. + WriteError(new ErrorRecord( + new PSInvalidOperationException("Cannot parse Version parameter provided into VersionRange"), + "ErrorParsingVersionParamIntoVersionRange", + ErrorCategory.InvalidArgument, + this)); + return; + } + + var namesToUpdate = ProcessPackageNameWildCards(Name, versionRange); + + if (namesToUpdate.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("package to update: '{0}'", String.Join(", ", Name)))) + { + WriteVerbose(string.Format("Update is cancelled by user for: {0}", String.Join(", ", Name))); + return; + } + + InstallHelper installHelper = new InstallHelper( + updatePkg: true, + savePkg: false, + cmdletPassedIn: this); + + installHelper.InstallPackages( + names: namesToUpdate, + versionRange: versionRange, + prerelease: Prerelease, + repository: Repository, + acceptLicense: AcceptLicense, + quiet: Quiet, + reinstall: false, + force: Force, + trustRepository: TrustRepository, + noClobber: false, + credential: Credential, + requiredResourceFile: null, + requiredResourceJson: null, + requiredResourceHash: null, + specifiedPath: null, + asNupkg: false, + includeXML: true, + pathsToInstallPkg: _pathsToInstallPkg); + } + + #endregion + #region Private Methods + + /// + /// This method checks all provided package names for wild card characters and removes any name containing invalid characters. + /// If any name contains a single '*' wildcard character then it is returned alone, indicating all packages should be processed. + /// + private string[] ProcessPackageNameWildCards(string[] namesToProcess, VersionRange versionRange) + { + namesToProcess = Utils.ProcessNameWildcards(namesToProcess, out string[] errorMsgs, out bool nameContainsWildcard); + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // this catches the case where namesToProcess wasn't passed in as null or empty, + // but after filtering out unsupported wildcard names there are no elements left in namesToProcess + if (namesToProcess.Length == 0) + { + return namesToProcess; + } + + if (String.Equals(namesToProcess[0], "*", StringComparison.InvariantCultureIgnoreCase)) + { + WriteVerbose("Package names were detected to be (or contain an element equal to): '*', so all packages will be updated"); + } + + if (nameContainsWildcard) + { + // if any of the namesToProcess entries contains a supported wildcard + // then we need to use GetHelper (Get-InstalledPSResource logic) to find which packages are installed that match + // the wildcard pattern name for each package name with wildcard + + GetHelper getHelper = new GetHelper( + cmdletPassedIn: this); + + namesToProcess = getHelper.FilterPkgPaths( + name: namesToProcess, + versionRange: versionRange, + pathsToSearch: Utils.GetAllResourcePaths(this)).Select(p => p.Name).ToArray(); + } + + return namesToProcess; + } + #endregion + } +} \ No newline at end of file diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 492d07025..c5155ffc0 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -66,6 +66,52 @@ public static string[] GetStringArray(ArrayList list) return strArray; } + public static string[] ProcessNameWildcards( + string[] pkgNames, + out string[] errorMsgs, + out bool isContainWildcard) + { + List namesWithSupportedWildcards = new List(); + List errorMsgsList = new List(); + + if (pkgNames == null) + { + isContainWildcard = true; + errorMsgs = errorMsgsList.ToArray(); + return new string[] {"*"}; + } + + isContainWildcard = false; + foreach (string name in pkgNames) + { + if (WildcardPattern.ContainsWildcardCharacters(name)) + { + if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) + { + isContainWildcard = true; + errorMsgs = new string[] {}; + return new string[] {"*"}; + } + + if (name.Contains("?") || name.Contains("[")) + { + errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); + continue; + } + + isContainWildcard = true; + namesWithSupportedWildcards.Add(name); + } + else + { + namesWithSupportedWildcards.Add(name); + } + } + + errorMsgs = errorMsgsList.ToArray(); + return namesWithSupportedWildcards.ToArray(); + } + public static string[] FilterOutWildcardNames( string[] pkgNames, out string[] errorMsgs) @@ -145,10 +191,8 @@ public static bool TryParseVersionOrVersionRange( out VersionRange versionRange) { versionRange = null; - if (version == null) { return false; } - if (version.Trim().Equals("*")) { versionRange = VersionRange.All; diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 33bc966af..3ee94b389 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -189,7 +189,7 @@ Describe 'Test Install-PSResource for Module' { Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName -AcceptLicense $pkg = Get-InstalledPSResource "testModuleWithlicense" $pkg.Name | Should -Be "testModuleWithlicense" - $pkg.Version | Should -Be "0.0.1.0" + $pkg.Version | Should -Be "0.0.3.0" } It "Install resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 new file mode 100644 index 000000000..12c84574c --- /dev/null +++ b/test/UpdatePSResource.Tests.ps1 @@ -0,0 +1,347 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Update-PSResource' { + + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $NuGetGalleryName = Get-NuGetGalleryName + Get-NewPSResourceRepositoryFile + Get-PSResourceRepository + } + + AfterEach { + Uninstall-PSResource "TestModule", "TestModule99", "TestModuleWithLicense", "PSGetTestModule" + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "update resource installed given Name parameter" { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + + Update-PSResource -Name "TestModule" -Repository $TestGalleryName + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + It "update resources installed given Name (with wildcard) parameter" { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name "TestModule99" -Version "0.0.4.0" -Repository $TestGalleryName + + Update-PSResource -Name "TestModule*" -Repository $TestGalleryName + $res = Get-InstalledPSResource -Name "TestModule*" + + $inputHashtable = @{TestModule = "1.1.0.0"; TestModule99 = "0.0.4.0"} + $isTestModuleUpdated = $false + $isTestModule99Updated = $false + foreach ($item in $res) + { + if ([System.Version]$item.Version -gt [System.Version]$inputHashtable[$item.Name]) + { + if ($item.Name -like "TestModule") + { + $isTestModuleUpdated = $true + } + elseif ($item.Name -like "TestModule99") + { + $isTestModule99Updated = $true + } + } + } + + $isTestModuleUpdated | Should -BeTrue + $isTestModule99Updated | Should -BeTrue + } + + It "update resource installed given Name and Version (specific) parameters" { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + + Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName + $res = Get-InstalledPSResource -Name "TestModule" + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -eq [System.Version]"1.2.0.0") + { + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -BeTrue + } + + $testCases2 = @{Version="[1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, exact match"}, + @{Version="1.3.0.0"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.1.1.0, 1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(1.1.1.0, 1.3.0.0)"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(1.1.1.0,)"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[1.1.1.0,)"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,1.3.0.0)"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, maximum version exclusive"}, + @{Version="(,1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[1.1.1.0, 1.3.0.0)"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + @{Version="(1.1.1.0, 1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} + + It "update resource when given Name to " -TestCases $testCases2{ + param($Version, $ExpectedVersions) + + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName + + $res = Get-InstalledPSResource -Name "TestModule" + + foreach ($item in $res) { + $item.Name | Should -Be "TestModule" + $ExpectedVersions | Should -Contain $item.Version + } + } + + $testCases = @( + @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, + @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + ) + It "Should not update resource with incorrectly formatted version such as " -TestCases $testCases{ + param($Version, $Description) + + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName + + $res = Get-InstalledPSResource -Name "TestModule" + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $false + } + + It "update resource with latest (including prerelease) version given Prerelease parameter" { + # PSGetTestModule resource's latest version is a prerelease version, before that it has a non-prerelease version + + Install-PSResource -Name "PSGetTestModule" -Version "1.0.2.0" -Repository $TestGalleryName + Update-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName + $res = Get-InstalledPSResource -Name "PSGetTestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.2.0") + { + $pkg.PrereleaseLabel | Should -Be "alpha1" + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + # Windows only + It "update resource under CurrentUser scope" -skip:(!$IsWindows) { + # TODO: perhaps also install TestModule with the highest version (the one above 1.2.0.0) to the AllUsers path too + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + + Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -Scope CurrentUser + + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $pkg.InstalledLocation.Contains("Documents") | Should -Be $true + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + # Windows only + It "update resource under AllUsers scope" -skip:(!$IsWindows) { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + + Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -Scope AllUsers + + $res = Get-InstalledPSResource -Name "TestModule" + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $pkg.InstalledLocation.Contains("Program Files") | Should -Be $true + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + # Windows only + It "update resource under no specified scope" -skip:(!$IsWindows) { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName + + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $pkg.InstalledLocation.Contains("Documents") | Should -Be $true + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + # Unix only + # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' + It "Update resource under CurrentUser scope - Unix only" -Skip:(Get-IsWindows) { + # this line is commented out because AllUsers scope requires sudo and that isn't supported in CI yet + # Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + + Update-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser + + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $pkg.InstalledLocation.Contains("$env:HOME/.local") | Should -Be $true + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + # Unix only + # Expected path should be similar to: '/usr/local/share/powershell/Modules' + # this test is skipped because it requires sudo to run and has yet to be resolved in CI + It "Update resource under AllUsers scope - Unix only" -Skip:($true) { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + + Update-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers + + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $pkg.InstalledLocation.Contains("usr") | Should -Be $true + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + # Unix only + # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' + It "Update resource under no specified scope - Unix only" -Skip:(Get-IsWindows) { + # this is commented out because it requires sudo to run with AllUsers scope and this hasn't been resolved in CI yet + # Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + + Update-PSResource -Name "TestModule" -Repository $TestGalleryName + + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $pkg.InstalledLocation.Contains("$env:HOME/.local") | Should -Be $true + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + It "update resource that requires accept license with -AcceptLicense flag" { + Install-PSResource -Name "TestModuleWithLicense" -Version "0.0.1.0" -Repository $TestGalleryName -AcceptLicense + Update-PSResource -Name "TestModuleWithLicense" -Repository $TestGalleryName -AcceptLicense + $res = Get-InstalledPSResource "TestModuleWithLicense" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"0.0.1.0") + { + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $true + } + + It "update resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + + Set-PSResourceRepository PoshTestGallery -Trusted:$false + + Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -TrustRepository + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -BeTrue + Set-PSResourceRepository PoshTestGallery -Trusted + } + + It "Update module using -WhatIf, should not update the module" { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name "TestModule" -WhatIf + + $res = Get-InstalledPSResource -Name "TestModule" + + $isPkgUpdated = $false + foreach ($pkg in $res) + { + if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + { + $isPkgUpdated = $true + } + } + + $isPkgUpdated | Should -Be $false + } +} \ No newline at end of file From 8c92787b8767da3942a9feeb6f8f6808b9cb61e2 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 29 Jul 2021 18:06:27 -0400 Subject: [PATCH 054/276] Install should implement ShouldProcess (#425) * Install should impelement ShouldProcess --- src/code/InstallPSResource.cs | 9 ++++++++- test/InstallPSResource.Tests.ps1 | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 51a7a3fc8..dee8e3e4e 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -1,3 +1,4 @@ +using System.Collections.Specialized; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; @@ -15,7 +16,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// It returns nothing. /// - [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, HelpUri = "")] + [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] public sealed class InstallPSResource : PSCmdlet { @@ -124,6 +125,12 @@ protected override void BeginProcessing() protected override void ProcessRecord() { + if (!ShouldProcess(string.Format("package to install: '{0}'", String.Join(", ", Name)))) + { + WriteVerbose(string.Format("Install operation cancelled by user for packages: {0}", String.Join(", ", Name))); + return; + } + var installHelper = new InstallHelper(updatePkg: false, savePkg: false, cmdletPassedIn: this); switch (ParameterSetName) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 3ee94b389..503f17bb6 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -226,6 +226,13 @@ Describe 'Test Install-PSResource for Module' { $pkg | Should -Not -BeNullOrEmpty $pkg.Name | Should -Be $publishModuleName } + + It "Install module using -WhatIf, should not install the module" { + Install-PSResource -Name "TestModule" -WhatIf + + $res = Get-Module "TestModule" -ListAvailable + $res | Should -BeNullOrEmpty + } } <# Temporarily commented until -Tag is implemented for this Describe block From 2e6f965daee265db102366f44553ebf7da0c6f85 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 30 Jul 2021 16:14:20 -0400 Subject: [PATCH 055/276] Preview tag support (#428) find prerelease version if version contains tag but prerelease parameter not used --- src/code/FindHelper.cs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 5de3044d0..a8b942dd3 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -251,6 +251,25 @@ private IEnumerable FindFromPackageSourceSearchAPI( SourceCacheContext sourceContext) { List foundPackagesMetadata = new List(); + VersionRange versionRange = null; + + if (_version != null) + { + if (!Utils.TryParseVersionOrVersionRange(_version, out versionRange)) + { + _cmdletPassedIn.WriteError(new ErrorRecord( + new ArgumentException("Argument for -Version parameter is not in the proper format"), + "IncorrectVersionFormat", + ErrorCategory.InvalidArgument, + this)); + yield break; + } + + if (_version.Contains("-")) + { + _prerelease = true; + } + } // filter by param: Name if (!pkgName.Contains("*")) @@ -382,16 +401,6 @@ private IEnumerable FindFromPackageSourceSearchAPI( } else { - if (!Utils.TryParseVersionOrVersionRange(_version, out VersionRange versionRange)) - { - _cmdletPassedIn.WriteError(new ErrorRecord( - new ArgumentException("Argument for -Version parameter is not in the proper format"), - "IncorrectVersionFormat", - ErrorCategory.InvalidArgument, - this)); - yield break; - } - // at this point, version should be parsed successfully, into allVersions (null or "*") or versionRange (specific or range) if (pkgName.Contains("*")) { From 02a85cc4164f6df97291b0d81e4aa06c898c9c16 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 2 Aug 2021 14:20:30 -0400 Subject: [PATCH 056/276] Find tests (#429) * add tests for FindPSResource package name with wildcards and version combinations * add test for invalid wildcard character names --- test/FindPSResource.Tests.ps1 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index fd24878e3..5b722f10b 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -27,6 +27,12 @@ Describe 'Test Find-PSResource for Module' { $res | Should -BeNullOrEmpty } + It "should not find any resources given names with invalid wildcard characters" { + Find-PSResource -Name "Invalid?PkgName", "Invalid[PkgName" -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorFilteringNamesForUnsupportedWildcards,Microsoft.PowerShell.PowerShellGet.Cmdlets.FindPSResource" + } + It "find resources when Name contains * from V2 endpoint repository (PowerShellGallery))" { $foundScript = $False $res = Find-PSResource -Name "AzureS*" -Repository $PSGalleryName @@ -108,6 +114,30 @@ Describe 'Test Find-PSResource for Module' { $res.Count | Should -BeGreaterOrEqual 1 } + It "find resources when given Name with wildcard, Version not null --> '*'" { + $res = Find-PSResource -Name "TestModuleWithDependency*" -Version "*" -Repository $TestGalleryName + $moduleA = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyA"} + $moduleA.Count | Should -BeGreaterOrEqual 3 + $moduleB = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyB"} + $moduleB.Count | Should -BeGreaterOrEqual 2 + $moduleC = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyC"} + $moduleC.Count | Should -BeGreaterOrEqual 3 + $moduleD = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyD"} + $moduleD.Count | Should -BeGreaterOrEqual 2 + $moduleE = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyE"} + $moduleE.Count | Should -BeGreaterOrEqual 1 + $moduleF = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyF"} + $moduleF.Count | Should -BeGreaterOrEqual 1 + } + + It "find resources when given Name with wildcard, Version range" { + $res = Find-PSResource -Name "TestModuleWithDependency*" -Version "[1.0.0.0, 2.0.0.0]" -Repository $TestGalleryName + foreach ($pkg in $res) { + $pkg.Name | Should -Match "TestModuleWithDependency*" + [System.Version]$pkg.Version -ge [System.Version]"1.0.0.0" -or [System.Version]$pkg.Version -le [System.Version]"2.0.0.0" | Should -Be $true + } + } + It "find resource when given Name, Version param null" { $res = Find-PSResource -Name "Carbon" -Repository $PSGalleryName $res.Name | Should -Be "Carbon" From 1863cf09232d4a74ba8b8d2792875e6277995d5c Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 2 Aug 2021 11:38:18 -0700 Subject: [PATCH 057/276] Temporarily remove unimplemented DestintationPath parameter (#431) --- src/code/PublishPSResource.cs | 32 ++++++++------------------------ test/PublishPSResource.Tests.ps1 | 10 ---------- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 5afc9ed62..0fb371bff 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -1,6 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using MoreLinq; +using MoreLinq.Extensions; +using NuGet.Commands; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Packaging; +using NuGet.Versioning; using System; using System.Collections; using System.Collections.Generic; @@ -10,15 +18,6 @@ using System.Management.Automation.Language; using System.Net.Http; using System.Xml; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using MoreLinq; -using MoreLinq.Extensions; -using NuGet.Commands; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging; -using NuGet.Versioning; - namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -45,21 +44,6 @@ public sealed class PublishPSResource : PSCmdlet [ArgumentCompleter(typeof(RepositoryNameCompleter))] public string Repository { get; set; } - /// - /// Can be used to publish a nupkg locally. - /// - [Parameter()] - [ValidateNotNullOrEmpty] - public string DestinationPath - { - get - { return _destinationPath; } - - set - { _destinationPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } - } - private string _destinationPath; - /// /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 0ed7016cb..2a49a1799 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -74,16 +74,6 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } - It "Publish a module with -Path and -DestinationPath" { - $version = "1.0.0" - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" - - Publish-PSResource -Path $script:PublishModuleBase -DestinationPath $script:destinationPath - - $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath - } - It "Publish a module with -LiteralPath" { $version = "1.0.0" New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" From 45996c91a660db867e814134d4df81e63866bb85 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 3 Aug 2021 11:37:41 -0400 Subject: [PATCH 058/276] Wildcard processing (#432) make wildcard support/error handling consistent across cmdlets --- src/code/FindPSResource.cs | 19 +++++++++++++-- src/code/GetInstalledPSResource.cs | 38 ++++++++++++++---------------- src/code/InstallPSResource.cs | 29 ++++++++++++++++++++++- src/code/SavePSResource.cs | 29 ++++++++++++++++++++++- src/code/UninstallPSResource.cs | 21 ++++++++++++++++- src/code/Utils.cs | 36 ---------------------------- test/FindPSResource.Tests.ps1 | 6 +++++ test/InstallPSResource.Tests.ps1 | 12 +++++++++- test/SavePSResource.Tests.ps1 | 6 +++++ test/UninstallPSResource.Tests.ps1 | 10 ++++++++ 10 files changed, 144 insertions(+), 62 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 12b3f4cb7..ba3016de3 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using Dbg = System.Diagnostics.Debug; using System.Linq; @@ -198,7 +199,8 @@ private void ProcessResourceNameParameterSet() this)); } - Name = Utils.FilterOutWildcardNames(Name, out string[] errorMsgs); + var namesToSearch = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard); + foreach (string error in errorMsgs) { WriteError(new ErrorRecord( @@ -208,8 +210,21 @@ private void ProcessResourceNameParameterSet() this)); } - if (Name.Length == 0) + // 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)) { + // 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; } diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index db1974781..7928c6e4c 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -106,33 +106,31 @@ protected override void BeginProcessing() // retrieve all possible paths _pathsToSearch = Utils.GetAllResourcePaths(this); } - - if (Name == null) - { - Name = new string[] { "*" }; - } - // if '*' is passed in as an argument for -Name with other -Name arguments, - // ignore all arguments except for '*' since it is the most inclusive - // eg: -Name ["TestModule, Test*, *"] will become -Name ["*"] - if (Name != null && Name.Length > 1) - { - foreach (var pkgName in Name) - { - if (pkgName.Trim().Equals("*")) - { - Name = new string[] { "*" }; - break; - } - } - } } protected override void ProcessRecord() { WriteDebug("Entering GetInstalledPSResource"); + var namesToSearch = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool _); + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // this catches the case where Name wasn't passed in as null or empty, + // but after filtering out unsupported wildcard names in BeginProcessing() there are no elements left in Name + if (namesToSearch.Length == 0) + { + return; + } + GetHelper getHelper = new GetHelper(this); - foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(Name, _versionRange, _pathsToSearch)) + foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(namesToSearch, _versionRange, _pathsToSearch)) { WriteObject(pkg); } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index dee8e3e4e..d546e6b4a 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -136,8 +136,35 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: + var namesToInstall = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Install-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToInstall + if (namesToInstall.Length == 0) + { + return; + } + installHelper.InstallPackages( - names: Name, + names: namesToInstall, versionRange: _versionRange, prerelease: Prerelease, repository: Repository, diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index a68496dd6..ff4832ce0 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -151,8 +151,35 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: + var namesToSave = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToSave + if (namesToSave.Length == 0) + { + return; + } + installHelper.InstallPackages( - names: Name, + names: namesToSave, versionRange: _versionRange, prerelease: Prerelease, repository: Repository, diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 0a69e4617..5081d039b 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,3 +1,4 @@ +using System.Text; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; @@ -16,7 +17,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// /// Uninstall-PSResource uninstalls a package found in a module or script installation path. /// - [Cmdlet(VerbsLifecycle.Uninstall, "PSResource", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true, HelpUri = "")] + [Cmdlet(VerbsLifecycle.Uninstall, "PSResource", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true)] public sealed class UninstallPSResource : PSCmdlet { #region Parameters @@ -83,6 +84,24 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: + Name = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool _); + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 Name + if (Name.Length == 0) + { + return; + } + if (!UninstallPkgHelper()) { // any errors should be caught lower in the stack, this debug statement will let us know if there was an unusual failure diff --git a/src/code/Utils.cs b/src/code/Utils.cs index c5155ffc0..8b2fa3a29 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -111,42 +111,6 @@ public static string[] ProcessNameWildcards( errorMsgs = errorMsgsList.ToArray(); return namesWithSupportedWildcards.ToArray(); } - - public static string[] FilterOutWildcardNames( - string[] pkgNames, - out string[] errorMsgs) - { - List errorFreeNames = new List(); - List errorMsgList = new List(); - - foreach (string n in pkgNames) - { - bool isNameErrorProne = false; - if (WildcardPattern.ContainsWildcardCharacters(n)) - { - if (String.Equals(n, "*", StringComparison.InvariantCultureIgnoreCase)) - { - errorMsgList = new List(); // clear prior error messages - errorMsgList.Add("-Name '*' is not supported for Find-PSResource so all Name entries will be discarded."); - errorFreeNames = new List(); - break; - } - else if (n.Contains("?") || n.Contains("[")) - { - errorMsgList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for Find-PSResource so Name entry: {0} will be discarded.", n)); - isNameErrorProne = true; - } - } - - if (!isNameErrorProne) - { - errorFreeNames.Add(n); - } - } - - errorMsgs = errorMsgList.ToArray(); - return errorFreeNames.ToArray(); - } #endregion diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 5b722f10b..71805f03c 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -48,6 +48,12 @@ 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 "find resource given Name from V3 endpoint repository (NuGetGallery)" { $res = Find-PSResource -Name "Serilog" -Repository $NuGetGalleryName $res.Count | Should -Be 1 diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 503f17bb6..ef206fece 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -22,6 +22,17 @@ Describe 'Test Install-PSResource for Module' { Get-RevertPSResourceRepositoryFile } + $testCases = @{Name="*"; ErrorId="NameContainsWildcard"}, + @{Name="TestModule*"; ErrorId="NameContainsWildcard"}, + @{Name="Test?Module","Test[Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"} + + It "Should not install resource with wildcard in name" -TestCases $testCases { + param($Name, $ErrorId) + Install-PSResource -Name $Name -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + } + It "Install specific module resource by name" { Install-PSResource -Name "TestModule" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable @@ -43,7 +54,6 @@ Describe 'Test Install-PSResource for Module' { $pkg.Name | Should -Be $pkgNames } - It "Should not install resource given nonexistant name" { Install-PSResource -Name NonExistantModule -Repository $TestGalleryName $pkg = Get-Module "NonExistantModule" -ListAvailable diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 6a20641e3..7f107b21f 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -54,6 +54,12 @@ Describe 'Test Save-PSResource for PSResources' { $pkgDir.Name | Should -BeNullOrEmpty } + It "Not Save module with Name containing wildcard" { + Save-PSResource -Name "TestModule*" -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "NameContainsWildcard,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + # Do some version testing, but Find-PSResource should be doing thorough testing It "Should save resource given name and exact version" { Save-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 511f43016..f20e967ae 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -23,6 +23,16 @@ Describe 'Test Uninstall-PSResource for Modules' { Get-Module ContosoServer -ListAvailable | Should -Be $null } + $testCases = @{Name="Test?Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"}, + @{Name="Test[Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"} + + It "not uninstall module given Name with invalid wildcard characters" -TestCases $testCases { + param($Name, $ErrorId) + Uninstall-PSResource -Name $Name -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource" + } + It "Uninstall a list of modules by name" { $null = Install-PSResource BaseTestPackage -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue From 91e32d4f85339193f577910fc96cb34af205e2a0 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 3 Aug 2021 14:08:04 -0400 Subject: [PATCH 059/276] Update help files for {Update, Find}-PSResource and {Register, Set, Get, Unregister}-PSResourceRepository (#434) update help docs --- help/Find-PSResource.md | 21 ++++++--------------- help/Get-PSResourceRepository.md | 6 ++++-- help/Register-PSResourceRepository.md | 21 +++++++++++++-------- help/Set-PSResourceRepository.md | 24 +++++++++++------------- help/Unregister-PSResourceRepository.md | 4 +++- help/Update-PSResource.md | 10 ++++++---- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index a29c9bb27..9c0f8b892 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -1,22 +1,20 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- # Find-PSResource ## SYNOPSIS -Searches for packages from a repository (local or remote), based on Name or other package properties. - +Searches for packages from a repository (local or remote), based on `-Name` and other package properties. ## SYNTAX ### ResourceNameParameterSet (Default) ``` PowerShell -[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tag ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` ### CommandNameParameterSet @@ -44,7 +42,7 @@ Searches for packages from a repository (local or remote), based on Name or othe ``` ## DESCRIPTION -The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on Name or other package properties. +The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. ## EXAMPLES These examples assume that the PSGallery repository is registered and contains the packages we are searching for. @@ -162,7 +160,7 @@ Accept wildcard characters: False ### -Repository Specifies one or more repository names to search. -If not specified, search will include all currently registered repositories, in order of highest priority, til first repository package is found in. +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 Type: System.String[] @@ -210,6 +208,7 @@ Accept wildcard characters: False ### -Version Specifies the version of the resource to be returned. +Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges ```yaml Type: System.String @@ -261,14 +260,6 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.String[] -### System.String - -### System.Management.Automation.PSCredential - -### System.Management.Automation.SwitchParameter - -### Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - ## OUTPUTS ### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo diff --git a/help/Get-PSResourceRepository.md b/help/Get-PSResourceRepository.md index cb3f7e77f..a2aeff8ea 100644 --- a/help/Get-PSResourceRepository.md +++ b/help/Get-PSResourceRepository.md @@ -17,7 +17,7 @@ Get-PSResourceRepository [[-Name] ] [] ``` ## DESCRIPTION -The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the -Name parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. +The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. ## EXAMPLES @@ -71,7 +71,7 @@ This example runs the command with the 'Name' parameter being set to a single wi ## PARAMETERS ### -Name -This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. +This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. ```yaml Type: String[] @@ -91,9 +91,11 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS ### System.String[] + ## OUTPUTS ### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo + ## NOTES If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index 698267ab3..a676178d2 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -14,7 +14,7 @@ Registers a repository for PowerShell resources. ### NameParameterSet (Default) ``` -Register-PSResourceRepository [-Name] [-URL] [-Trusted] [-Priority ] [-PassThru] +Register-PSResourceRepository [-Name] [-URL] [-Trusted] [-Priority ] [-PassThru] [-WhatIf] [-Confirm] [] ``` @@ -33,7 +33,7 @@ Register-PSResourceRepository -Repositories [-PassThru] [-WhatIf] The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. ## EXAMPLES -These examples assume that the repository we attempt to reigster is not already registered on the user's machine. +These examples assume that the repository we attempt to register is not already registered on the user's machine. ### Example 1 ``` PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -URL "https://www.powershellgallery.com/api/v2" @@ -43,7 +43,7 @@ PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 ``` -This example registers the repository with the 'Name' of "PoshTestGallery" along with the associated 'URL' value for it. +This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `URL` value for it. ### Example 2 ``` @@ -54,7 +54,7 @@ PS C:\> Get-PSResourceRepository -Name "PSGallery" PSGallery https://www.powershellgallery.com/api/v2 False 50 ``` -This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the 'Name' or 'URL' parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for URL. +This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-URL` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for URL. ### Example 3 ``` @@ -68,12 +68,13 @@ PS C:\> Get-PSResourceRepository ``` -This example registers multiple repositories at once. To do so, we use the 'Repositories' parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. +This example registers multiple repositories at once. To do so, we use the `-Repositories` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. ## PARAMETERS ### -Name Name of the repository to be registered. +Cannot be "PSGallery". ```yaml Type: String @@ -153,7 +154,7 @@ Specifies the location of the repository to be registered. URL can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. ```yaml -Type: Uri +Type: String Parameter Sets: NameParameterSet Aliases: @@ -216,12 +217,16 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS ### System.String -### System.Uri + ## OUTPUTS -### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) + ## NOTES Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. + Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'URL' parameters). +URL string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File + ## RELATED LINKS diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index 1b2e76236..a775ad574 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -1,7 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- @@ -14,7 +14,7 @@ Sets information for a registered repository. ### NameParameterSet (Default) ``` -Set-PSResourceRepository [-Name] [-URL ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository [-Name] [-URL ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet @@ -26,7 +26,7 @@ Set-PSResourceRepository -Repositories [-Priority ] [-WhatI The Set-PSResourceRepository cmdlet sets information for a registered repository. ## EXAMPLES -These examples are run independently of each other and assume the repositories used are already registered. The 'PassThru' parameter used with Set-PSResourceRepository is only used to display the changes made to the repository and is not mandatory. +These examples are run independently of each other and assume the repositories used are already registered. The `-PassThru` parameter used with Set-PSResourceRepository is only used to display the changes made to the repository and is not mandatory. ### Example 1 ```powershell PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" @@ -39,7 +39,7 @@ PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -URL "c:/code/testdir" PoshTestGallery file:///c:/code/testdir False 50 ``` -This example first checks if the PoshTestGallery repository has been registered. We wish to set the 'URL' value of this repository by running the Set-PSResourceRepository cmdlet with the 'URL' parameter and a valid Uri scheme url. We run the Get-PSResourceRepository cmdlet again to ensure that the 'URL' of the repository was changed. We also use the 'PassThru' parameter to see the changed repository. +This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-URL` value of this repository by running the Set-PSResourceRepository cmdlet with the `-URL` parameter and a valid Uri scheme url. We run the Get-PSResourceRepository cmdlet again to ensure that the `-URL` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. ### Example 2 ```powershell @@ -53,7 +53,7 @@ PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassTh PSGallery https://www.powershellgallery.com/api/v2 True 25 ``` -This example first checks if the PSGallery repository has been registered. We wish to set the 'Priority' and 'Trusted' values of this repository by running the Set-PSResourceRepository cmdlet with the 'Priority' parameter set to a value between 0 and 50 and by using the 'Trusted' parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the 'Priority' and 'Trusted' values of the repository were changed. An important note here is that just for the default PSGallery repository, the 'URL' value can't be changed/set. We also use the 'PassThru' parameter to see the changed repository. +This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-URL` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. ### Example 3 ```powershell @@ -62,7 +62,9 @@ PS C:\> Get-PSResourceRepository -Name "*" ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True},@{Name = "PoshTestGallery"; URL = "c:/code/testdir"} + PS C:\> Set-PSResourceRepository -Repositories $arrayOfHashtables -PassThru Name Url Trusted Priority ---- --- ------- -------- @@ -70,7 +72,7 @@ PS C:\> Set-PSResourceRepository -Repositories $arrayOfHashtables -PassThru PoshTestGallery file:///c:/code/testdir False 50 ``` -This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the 'Repositories' parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the 'PassThru' parameter to see the changed repositories. +This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repositories` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. ## PARAMETERS @@ -105,7 +107,7 @@ Accept wildcard characters: False ``` ### -Repositories -Specifies a hashtable of repositories and is used to register multiple repositories at once. +Specifies a hashtable of repositories and is used to set multiple repositories at once. ```yaml Type: Hashtable[] @@ -138,14 +140,14 @@ Accept wildcard characters: False Specifies the location of the repository to be set. ```yaml -Type: System.Uri +Type: String Parameter Sets: NameParameterSet Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` @@ -187,12 +189,8 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.String -### System.Uri - ### System.Collections.Hashtable[] -### System.Int32 - ## OUTPUTS ### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) diff --git a/help/Unregister-PSResourceRepository.md b/help/Unregister-PSResourceRepository.md index e875af838..95f69b31f 100644 --- a/help/Unregister-PSResourceRepository.md +++ b/help/Unregister-PSResourceRepository.md @@ -49,7 +49,7 @@ PS C:\> Get-PSResourceRepository ``` -In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the 'Name' parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. +In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. ## PARAMETERS @@ -105,9 +105,11 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS ### System.String[] + ## OUTPUTS None + ## NOTES ## RELATED LINKS diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 158815573..8ee64d319 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -1,7 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +online version: schema: 2.0.0 --- @@ -20,7 +20,7 @@ Update-PSResource [-Name] [-Version ] [-Prerelease] [-Reposit ## DESCRIPTION The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. -It updates an already installed package based on the -Name parameter argument. +It updates an already installed package based on the `-Name` parameter argument. It does not return an object. Other parameters allow the package to be updated to be further filtered. ## EXAMPLES @@ -32,8 +32,9 @@ PS C:\> Get-InstalledPSResource -Name "TestModule" ---- ------- ---------- ----------- TestModule 1.2.0 test - Update-PSResource -Name "TestModule" - Get-InstalledPSResource -Name "TestModule" +PS C:\> Update-PSResource -Name "TestModule" + +PS C:\> Get-InstalledPSResource -Name "TestModule" Name Version Prerelease Description ---- ------- ---------- ----------- TestModule 1.3.0 test @@ -169,6 +170,7 @@ Accept wildcard characters: False ### -Version Specifies the version the resource is to be updated to. +Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges ```yaml Type: System.String From 87ed19e828fc41da93e7fba23e4a73f09e05ef0c Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:59:10 -0700 Subject: [PATCH 060/276] Update help files for {Get-Installed, Install, Publish, Save, and Uninstall}-PSResource (#435) --- help/Get-InstalledPSResource.md | 24 ++-- help/Install-PSResource.md | 214 +++++++++----------------------- help/Publish-PSResource.md | 64 ++++------ help/Save-PSResource.md | 121 +++++++++--------- help/Uninstall-PSResource.md | 11 +- 5 files changed, 168 insertions(+), 266 deletions(-) diff --git a/help/Get-InstalledPSResource.md b/help/Get-InstalledPSResource.md index bb3a76b17..d5b320ab1 100644 --- a/help/Get-InstalledPSResource.md +++ b/help/Get-InstalledPSResource.md @@ -17,7 +17,7 @@ Get-InstalledPSResource [[-Name] ] [-Version ] [-Path ``` ## DESCRIPTION -The Get-InstalledPSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describe each resource item found. Other parameters allow the returned results to be filtered by version and path. +The Get-InstalledPSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. ## EXAMPLES @@ -49,14 +49,21 @@ PS C:\> Get-InstalledPSResource Az -Path . This will return all versions of the Az module that have been installed in the current directory. +### Example 5 +```powershell +PS C:\> Get-InstalledPSResource +``` + +This will return all versions and scripts installed on the machine. + ## PARAMETERS ### -Name -Name of a resource or resources to find. Accepts wild card characters. +Name of a resource or resources to find. Accepts wild card characters or a null value. ```yaml Type: System.String[] -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -71,7 +78,7 @@ Specifies the path to search in. ```yaml Type: System.String -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -82,11 +89,13 @@ Accept wildcard characters: False ``` ### -Version -Specifies the version of the resource to be returned. Can be an exact version or a version range. +Specifies the version of the resource to be returned. +Can be an exact version or a version range, using the NuGet versioning syntax. +Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges ```yaml Type: System.String -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -103,7 +112,7 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo ``` -PSRepositoryItemInfo : { +PSResourceInfo : { AdditionalMetadata Author CompanyName @@ -119,6 +128,7 @@ PSRepositoryItemInfo : { Name PackageManagementProvider PowerShellGetFormatVersion + PrereleaseLabel ProjectUri PublishedDate ReleaseNotes diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 187ae7a25..47765a5f2 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -8,107 +8,56 @@ schema: 2.0.0 # Install-PSResource ## SYNOPSIS -{{ Fill in the Synopsis }} +Installs resources (modules and scripts) from a registered repository onto the machine. ## SYNTAX -### NameParameterSet (Default) +### NameParameterSet ``` -Install-PSResource [-Name] [-Type ] [-Version ] [-Prerelease] - [-Repository ] [-Credential ] [-Scope ] [-NoClobber] [-TrustRepository] +Install-PSResource [-Name] [-Version ] [-Prerelease] + [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] [] ``` -### InputObjectSet -``` -Install-PSResource [-InputObject] [-WhatIf] [-Confirm] [] -``` - -### RequiredResourceFileParameterSet -``` -Install-PSResource [-Type ] [-Prerelease] [-Repository ] [-Credential ] - [-Scope ] [-NoClobber] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] - [-RequiredResourceFile ] [-WhatIf] [-Confirm] [] -``` - -### RequiredResourceParameterSet -``` -Install-PSResource [-RequiredResource ] [-WhatIf] [-Confirm] [] -``` - ## DESCRIPTION -{{ Fill in the Description }} +The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. +It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. ## EXAMPLES ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Install-PSResource Az ``` -{{ Add example description here }} - -## PARAMETERS - -### -AcceptLicense -{{ Fill AcceptLicense Description }} +Installs the Az module. -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False +### Example 2 +```powershell +PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" ``` -### -Credential -{{ Fill Credential Description }} +Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. -```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: NameParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False +### Example 3 +```powershell +PS C:\> Install-PSResource Az -Repository PSGallery ``` -```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: RequiredResourceFileParameterSet -Aliases: +Installs the latest stable Az module from the PowerShellGallery. -Required: False -Position: Named -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False -``` -### -InputObject -{{ Fill InputObject Description }} +### Example 3 +```powershell +PS C:\> Install-PSResource Az -Reinstall +``` -```yaml -Type: System.Object[] -Parameter Sets: InputObjectSet -Aliases: +Installs the Az module and will write over any previously installed version if it is already installed. -Required: True -Position: 0 -Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` +## PARAMETERS ### -Name -{{ Fill Name Description }} +Name of a resource or resources to install. Does not accept wildcard characters or a null value. ```yaml Type: System.String[] @@ -122,12 +71,14 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` -### -NoClobber -{{ Fill NoClobber Description }} +### -Version +Specifies the version of the resource to be installed. +Can be an exact version or a version range, using the NuGet versioning syntax. +Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Type: System.String +Parameter Sets: NameParameterSet Aliases: Required: False @@ -138,41 +89,11 @@ Accept wildcard characters: False ``` ### -Prerelease -{{ Fill Prerelease Description }} +When specified, includes prerelease versions in search results returned. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Quiet -{{ Fill Quiet Description }} - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Reinstall -{{ Fill Reinstall Description }} - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Parameter Sets: NameParameterSet Aliases: Required: False @@ -183,11 +104,12 @@ Accept wildcard characters: False ``` ### -Repository -{{ Fill Repository Description }} +Specifies one or more repository names to search. +If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. ```yaml Type: System.String[] -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Parameter Sets: NameParameterSet Aliases: Required: False @@ -197,28 +119,29 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -RequiredResource -{{ Fill RequiredResource Description }} +### -Credential +Optional credentials to be used when accessing a repository. ```yaml -Type: System.Object -Parameter Sets: RequiredResourceParameterSet +Type: System.Management.Automation.PSCredential +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` -### -RequiredResourceFile -{{ Fill RequiredResourceFile Description }} +### -Scope +Specifies the scope under which a user has access. ```yaml -Type: System.String -Parameter Sets: RequiredResourceFileParameterSet +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: NameParameterSet Aliases: +Accepted values: CurrentUser, AllUsers Required: False Position: Named @@ -227,14 +150,13 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Scope -{{ Fill Scope Description }} +### -TrustRepository +Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. ```yaml -Type: System.String -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: NameParameterSet Aliases: -Accepted values: CurrentUser, AllUsers Required: False Position: Named @@ -243,12 +165,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -TrustRepository -{{ Fill TrustRepository Description }} +### -Reinstall +Writes over any previously installed resource version that already exists on the machine. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Parameter Sets: NameParameterSet Aliases: Required: False @@ -258,12 +180,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Type -{{ Fill Type Description }} +### -Quiet +Supresses installation progress bar. ```yaml -Type: System.String[] -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: NameParameterSet Aliases: Required: False @@ -273,11 +195,11 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Version -{{ Fill Version Description }} +### -AcceptLicense +Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. ```yaml -Type: System.String +Type: System.Management.Automation.SwitchParameter Parameter Sets: NameParameterSet Aliases: @@ -293,7 +215,7 @@ Prompts you for confirmation before running the cmdlet. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: cf Required: False @@ -309,7 +231,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: wi Required: False @@ -322,21 +244,9 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). -## INPUTS - -### System.String[] - -### System.Object[] - -### System.Management.Automation.PSCredential - ## OUTPUTS - -### System.Object +None ## NOTES -## RELATED LINKS - -[]() - +## RELATED LINKS \ No newline at end of file diff --git a/help/Publish-PSResource.md b/help/Publish-PSResource.md index a73e53ceb..247919a52 100644 --- a/help/Publish-PSResource.md +++ b/help/Publish-PSResource.md @@ -14,22 +14,22 @@ Publishes a specified module from the local computer to PSResource repository. ### PathParameterSet ``` -Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] [-Path] +Publish-PSResource [-APIKey ] [-Repository ] [-Path] [-Credential ] [-SkipDependenciesCheck] [-WhatIf] [-Confirm] [] ``` ### PathLiteralParameterSet ``` -Publish-PSResource [-APIKey ] [-Repository ] [-DestinationPath ] -LiteralPath +Publish-PSResource [-APIKey ] [-Repository ] -LiteralPath [-Credential ] [-SkipDependenciesCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. - -It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. +It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. +You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. ## EXAMPLES @@ -54,7 +54,7 @@ Specifies the API key that you want to use to publish a resource to the online g ```yaml Type: System.String -Parameter Sets: (All) +Parameter Sets: PathParameterSet, PathLiteralParameterSet Aliases: Required: False @@ -64,12 +64,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Credential -Specifies a user account that has rights to a specific repository (used for finding dependencies). +### -Repository +Specifies the repository to publish to. ```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: (All) +Type: System.String +Parameter Sets: PathParameterSet, PathLiteralParameterSet Aliases: Required: False @@ -79,18 +79,18 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -DestinationPath -Specifies the location to be used to publish a nupkg locally. +### -Path +When specified, includes prerelease versions in search. ```yaml Type: System.String -Parameter Sets: (All) +Parameter Sets: PathParameterSet Aliases: -Required: False -Position: Named +Required: True +Position: 0 Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` @@ -109,27 +109,12 @@ Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` -### -Path -When specified, includes prerelease versions in search. - -```yaml -Type: System.String -Parameter Sets: PathParameterSet -Aliases: - -Required: True -Position: 0 -Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` - -### -Repository -Specifies the repository to publish to. +### -Credential +Specifies a user account that has rights to a specific repository (used for finding dependencies). ```yaml -Type: System.String -Parameter Sets: (All) +Type: System.Management.Automation.PSCredential +Parameter Sets: PathParameterSet, PathLiteralParameterSet Aliases: Required: False @@ -140,11 +125,11 @@ Accept wildcard characters: False ``` ### -SkipDependenciesCheck -Bypasses the default check that all dependencies are present. +Bypasses the default check that all dependencies are present on the repository which the resource is being published to. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: PathParameterSet, PathLiteralParameterSet Aliases: Required: False @@ -159,7 +144,7 @@ Prompts you for confirmation before running the cmdlet. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: PathParameterSet, PathLiteralParameterSet Aliases: cf Required: False @@ -175,7 +160,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: PathParameterSet, PathLiteralParameterSet Aliases: wi Required: False @@ -190,8 +175,7 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## OUTPUTS - -### None +None ## NOTES diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index e8d51d16f..ca6ae0889 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -8,7 +8,7 @@ schema: 2.0.0 # Save-PSResource ## SYNOPSIS -{{ Fill in the Synopsis }} +Saves resources (modules and scripts) from a registered repository onto the machine. ## SYNTAX @@ -19,55 +19,75 @@ Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repositor ``` ## DESCRIPTION -{{ Fill in the Description }} +The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. +It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. ## EXAMPLES ### Example 1 ```powershell -PS C:\> {{ Add example code here }} +PS C:\> Save-PSResource -Name Az ``` +Saves the Az module -{{ Add example description here }} +### Example 2 +```powershell +PS C:\> Save-PSResource -Name Az -Repository PSGallery +``` +Saves the Az module found in the PowerShellGallery + +### Example 3 +```powershell +PS C:\> Save-PSResource Az -AsNupkg +``` +Saves the Az module as a .nupkg file + +### Example 4 +```powershell +PS C:\> Save-PSResource Az -IncludeXML +``` +Saves the Az module and includes the PowerShellGet XML metadata ## PARAMETERS -### -AsNupkg -{{ Fill AsNupkg Description }} +### -Name +Name of a resource or resources to save. Does not accept wildcard characters or a null value. ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Type: System.String[] +Parameter Sets: NameParameterSet Aliases: -Required: False -Position: Named +Required: True +Position: 0 Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` -### -Credential -{{ Fill Credential Description }} +### -Version +Specifies the version of the resource to be saved. +Can be an exact version or a version range, using the NuGet versioning syntax. +Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges ```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: (All) +Type: System.String +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` -### -IncludeXML -{{ Fill IncludeXML Description }} +### -Prerelease +Specifies to include prerelease versions. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -77,42 +97,27 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Name -{{ Fill Name Description }} +### -Repository +Specifies one or more repository names to search. +If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. ```yaml Type: System.String[] -Parameter Sets: (All) -Aliases: - -Required: True -Position: 0 -Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` - -### -Path -{{ Fill Path Description }} - -```yaml -Type: System.String -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` -### -Prerelease -{{ Fill Prerelease Description }} - +### -AsNupkg +Saves the resource as a zipped .nupkg file. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -122,12 +127,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Repository -{{ Fill Repository Description }} +### -IncludeXML +Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). ```yaml -Type: System.String[] -Parameter Sets: (All) +Type: System.Management.Automation.SwitchParameter +Parameter Sets: NameParameterSet Aliases: Required: False @@ -137,18 +142,18 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Version -{{ Fill Version Description }} +### -Path +Specifies the path to save the resource to. ```yaml Type: System.String -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` @@ -157,7 +162,7 @@ Prompts you for confirmation before running the cmdlet. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: cf Required: False @@ -173,7 +178,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: wi Required: False @@ -188,19 +193,9 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS -### System.String[] - -### System.Management.Automation.PSCredential - -### System.String - ## OUTPUTS - -### System.Object +None ## NOTES ## RELATED LINKS - -[]() - diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index 13844b909..9dbd89a48 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -17,7 +17,10 @@ Uninstall-PSResource [-Name] [-Version ] [-Force] [-WhatIf] [ ``` ## DESCRIPTION -The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. +The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. +It uninstalls a package found in a module or script installation path based on the -Name parameter argument. +It does not return an object. +Other parameters allow the returned results to be further filtered. ## EXAMPLES @@ -66,7 +69,7 @@ Specifies the version of the resource to be uninstalled. ```yaml Type: System.String -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -81,7 +84,7 @@ Skips check to see if any modules have a dependency on the resource to be uninst ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False @@ -97,7 +100,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: wi Required: False From f4b04e3bc780ca1f02493ca8604972a34e3b1658 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 3 Aug 2021 17:59:43 -0700 Subject: [PATCH 061/276] Update PSGet documentation link in readme (#437) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 997deab3a..39b74a765 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/PowerShell/PowerShellGet/blob/development/LICENSE) -[![Documentation - PowerShellGet](https://img.shields.io/badge/Documentation-PowerShellGet-blue.svg)](https://msdn.microsoft.com/en-us/powershell/gallery/psget) +[![Documentation - PowerShellGet](https://img.shields.io/badge/Documentation-PowerShellGet-blue.svg)](https://docs.microsoft.com/en-us/powershell/module/powershellget/?view=powershell-7.1) [![PowerShell Gallery - PowerShellGet](https://img.shields.io/badge/PowerShell%20Gallery-PowerShellGet-blue.svg)](https://www.powershellgallery.com/packages/PowerShellGet) [![Minimum Supported PowerShell Version](https://img.shields.io/badge/PowerShell-5.0-blue.svg)](https://github.com/PowerShell/PowerShellGet) From 4773b46b794ee28c48df86f9aef715431149a98a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 4 Aug 2021 11:38:33 -0400 Subject: [PATCH 062/276] Replace WriteDebug() with WriteVerbose() (#438) remove WriteDebug() --- src/code/FindHelper.cs | 8 ++-- src/code/GetHelper.cs | 6 +-- src/code/GetInstalledPSResource.cs | 6 +-- src/code/GetPSResourceRepository.cs | 4 +- src/code/InstallHelper.cs | 50 +++++++++++----------- src/code/PublishPSResource.cs | 12 +++--- src/code/RegisterPSResourceRepository.cs | 10 ++--- src/code/SetPSResourceRepository.cs | 6 +-- src/code/UninstallPSResource.cs | 6 +-- src/code/UnregisterPSResourceRepository.cs | 4 +- src/code/Utils.cs | 6 +-- 11 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index a8b942dd3..460054b45 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -110,12 +110,12 @@ public IEnumerable FindByResourceName( PSRepositoryInfo psGalleryScripts = new PSRepositoryInfo(_psGalleryScriptsRepoName, psGalleryScriptsUrl, repositoriesToSearch[i].Priority, false); if (_type == ResourceType.None) { - _cmdletPassedIn.WriteDebug("Null Type provided, so add PSGalleryScripts repository"); + _cmdletPassedIn.WriteVerbose("Null Type provided, so add PSGalleryScripts repository"); repositoriesToSearch.Insert(i + 1, psGalleryScripts); } else if (_type != ResourceType.None && _type == ResourceType.Script) { - _cmdletPassedIn.WriteDebug("Type Script provided, so add PSGalleryScripts and remove PSGallery (Modules only)"); + _cmdletPassedIn.WriteVerbose("Type Script provided, so add PSGalleryScripts and remove PSGallery (Modules only)"); repositoriesToSearch.Insert(i + 1, psGalleryScripts); repositoriesToSearch.RemoveAt(i); // remove PSGallery } @@ -124,7 +124,7 @@ public IEnumerable FindByResourceName( for (int i = 0; i < repositoriesToSearch.Count && _pkgsLeftToFind.Any(); i++) { - _cmdletPassedIn.WriteDebug(string.Format("Searching in repository {0}", repositoriesToSearch[i].Name)); + _cmdletPassedIn.WriteVerbose(string.Format("Searching in repository {0}", repositoriesToSearch[i].Name)); foreach (var pkg in SearchFromRepository( repositoryName: repositoriesToSearch[i].Name, repositoryUrl: repositoriesToSearch[i].Url)) @@ -224,7 +224,7 @@ public IEnumerable SearchAcrossNamesInRepository( { if (String.IsNullOrWhiteSpace(pkgName)) { - _cmdletPassedIn.WriteDebug(String.Format("Package name: {0} provided was null or whitespace, so name was skipped in search.", + _cmdletPassedIn.WriteVerbose(String.Format("Package name: {0} provided was null or whitespace, so name was skipped in search.", pkgName == null ? "null string" : pkgName)); continue; } diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index b451f3227..18cd5ab29 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -86,7 +86,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // if no version is specified, just get the latest version foreach (string pkgPath in dirsToSearch) { - _cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); + _cmdletPassedIn.WriteVerbose(string.Format("Searching through package path: '{0}'", pkgPath)); // if this is a module directory if (Directory.Exists(pkgPath)) @@ -94,7 +94,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // search modules paths // ./Modules/Test-Module/1.0.0 // ./Modules/Test-Module/2.0.0 - _cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); + _cmdletPassedIn.WriteVerbose(string.Format("Searching through package path: '{0}'", pkgPath)); string[] versionsDirs = Utils.GetSubDirectories(pkgPath); @@ -111,7 +111,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li foreach (string versionPath in versionsDirs) { - _cmdletPassedIn.WriteDebug(string.Format("Searching through package version path: '{0}'", versionPath)); + _cmdletPassedIn.WriteVerbose(string.Format("Searching through package version path: '{0}'", versionPath)); DirectoryInfo dirInfo = new DirectoryInfo(versionPath); // if the version is not valid, we'll just skip it and output a debug message diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index 7928c6e4c..34ac306d1 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -71,7 +71,7 @@ protected override void BeginProcessing() _pathsToSearch = new List(); if (Path != null) { - WriteDebug(string.Format("Provided path is: '{0}'", Path)); + WriteVerbose(string.Format("Provided path is: '{0}'", Path)); var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(Path); if (resolvedPaths.Count != 1) @@ -85,7 +85,7 @@ protected override void BeginProcessing() } var resolvedPath = resolvedPaths[0].Path; - WriteDebug(string.Format("Provided resolved path is '{0}'", resolvedPath)); + WriteVerbose(string.Format("Provided resolved path is '{0}'", resolvedPath)); var versionPaths = Utils.GetSubDirectories(resolvedPath); if (versionPaths.Length == 0) @@ -110,7 +110,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - WriteDebug("Entering GetInstalledPSResource"); + WriteVerbose("Entering GetInstalledPSResource"); var namesToSearch = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool _); foreach (string error in errorMsgs) diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs index 05f168d58..9eb57b530 100644 --- a/src/code/GetPSResourceRepository.cs +++ b/src/code/GetPSResourceRepository.cs @@ -41,7 +41,7 @@ protected override void BeginProcessing() { try { - WriteDebug("Calling API to check repository store exists in non-corrupted state"); + WriteVerbose("Calling API to check repository store exists in non-corrupted state"); RepositorySettings.CheckRepositoryStore(); } catch (PSInvalidOperationException e) @@ -56,7 +56,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { string nameArrayAsString = (Name == null || !Name.Any() || string.Equals(Name[0], "*") || Name[0] == null) ? "all" : string.Join(", ", Name); - WriteDebug(String.Format("reading repository: {0}. Calling Read() API now", nameArrayAsString)); + WriteVerbose(String.Format("reading repository: {0}. Calling Read() API now", nameArrayAsString)); List items = RepositorySettings.Read(Name, out string[] errorList); // handle non-terminating errors diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 87d624e9d..e59ab36f6 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -77,7 +77,7 @@ public void InstallPackages( bool includeXML, List pathsToInstallPkg) { - _cmdletPassedIn.WriteDebug(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + + _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", string.Join(",", names), (versionRange != null ? versionRange.OriginalString : string.Empty), @@ -124,13 +124,13 @@ public void ProcessRepositories(string[] packageNames, string[] repository, bool var sourceTrusted = false; string repoName = repo.Name; - _cmdletPassedIn.WriteDebug(string.Format("Attempting to search for packages in '{0}'", repoName)); + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true // OR the user issues trust interactively via console. if (repo.Trusted == false && !trustRepository && !_force) { - _cmdletPassedIn.WriteDebug("Checking if untrusted repository should be used"); + _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); if (!(yesToAll || noToAll)) { @@ -146,7 +146,7 @@ public void ProcessRepositories(string[] packageNames, string[] repository, bool if (sourceTrusted || yesToAll) { - _cmdletPassedIn.WriteDebug("Untrusted repository accepted as trusted source."); + _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); // If it can't find the pkg in one repository, it'll look for it in the next repo in the list var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); @@ -279,7 +279,7 @@ private List InstallPackage(IEnumerable pkgsToInstall, s if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) { - _cmdletPassedIn.WriteDebug(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", p.Name, p.Version.ToString())); + _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", p.Name, p.Version.ToString())); continue; } var pkgIdentity = new PackageIdentity(p.Name, pkgVersion); @@ -350,7 +350,7 @@ private List InstallPackage(IEnumerable pkgsToInstall, s } catch (Exception e) { - _cmdletPassedIn.WriteDebug(string.Format("Error attempting download: '{0}'", e.Message)); + _cmdletPassedIn.WriteVerbose(string.Format("Error attempting download: '{0}'", e.Message)); } finally { @@ -359,7 +359,7 @@ private List InstallPackage(IEnumerable pkgsToInstall, s } } - _cmdletPassedIn.WriteDebug(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); + _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); // Prompt if module requires license acceptance (need to read info license acceptance info from the module manifest) // pkgIdentity.Version.Version gets the version without metadata or release labels. @@ -426,12 +426,12 @@ private List InstallPackage(IEnumerable pkgsToInstall, s } catch (Exception e) { - _cmdletPassedIn.WriteDebug(string.Format("Unable to successfully install package '{0}': '{1}'", p.Name, e.Message)); + _cmdletPassedIn.WriteVerbose(string.Format("Unable to successfully install package '{0}': '{1}'", p.Name, e.Message)); } finally { // Delete the temp directory and all its contents - _cmdletPassedIn.WriteDebug(string.Format("Attempting to delete '{0}'", tempInstallPath)); + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); if (Directory.Exists(tempInstallPath)) { Directory.Delete(tempInstallPath, true); @@ -551,32 +551,32 @@ private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgId // Unforunately have to check if each file exists because it may or may not be there if (File.Exists(nupkgSHAToDelete)) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nupkgSHAToDelete)); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgSHAToDelete)); File.Delete(nupkgSHAToDelete); } if (File.Exists(nuspecToDelete)) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nuspecToDelete)); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nuspecToDelete)); File.Delete(nuspecToDelete); } if (File.Exists(nupkgToDelete)) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", nupkgToDelete)); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgToDelete)); File.Delete(nupkgToDelete); } if (File.Exists(contentTypesToDelete)) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", contentTypesToDelete)); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", contentTypesToDelete)); File.Delete(contentTypesToDelete); } if (Directory.Exists(relsDirToDelete)) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", relsDirToDelete)); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", relsDirToDelete)); Directory.Delete(relsDirToDelete, true); } if (Directory.Exists(packageDirToDelete)) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting '{0}'", packageDirToDelete)); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", packageDirToDelete)); Directory.Delete(packageDirToDelete, true); } } @@ -611,26 +611,26 @@ private void MoveFilesIntoInstallPath( { // Need to delete old xml files because there can only be 1 per script var scriptXML = p.Name + "_InstalledScriptInfo.xml"; - _cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting script metadata XML")); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting script metadata XML")); File.Delete(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); } - _cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); // Need to delete old script file, if that exists - _cmdletPassedIn.WriteDebug(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); if (File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))) { - _cmdletPassedIn.WriteDebug(string.Format("Deleting script file")); + _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); File.Delete(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); } } - _cmdletPassedIn.WriteDebug(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); } else @@ -638,23 +638,23 @@ private void MoveFilesIntoInstallPath( // If new path does not exist if (!Directory.Exists(newPathParent)) { - _cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); Directory.CreateDirectory(newPathParent); Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); } else { - _cmdletPassedIn.WriteDebug(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); // At this point if if (Directory.Exists(finalModuleVersionDir)) { // Delete the directory path before replacing it with the new module - _cmdletPassedIn.WriteDebug(string.Format("Attempting to delete '{0}'", finalModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", finalModuleVersionDir)); Directory.Delete(finalModuleVersionDir, true); } - _cmdletPassedIn.WriteDebug(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); } } diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 0fb371bff..221f731dd 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -176,7 +176,7 @@ protected override void ProcessRecord() // TODO: think about including the repository the resource is being published to if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine.", _path))) { - WriteDebug("ShouldProcess is set to false."); + WriteVerbose("ShouldProcess is set to false."); return; } @@ -287,7 +287,7 @@ protected override void ProcessRecord() if (string.IsNullOrEmpty(nuspec)) { // nuspec creation failed. - WriteDebug("Nuspec creation failed."); + WriteVerbose("Nuspec creation failed."); return; } @@ -371,7 +371,7 @@ protected override void ProcessRecord() PushNupkg(outputNupkgDir, repositoryUrl); } finally { - WriteDebug(string.Format("Deleting temporary directory '{0}'", outputDir)); + WriteVerbose(string.Format("Deleting temporary directory '{0}'", outputDir)); Directory.Delete(outputDir, recursive:true); } } @@ -620,7 +620,7 @@ private string CreateNuspec( metadataElement.AppendChild(element); } else { - WriteDebug(string.Format("Creating XML element failed. Unable to get value from key '{0}'.", key)); + WriteVerbose(string.Format("Creating XML element failed. Unable to get value from key '{0}'.", key)); } } @@ -812,11 +812,11 @@ private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFil bool success = runner.RunPackageBuild(); if (success) { - WriteDebug("Successfully packed the resource into a .nupkg"); + WriteVerbose("Successfully packed the resource into a .nupkg"); } else { - WriteDebug("Successfully packed the resource into a .nupkg"); + WriteVerbose("Successfully packed the resource into a .nupkg"); } return success; diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index d019071c6..4ede96ae3 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -220,7 +220,7 @@ private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl throw new ArgumentException("Invalid url, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); } - WriteDebug("All required values to add to repository provided, calling internal Add() API now"); + WriteVerbose("All required values to add to repository provided, calling internal Add() API now"); if (!ShouldProcess(repoName, "Register repository to repository store")) { return null; @@ -233,7 +233,7 @@ private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, in { if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) { - WriteDebug("Provided Name (NameParameterSet) but with invalid value of PSGallery"); + WriteVerbose("Provided Name (NameParameterSet) but with invalid value of PSGallery"); throw new ArgumentException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"); } @@ -243,7 +243,7 @@ private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, in private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repoTrusted) { Uri psGalleryUri = new Uri(PSGalleryRepoURL); - WriteDebug("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); + WriteVerbose("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted); } @@ -266,7 +266,7 @@ private List RepositoriesParameterSetHelper() try { - WriteDebug("(RepositoriesParameterSet): on repo: PSGallery. Registers PSGallery repository"); + WriteVerbose("(RepositoriesParameterSet): on repo: PSGallery. Registers PSGallery repository"); reposAddedFromHashTable.Add(PSGalleryParameterSetHelper( repo.ContainsKey("Priority") ? (int)repo["Priority"] : defaultPriority, repo.ContainsKey("Trusted") ? (bool)repo["Trusted"] : defaultTrusted)); @@ -336,7 +336,7 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) try { - WriteDebug(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); + WriteVerbose(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); return NameParameterSetHelper(repo["Name"].ToString(), repoURL, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : defaultPriority, diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 5f674f02f..d57588a32 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -97,7 +97,7 @@ protected override void BeginProcessing() { try { - WriteDebug("Calling API to check repository store exists in non-corrupted state"); + WriteVerbose("Calling API to check repository store exists in non-corrupted state"); RepositorySettings.CheckRepositoryStore(); } catch (PSInvalidOperationException e) @@ -200,7 +200,7 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr throw new ArgumentException("Either URL, Priority or Trusted parameters must be requested to be set"); } - WriteDebug("All required values to set repository provided, calling internal Update() API now"); + WriteVerbose("All required values to set repository provided, calling internal Update() API now"); if (!ShouldProcess(repoName, "Set repository's value(s) in repository store")) { return null; @@ -234,7 +234,7 @@ private List RepositoriesParameterSetHelper() private PSRepositoryInfo RepoValidationHelper(Hashtable repo) { - WriteDebug(String.Format("Parsing through repository: {0}", repo["Name"])); + WriteVerbose(String.Format("Parsing through repository: {0}", repo["Name"])); Uri repoURL = null; if (repo.ContainsKey("Url")) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 5081d039b..e38cd7533 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -105,7 +105,7 @@ protected override void ProcessRecord() if (!UninstallPkgHelper()) { // any errors should be caught lower in the stack, this debug statement will let us know if there was an unusual failure - WriteDebug("Did not successfully uninstall all packages"); + WriteVerbose("Did not successfully uninstall all packages"); } break; @@ -140,7 +140,7 @@ protected override void ProcessRecord() break; default: - WriteDebug("Invalid parameter set"); + WriteVerbose("Invalid parameter set"); break; } } @@ -169,7 +169,7 @@ private bool UninstallPkgHelper() if (!ShouldProcess(string.Format("Uninstall resource '{0}' from the machine.", pkgName))) { - this.WriteDebug("ShouldProcess is set to false."); + WriteVerbose("ShouldProcess is set to false."); continue; } diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index 2da1a284a..6257b77f0 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -39,7 +39,7 @@ protected override void BeginProcessing() { try { - WriteDebug("Calling API to check repository store exists in non-corrupted state"); + WriteVerbose("Calling API to check repository store exists in non-corrupted state"); RepositorySettings.CheckRepositoryStore(); } catch (PSInvalidOperationException e) @@ -54,7 +54,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { string nameArrayAsString = string.Join(", ", Name); - WriteDebug(String.Format("removing repository {0}. Calling Remove() API now", nameArrayAsString)); + WriteVerbose(String.Format("removing repository {0}. Calling Remove() API now", nameArrayAsString)); if (!ShouldProcess(nameArrayAsString, "Unregister repositories from repository store")) { return; diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 8b2fa3a29..b4881b3c8 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -300,7 +300,7 @@ public static List GetAllResourcePaths(PSCmdlet psCmdlet) // add all module directories or script files foreach (string path in resourcePaths) { - psCmdlet.WriteDebug(string.Format("Retrieving directories in the path '{0}'", path)); + psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); if (path.EndsWith("Scripts")) { @@ -331,7 +331,7 @@ public static List GetAllResourcePaths(PSCmdlet psCmdlet) // ./PowerShell/Modules/TestModule // need to use .ToList() to cast the IEnumerable to type List pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - pathsToSearch.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); + pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); return pathsToSearch; } @@ -358,7 +358,7 @@ public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType } installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - installationPaths.ForEach(dir => psCmdlet.WriteDebug(string.Format("All paths to search: '{0}'", dir))); + installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); return installationPaths; } From b740a701eff0945a6829e6b0753860eb6c1c4120 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 4 Aug 2021 09:54:50 -0700 Subject: [PATCH 063/276] Update module version to use new form (#439) * Update version to new form * Add missing copyright header --- CHANGELOG.md | 49 ++++++++++++++++++++++++++--------- src/PowerShellGet.psd1 | 12 ++++++--- src/code/PowerShellGet.csproj | 6 ++--- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dfe080bc..2d79c4634 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ -### 3.0.0-beta10 -# Changelog +# CHANGELOG + +## 3.0.11-beta + +### Fixes + +### Changes + +### New Features + +- Find-PSResource +- Get-InstalledPSResource +- Get-PSResourceRepository +- Install-PSResource +- Publish-PSResource +- Register-PSResourceRepository +- Save-PSResource +- Set-PSResourceRepository +- Uninstall-PSResource +- Unregister-PSResourceRepository +- Update-PSResource + +### Notes +In this release, all cmdlets have been reviewed and implementation code refactored as needed. +Cmdlets have most of their functionality, but some parameters are not yet implemented and will be added in future releases. +All tests have been reviewed and rewritten as needed. + +## 3.0.0-beta10 Bug Fixes * Bug fix for -ModuleName (used with -Version) in Find-PSResource returning incorrect resource type * Make repositories unique by name @@ -10,8 +36,7 @@ Bug Fixes * Ensure that not passing credentials does not throw an error if searching through multiple repositories * Remove attempt to remove loaded assemblies in psm1 -### 3.0.0-beta9 -# Changelog +## 3.0.0-beta9 New Features * Add DSCResources @@ -23,7 +48,7 @@ Bug Fixes * Add debugging statements for Get-PSResource and Install-PSResource * Fix bug related to paths in Uninstall-PSResource -### 3.0.0-beta8 +## 3.0.0-beta8 New Features * Add Type parameter to Install-PSResource * Add 'sudo' check for admin privileges in Unix in Install-PSResource @@ -34,7 +59,7 @@ Bug Fixes * Fix bug with Uninstall-PSResource sometimes not fully uninstalling * Change installed file paths to contain original version number instead of normalized version -### 3.0.0-beta7 +## 3.0.0-beta7 New Features * Completed functionality for Update-PSResource * Input-Object parameter for Install-PSResource @@ -48,21 +73,21 @@ Bug Fixes * Fix error getting thrown from paths with incorrectly formatted module versions * Fix module installation paths on Linux and MacOS -### 3.0.0-beta6 +## 3.0.0-beta6 New Feature * Implement functionality for Publish-PSResource -### 3.0.0-beta5 +## 3.0.0-beta5 * Note: 3.0.0-beta5 was skipped due to a packaging error -### 3.0.0-beta4 +## 3.0.0-beta4 New Feature * Implement -Repository '*' in Find-PSResource to search through all repositories instead of prioritized repository Bug Fix * Fix poor error handling for when repository is not accessible in Find-PSResource -### 3.0.0-beta3 +## 3.0.0-beta3 New Features * -RequiredResource parameter for Install-PSResource * -RequiredResourceFile parameter for Install-PSResource @@ -72,7 +97,7 @@ Bug Fixes * Resolved paths in Install-PSRsource and Save-PSResource * Resolved issues with capitalization (for unix systems) in Install-PSResource and Save-PSResource -### 3.0.0-beta2 +## 3.0.0-beta2 New Features * Progress bar and -Quiet parameter for Install-PSResource * -TrustRepository parameter for Install-PSResource @@ -82,6 +107,6 @@ New Features * -Reinstall parameter for Install-PSResource * Improved error handling -### 3.0.0-beta1 +## 3.0.0-beta1 BREAKING CHANGE * Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. \ No newline at end of file diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 1fa277441..3c1084c2c 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -1,6 +1,9 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.0' + ModuleVersion = '3.0.11' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -27,7 +30,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta11' + Prerelease = 'beta' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -37,7 +40,10 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' -### 3.0.0-beta11 + In this release, all cmdlets have been reviewed and implementation code refactored as needed. + Cmdlets have most of their functionality, but some parameters are not yet implemented and will be added in future releases. + All tests have been reviewed and rewritten as needed. +### 3.0.11 '@ } } diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 63c5b0bd8..3e1e9c238 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.0.0 - 3.0.0 - 3.0.0 + 3.0.11.0 + 3.0.11 + 3.0.11 netstandard2.0 8.0 From c82d3148c6cc0914bff9835067b5c70fefcb825d Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 5 Aug 2021 12:28:32 -0700 Subject: [PATCH 064/276] Change 'APIKey' to 'ApiKey' (#443) --- src/code/PublishPSResource.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 221f731dd..dbdc87032 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -34,7 +34,7 @@ public sealed class PublishPSResource : PSCmdlet /// [Parameter()] [ValidateNotNullOrEmpty] - public string APIKey { get; set; } + public string ApiKey { get; set; } /// /// Specifies the repository to publish to. @@ -844,7 +844,7 @@ private void PushNupkg(string outputNupkgDir, string repoUrl) sourceProvider: new PackageSourceProvider(settings), packagePath: fullNupkgFile, source: publishLocation, - apiKey: APIKey, + apiKey: ApiKey, symbolSource: null, symbolApiKey: null, timeoutSeconds: 0, @@ -865,10 +865,10 @@ private void PushNupkg(string outputNupkgDir, string repoUrl) { if (e.Message.Contains("API")) { - var message = String.Format("{0} Please try running again with the -APIKey parameter and specific API key for the repository specified.", e.Message); + var message = String.Format("{0} Please try running again with the -ApiKey parameter and specific API key for the repository specified.", e.Message); ex = new ArgumentException(message); - var APIKeyError = new ErrorRecord(ex, "APIKeyError", ErrorCategory.AuthenticationError, null); - WriteError(APIKeyError); + var ApiKeyError = new ErrorRecord(ex, "ApiKeyError", ErrorCategory.AuthenticationError, null); + WriteError(ApiKeyError); } else { From 651ac00a152e658bc41dcf9866c6b8b1992c8766 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 5 Aug 2021 17:06:11 -0400 Subject: [PATCH 065/276] Update help documentation for minimum inclusive version range (#442) * update help files with note about minimum inclusive version not being supported according to NuGet version documentation --- help/Find-PSResource.md | 12 ++++++++++-- help/Get-InstalledPSResource.md | 13 ++++++++++--- help/Install-PSResource.md | 13 ++++++++++--- help/Save-PSResource.md | 13 ++++++++++--- help/Update-PSResource.md | 12 ++++++++++-- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index 9c0f8b892..cac8dfa5b 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -207,8 +207,16 @@ Accept wildcard characters: False ``` ### -Version -Specifies the version of the resource to be returned. -Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges +Specifies the version of the resource to be returned. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher +(minimum inclusive range). Instead, the values is considered as the required version and yields +version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as +the version range. ```yaml Type: System.String diff --git a/help/Get-InstalledPSResource.md b/help/Get-InstalledPSResource.md index d5b320ab1..0b1d784bd 100644 --- a/help/Get-InstalledPSResource.md +++ b/help/Get-InstalledPSResource.md @@ -89,9 +89,16 @@ Accept wildcard characters: False ``` ### -Version -Specifies the version of the resource to be returned. -Can be an exact version or a version range, using the NuGet versioning syntax. -Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges +Specifies the version of the resource to be returned. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher +(minimum inclusive range). Instead, the values is considered as the required version and yields +version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as +the version range. ```yaml Type: System.String diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 47765a5f2..ddecc1257 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -72,9 +72,16 @@ Accept wildcard characters: False ``` ### -Version -Specifies the version of the resource to be installed. -Can be an exact version or a version range, using the NuGet versioning syntax. -Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges +Specifies the version of the resource to be installed. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher +(minimum inclusive range). Instead, the values is considered as the required version and yields +version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as +the version range. ```yaml Type: System.String diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index ca6ae0889..44d7f90a5 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -66,9 +66,16 @@ Accept wildcard characters: False ``` ### -Version -Specifies the version of the resource to be saved. -Can be an exact version or a version range, using the NuGet versioning syntax. -Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges +Specifies the version of the resource to be saved. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher +(minimum inclusive range). Instead, the values is considered as the required version and yields +version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as +the version range. ```yaml Type: System.String diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 8ee64d319..238abfb6e 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -169,8 +169,16 @@ Accept wildcard characters: False ``` ### -Version -Specifies the version the resource is to be updated to. -Expected version/version range format is documented here: https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges +Specifies the version of the resource to be updated to. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher +(minimum inclusive range). Instead, the values is considered as the required version and yields +version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as +the version range. ```yaml Type: System.String From 299aee3907abe49af081e9c5a071670652501d4a Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 6 Aug 2021 09:48:58 -0700 Subject: [PATCH 066/276] Update NuGet libraries to stable version (#445) --- src/code/PowerShellGet.csproj | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 3e1e9c238..2dfd10cbe 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -15,14 +15,13 @@ - - - - - - - + + + + + + From 03f59c41cab8b335903b331012131b0530e25cd5 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 6 Aug 2021 10:08:58 -0700 Subject: [PATCH 067/276] Fix bug with Publish-PSResource not properly adding tags to nuspec (#448) --- src/code/PublishPSResource.cs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index dbdc87032..3a41ac047 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -275,8 +275,8 @@ protected override void ProcessRecord() { nuspec = CreateNuspec(outputDir, moduleFileInfo, out dependencies, parsedMetadataHash); } - catch { - var message = "Nuspec creation failed."; + catch (Exception e) { + var message = string.Format("Nuspec creation failed: {0}", e.Message); var ex = new ArgumentException(message); var nuspecCreationFailed = new ErrorRecord(ex, "NuspecCreationFailed", ErrorCategory.ObjectNotFound, null); WriteError(nuspecCreationFailed); @@ -451,7 +451,8 @@ private string CreateNuspec( } else { - var data = ast.Find(a => a is HashtableAst, false); + // Must search nested script blocks because 'Tags' are located under 'PrivateData' > 'PSData' + var data = ast.Find(a => a is HashtableAst, true); if (data != null) { parsedMetadataHash = (Hashtable) data.SafeGetValue(); @@ -506,18 +507,26 @@ private string CreateNuspec( return string.Empty; } - // Look for Prerelease tag + // Look for Prerelease tag and then process any Tags in PrivateData > PSData if (parsedMetadataHash.ContainsKey("PrivateData")) { if (parsedMetadataHash["PrivateData"] is Hashtable privateData && privateData.ContainsKey("PSData")) { - if (privateData["PSData"] is Hashtable psData && - psData.ContainsKey("Prerelease")) + if (privateData["PSData"] is Hashtable psData) { - if (psData["Prerelease"] is string preReleaseVersion) + if (psData.ContainsKey("Prerelease") && psData["Prerelease"] is string preReleaseVersion) + { + version = string.Format(@"{0}-{1}", version, preReleaseVersion); + } + if (psData.ContainsKey("Tags") && psData["Tags"] is Array manifestTags) { - version = string.Format(@"{0}-{1}", version, preReleaseVersion); + var tagArr = new List(); + foreach (string tag in manifestTags) + { + tagArr.Add(tag); + } + parsedMetadataHash["tags"] = string.Join(" ", tagArr.ToArray()); } } } From ea460f276501c042f5daf66bbc45d87d7a9b2406 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 6 Aug 2021 14:09:22 -0400 Subject: [PATCH 068/276] add ShouldSupport implementation for Save-PSResource (#447) --- src/code/SavePSResource.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index ff4832ce0..ecc20fe44 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -146,6 +146,12 @@ protected override void BeginProcessing() protected override void ProcessRecord() { + if (!ShouldProcess(string.Format("Resources to save: '{0}'", String.Join(", ", Name)))) + { + WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", String.Join(", ", Name))); + return; + } + var installHelper = new InstallHelper(updatePkg: false, savePkg: true, cmdletPassedIn: this); switch (ParameterSetName) From b96b290f99b662bb26affeba7beb9c53fef692dd Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 6 Aug 2021 14:10:24 -0400 Subject: [PATCH 069/276] make support for Artifactory more generalized (#446) --- src/code/FindHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 460054b45..34d79f289 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -165,7 +165,7 @@ public IEnumerable SearchFromRepository( } // check if ADOFeed- for which searching for Name with wildcard has a different logic flow - if (repositoryUrl.ToString().Contains("pkgs.visualstudio.com")) + if (repositoryUrl.ToString().Contains("pkgs.")) { _isADOFeedRepository = true; } From e6208fd279b37baebad3f62fca9f579c52f046a3 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 9 Aug 2021 11:13:13 -0700 Subject: [PATCH 070/276] Auto-create PSResourceRepository.xml file if the file does not already exist. (#450) --- src/code/FindPSResource.cs | 6 +++++- src/code/GetPSResourceRepository.cs | 14 +------------- src/code/InstallPSResource.cs | 4 ++++ src/code/PublishPSResource.cs | 8 +++++++- src/code/RegisterPSResourceRepository.cs | 15 ++------------- src/code/RepositorySettings.cs | 13 ++++++++++--- src/code/SavePSResource.cs | 4 ++++ src/code/SetPSResourceRepository.cs | 14 +------------- src/code/UnregisterPSResourceRepository.cs | 14 +------------- src/code/UpdatePSResource.cs | 7 ++++++- 10 files changed, 41 insertions(+), 58 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index ba3016de3..1e576ad29 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -134,7 +134,11 @@ public sealed class FindPSResource : PSCmdlet protected override void BeginProcessing() { _source = new CancellationTokenSource(); - _cancellationToken = _source.Token; + _cancellationToken = _source.Token; + + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); } protected override void StopProcessing() diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs index 9eb57b530..310549f69 100644 --- a/src/code/GetPSResourceRepository.cs +++ b/src/code/GetPSResourceRepository.cs @@ -39,19 +39,7 @@ class GetPSResourceRepository : PSCmdlet protected override void BeginProcessing() { - try - { - WriteVerbose("Calling API to check repository store exists in non-corrupted state"); - RepositorySettings.CheckRepositoryStore(); - } - catch (PSInvalidOperationException e) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException(e.Message), - "RepositoryStoreException", - ErrorCategory.ReadError, - this)); - } + RepositorySettings.CheckRepositoryStore(); } protected override void ProcessRecord() { diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index d546e6b4a..78e7ecd62 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -103,6 +103,10 @@ class InstallPSResource : PSCmdlet protected override void BeginProcessing() { + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. // An exact version will be formatted into a version range. if (ParameterSetName.Equals(NameParameterSet) && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 3a41ac047..5684bfc08 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -156,10 +156,16 @@ public PSCredential ProxyCredential { private NuGetVersion _pkgVersion; private string _pkgName; private static char[] _PathSeparators = new [] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; - + #endregion #region Method overrides + protected override void BeginProcessing() + { + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + } protected override void ProcessRecord() { diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 4ede96ae3..be8173488 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -118,19 +118,8 @@ protected override void BeginProcessing() ErrorCategory.NotImplemented, this)); } - - try - { - RepositorySettings.CheckRepositoryStore(); - } - catch (PSInvalidOperationException e) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException(e.Message), - "RepositoryStoreException", - ErrorCategory.ReadError, - this)); - } + + RepositorySettings.CheckRepositoryStore(); } protected override void ProcessRecord() { diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 99911a39e..529e56186 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -19,16 +19,19 @@ namespace Microsoft.PowerShell.PowerShellGet.UtilClasses /// internal static class RepositorySettings - { + { /// /// File name for a user's repository store file is 'PSResourceRepository.xml' /// The repository store file's location is currently only at '%LOCALAPPDATA%\PowerShellGet' for the user account. /// - private static readonly string RepositoryFileName = "PSResourceRepository.xml"; + private const string PSGalleryRepoName = "PSGallery"; + private const string PSGalleryRepoURL = "https://www.powershellgallery.com/api/v2"; + private const int defaultPriority = 50; + private const bool defaultTrusted = false; + private const string RepositoryFileName = "PSResourceRepository.xml"; private static readonly string RepositoryPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet"); private static readonly string FullRepositoryPath = Path.Combine(RepositoryPath, RepositoryFileName); - /// /// Check if repository store xml file exists, if not then create /// @@ -52,6 +55,10 @@ public static void CheckRepositoryStore() { throw new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Repository store creation failed with error: {0}.", e.Message)); } + + // Add PSGallery to the newly created store + Uri psGalleryUri = new Uri(PSGalleryRepoURL); + Add(PSGalleryRepoName, psGalleryUri, defaultPriority, defaultTrusted); } // Open file (which should exist now), if cannot/is corrupted then throw error diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index ecc20fe44..d4af1d151 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -125,6 +125,10 @@ public string Path protected override void BeginProcessing() { + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. // an exact version will be formatted into a version range. if (ParameterSetName.Equals("NameParameterSet") && diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index d57588a32..284a27e7e 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -95,19 +95,7 @@ public SwitchParameter Trusted #region Methods protected override void BeginProcessing() { - try - { - WriteVerbose("Calling API to check repository store exists in non-corrupted state"); - RepositorySettings.CheckRepositoryStore(); - } - catch (PSInvalidOperationException e) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException(e.Message), - "RepositoryStoreException", - ErrorCategory.ReadError, - this)); - } + RepositorySettings.CheckRepositoryStore(); } protected override void ProcessRecord() diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index 6257b77f0..10a15896f 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -37,19 +37,7 @@ class UnregisterPSResourceRepository : PSCmdlet protected override void BeginProcessing() { - try - { - WriteVerbose("Calling API to check repository store exists in non-corrupted state"); - RepositorySettings.CheckRepositoryStore(); - } - catch (PSInvalidOperationException e) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException(e.Message), - "RepositoryStoreException", - ErrorCategory.ReadError, - this)); - } + RepositorySettings.CheckRepositoryStore(); } protected override void ProcessRecord() { diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index de6bacac7..0cf0a8fe5 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -103,7 +103,11 @@ public sealed class UpdatePSResource : PSCmdlet #region Override Methods protected override void BeginProcessing() - { + { + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); } @@ -166,6 +170,7 @@ protected override void ProcessRecord() } #endregion + #region Private Methods /// From 5361a55137ce34bb6f1f4be4ab881b3af26327f6 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Mon, 9 Aug 2021 13:01:33 -0700 Subject: [PATCH 071/276] add issue template (#452) --- .github/ISSUE_TEMPLATE/Bug_Report.yaml | 73 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/Feature_Request.yaml | 20 ++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ 3 files changed, 98 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Bug_Report.yaml create mode 100644 .github/ISSUE_TEMPLATE/Feature_Request.yaml create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.yaml b/.github/ISSUE_TEMPLATE/Bug_Report.yaml new file mode 100644 index 000000000..d7cc58012 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_Report.yaml @@ -0,0 +1,73 @@ +name: Bug report 🐛 +description: Report errors or unexpected behavior 🤔 +labels: Needs-Triage +body: +- type: markdown + attributes: + value: > + For Windows PowerShell 5.1 issues, suggestions, or feature requests please use the + [Feedback Hub app](https://support.microsoft.com/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332) + + For PowerShellGet v2 issues, please use [PowerShellGetv2 repo](https://github.com/PowerShell/PowerShellGetv2). + + This repository is **ONLY** for PowerShellGet v3 issues. +- type: checkboxes + attributes: + label: Prerequisites + options: + - label: Write a descriptive title. + required: true + - label: Make sure you are able to repro it on the [latest released version](https://www.powershellgallery.com/packages/PowerShellGet) + required: true + - label: Search the existing issues. + required: true +- type: textarea + attributes: + label: Steps to reproduce + description: > + List of steps, sample code, failing test or link to a project that reproduces the behavior. + Make sure you place a stack trace inside a code (```) block to avoid linking unrelated issues. + placeholder: > + I am experiencing a problem with X. + I think Y should be happening but Z is actually happening. + validations: + required: true +- type: textarea + attributes: + label: Expected behavior + render: console + placeholder: | + PS> 2 + 2 + 4 + validations: + required: true +- type: textarea + attributes: + label: Actual behavior + render: console + placeholder: | + PS> 2 + 2 + 5 + validations: + required: true +- type: textarea + attributes: + label: Error details + description: Paste verbatim output from `Get-Error` if PowerShell return an error. + render: console + placeholder: PS> Get-Error +- type: textarea + attributes: + label: Environment data + description: Paste verbatim output from `Get-Module PowerShellGet; $PSVersionTable` below. + render: powershell + placeholder: PS> Get-Module PowerShellGet; $PSVersionTable + validations: + required: true +- type: textarea + attributes: + label: Visuals + description: > + Please upload images or animations that can be used to reproduce issues in the area below. + Try the [Steps Recorder](https://support.microsoft.com/en-us/windows/record-steps-to-reproduce-a-problem-46582a9b-620f-2e36-00c9-04e25d784e47) + on Windows or [Screenshot](https://support.apple.com/en-us/HT208721) on macOS. diff --git a/.github/ISSUE_TEMPLATE/Feature_Request.yaml b/.github/ISSUE_TEMPLATE/Feature_Request.yaml new file mode 100644 index 000000000..5079bad45 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_Request.yaml @@ -0,0 +1,20 @@ +name: Feature Request / Idea 🚀 +description: Suggest a new feature or improvement (this does not mean you have to implement it) +labels: [feature_request, Needs-Triage] +body: +- type: textarea + attributes: + label: Summary of the new feature / enhancement + description: > + A clear and concise description of what the problem is that the + new feature would solve. Try formulating it in user story style + (if applicable). + placeholder: "'As a user I want X so that Y...' with X being the being the action and Y being the value of the action." + validations: + required: true +- type: textarea + attributes: + label: Proposed technical implementation details (optional) + placeholder: > + A clear and concise description of what you want to happen. + Consider providing an example PowerShell experience with expected result. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..9fc4f3026 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Documentation Issue + url: https://github.com/MicrosoftDocs/PowerShell-Docs + about: Please open issues on documentation for PowerShellGet here. From 4ed9654fda268c6aef565b391380ae7c924425d8 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 9 Aug 2021 13:30:50 -0700 Subject: [PATCH 072/276] Update changelog (#453) --- CHANGELOG.md | 34 +++++++++++++++++++--------------- src/PowerShellGet.psd1 | 26 +++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d79c4634..f380816ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,29 +2,33 @@ ## 3.0.11-beta -### Fixes - ### Changes +- Graceful handling of paths that do not exist +- The repository store (PSResourceRepository.xml) is auto-generated if it does not already exist. It also automatically registers the PowerShellGallery with a default priority of 50 and a default trusted value of false. +- Better Linux support, including graceful exits when paths do not exist +- Better pipeline input support all cmdlets +- General wildcard support for all cmdlets +- WhatIf support for all cmdlets +- All cmdlets output concrete return types +- Better help documentation for all cmdlets +- Using an exact prerelease version with Find, Install, or Save no longer requires `-Prerelease` tag +- Support for finding, installing, saving, and updating PowerShell resources from Azure Artifact feeds +- Publish-PSResource now properly dispays 'Tags' in nuspec +- Find-PSResource quickly cancels transactions with 'CTRL + C' +- Register-PSRepository now handles relative paths +- Find-PSResource and Save-PSResource deduplicates dependencies +- Install-PSResource no longer creates version folder with the prerelease tag +- Update-PSResource can now update all resources, and no longer requires name param +- Save-PSResource properly handles saving scripts +- Get-InstalledPSResource uses default PowerShell paths -### New Features - -- Find-PSResource -- Get-InstalledPSResource -- Get-PSResourceRepository -- Install-PSResource -- Publish-PSResource -- Register-PSResourceRepository -- Save-PSResource -- Set-PSResourceRepository -- Uninstall-PSResource -- Unregister-PSResourceRepository -- Update-PSResource ### Notes In this release, all cmdlets have been reviewed and implementation code refactored as needed. Cmdlets have most of their functionality, but some parameters are not yet implemented and will be added in future releases. All tests have been reviewed and rewritten as needed. + ## 3.0.0-beta10 Bug Fixes * Bug fix for -ModuleName (used with -Version) in Find-PSResource returning incorrect resource type diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 3c1084c2c..6b4bcc2a6 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -40,10 +40,30 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' - In this release, all cmdlets have been reviewed and implementation code refactored as needed. - Cmdlets have most of their functionality, but some parameters are not yet implemented and will be added in future releases. - All tests have been reviewed and rewritten as needed. + ### 3.0.11 +In this release, all cmdlets have been reviewed and implementation code refactored as needed. +Cmdlets have most of their functionality, but some parameters are not yet implemented and will be added in future releases. +All tests have been reviewed and rewritten as needed. + +- Graceful handling of paths that do not exist +- The repository store (PSResourceRepository.xml) is auto-generated if it does not already exist. It also automatically registers the PowerShellGallery with a default priority of 50 and a default trusted value of false. +- Better Linux support, including graceful exits when paths do not exist +- Better pipeline input support all cmdlets +- General wildcard support for all cmdlets +- WhatIf support for all cmdlets +- All cmdlets output concrete return types +- Better help documentation for all cmdlets +- Using an exact prerelease version with Find, Install, or Save no longer requires `-Prerelease` tag +- Support for finding, installing, saving, and updating PowerShell resources from Azure Artifact feeds +- Publish-PSResource now properly dispays 'Tags' in nuspec +- Find-PSResource quickly cancels transactions with 'CTRL + C' +- Register-PSRepository now handles relative paths +- Find-PSResource and Save-PSResource deduplicates dependencies +- Install-PSResource no longer creates version folder with the prerelease tag +- Update-PSResource can now update all resources, and no longer requires name param +- Save-PSResource properly handles saving scripts +- Get-InstalledPSResource uses default PowerShell paths '@ } } From 47b7ad987b33dcf71af39b6861087253e2974d47 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 9 Aug 2021 16:31:39 -0400 Subject: [PATCH 073/276] Support Azure Artifacts for PowerShell modules (#449) PowerShell modules should be supported for Azure Artifacts feeds --- src/code/InstallHelper.cs | 48 ++++++++++++++++++++++++++++++++++++--- src/code/Utils.cs | 15 ++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index e59ab36f6..926f13c8f 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -385,8 +385,22 @@ private List InstallPackage(IEnumerable pkgsToInstall, s if (!isScript) { var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); + if (!File.Exists(moduleManifest)) + { + var message = String.Format("Module manifest file: {0} does not exist. This is not a valid PowerShell module.", moduleManifest); + + var ex = new ArgumentException(message); + var psdataFileDoesNotExistError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); + _cmdletPassedIn.WriteError(psdataFileDoesNotExistError); + continue; + } + + if (!Utils.TryParseModuleManifest(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) + { + // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. + continue; + } - var parsedMetadataHashtable = Utils.ParseModuleManifest(moduleManifest, this); moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; // Accept License verification @@ -432,9 +446,17 @@ private List InstallPackage(IEnumerable pkgsToInstall, s { // Delete the temp directory and all its contents _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); + if (Directory.Exists(tempInstallPath)) { - Directory.Delete(tempInstallPath, true); + if (!TryDeleteDirectory(tempInstallPath, out ErrorRecord errorMsg)) + { + _cmdletPassedIn.WriteError(errorMsg); + } + else + { + _cmdletPassedIn.WriteVerbose(String.Format("Successfully deleted '{0}'", tempInstallPath)); + } } } } @@ -581,6 +603,26 @@ private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgId } } + private bool TryDeleteDirectory( + string tempInstallPath, + out ErrorRecord errorMsg) + { + errorMsg = null; + + try + { + Utils.DeleteDirectory(tempInstallPath); + } + catch (Exception e) + { + var TempDirCouldNotBeDeletedError = new ErrorRecord(e, "errorDeletingTempInstallPath", ErrorCategory.InvalidResult, null); + errorMsg = TempDirCouldNotBeDeletedError; + return false; + } + + return true; + } + private void MoveFilesIntoInstallPath( PSResourceInfo p, bool isScript, @@ -660,4 +702,4 @@ private void MoveFilesIntoInstallPath( } } } -} \ No newline at end of file +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index b4881b3c8..891482d0e 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -387,9 +387,14 @@ private static void GetStandardPlatformPaths( #region Manifest methods - public static Hashtable ParseModuleManifest(string moduleFileInfo, PSCmdlet cmdletPassedIn) + public static bool TryParseModuleManifest( + string moduleFileInfo, + PSCmdlet cmdletPassedIn, + out Hashtable parsedMetadataHashtable) { - Hashtable parsedMetadataHash = new Hashtable(); + parsedMetadataHashtable = new Hashtable(); + bool successfullyParsed = false; + // A script will already have the metadata parsed into the parsedMetadatahash, // a module will still need the module manifest to be parsed. if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) @@ -405,13 +410,15 @@ public static Hashtable ParseModuleManifest(string moduleFileInfo, PSCmdlet cmdl var ex = new ArgumentException(message); var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); cmdletPassedIn.WriteError(psdataParseError); + return successfullyParsed; } else { var data = ast.Find(a => a is HashtableAst, false); if (data != null) { - parsedMetadataHash = (Hashtable)data.SafeGetValue(); + parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); + successfullyParsed = true; } else { @@ -423,7 +430,7 @@ public static Hashtable ParseModuleManifest(string moduleFileInfo, PSCmdlet cmdl } } - return parsedMetadataHash; + return successfullyParsed; } #endregion From c921b0ccff3c1cf7058c4031397311a862092bf3 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 10 Aug 2021 09:54:48 -0700 Subject: [PATCH 074/276] Add clarifying comments to util functions (#454) --- src/code/Utils.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 891482d0e..aaca16bbc 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -459,6 +459,9 @@ public static void WriteVerboseOnCmdlet( /// /// Deletes a directory and its contents + /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell + /// on OneDrive with 'access denied' error. + /// Later versions of .NET, with PowerShellCore, do not have this bug. /// public static void DeleteDirectory(string dirPath) { @@ -477,7 +480,7 @@ public static void DeleteDirectory(string dirPath) /// /// Moves files from source to destination locations. - /// Works over different file volumes. + /// This is a workaround for .NET File.Move(), which fails over different file volumes. /// public static void MoveFiles( string sourceFilePath, @@ -490,7 +493,7 @@ public static void MoveFiles( /// /// Moves the directory, including contents, from source to destination locations. - /// Works over different file volumes. + /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. /// public static void MoveDirectory( string sourceDirPath, From cbccb23f2d3b91d10e460c887e011aee1dfdbde1 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 10 Aug 2021 13:37:25 -0400 Subject: [PATCH 075/276] fix minor typo in release yml (#455) --- .ci/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/release.yml b/.ci/release.yml index bc808d402..6c8527990 100644 --- a/.ci/release.yml +++ b/.ci/release.yml @@ -28,7 +28,7 @@ jobs: displayName: 'Capture PowerShellGet module NuGet package path and set environment variable' - task: NuGetCommand@2 - displayName: 'Push Microsoft.PowerShell.Store module artifacts to PSGallery feed' + displayName: 'Push PowerShellGet module artifacts to PSGallery feed' inputs: command: push packagesToPush: '$(NugetPkgPath)' From 58df9c5bc108b1cbec3dbb530f74d88b823b58d1 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 28 Sep 2021 18:37:27 -0400 Subject: [PATCH 076/276] Command dsc parametersets (#490) Implement CommandName and DSCResourceName parameter sets --- help/Find-PSResource.md | 45 +++++++++++++- src/PSGet.Format.ps1xml | 34 ++++++++++ src/code/FindPSResource.cs | 113 +++++++++++++++++++++++++++++----- src/code/PSResourceInfo.cs | 60 ++++++++++++++++-- test/FindPSResource.Tests.ps1 | 33 ++++++++++ 5 files changed, 260 insertions(+), 25 deletions(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index cac8dfa5b..82fbce245 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -19,13 +19,13 @@ Searches for packages from a repository (local or remote), based on `-Name` and ### CommandNameParameterSet ``` PowerShell -[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] +[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` ### DscResourceNameParameterSet ``` PowerShell -[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] +[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` @@ -77,6 +77,47 @@ PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version " This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". +### Example 4 +```powershell +PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery + Get-TargetResource 1.0.0.4 WindowsDefender PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery + Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery + Get-TargetResource 1.2.0.0 cRegFile PSGallery + Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery + Get-TargetResource 1.0.0.0 cVNIC PSGallery + Get-TargetResource 1.1.17.0 supVsts PSGallery + +``` + +This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + +### Example 5 +```powershell +PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery +``` + +This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + +### Example 6 +```powershell +PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + +``` + +This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. + ## PARAMETERS ### -Credential diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml index 80decb5de..695dc2813 100644 --- a/src/PSGet.Format.ps1xml +++ b/src/PSGet.Format.ps1xml @@ -25,5 +25,39 @@ + + PSIncludedResourceInfoTable + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSIncludedResourceInfo + + + + + + + + + + + + + + + + + + + + + Name + $_.ParentResource.Version + $_.ParentResource.PrereleaseLabel + $_.ParentResource.Name + $_.ParentResource.Repository + + + + + diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 1e576ad29..f317c4280 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -21,7 +21,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets "PSResource", DefaultParameterSetName = ResourceNameParameterSet, SupportsShouldProcess = true)] - [OutputType(typeof(PSResourceInfo))] + [OutputType(typeof(PSResourceInfo), typeof(PSCommandResourceInfo))] public sealed class FindPSResource : PSCmdlet { #region Members @@ -76,7 +76,7 @@ public sealed class FindPSResource : PSCmdlet [Parameter(ParameterSetName = CommandNameParameterSet)] [Parameter(ParameterSetName = DscResourceNameParameterSet)] [ValidateNotNullOrEmpty] - public string ModuleName { get; set; } + public string[] ModuleName { get; set; } /// /// Specifies a list of command names that searched module packages will provide. Wildcards are supported. @@ -134,11 +134,11 @@ public sealed class FindPSResource : PSCmdlet protected override void BeginProcessing() { _source = new CancellationTokenSource(); - _cancellationToken = _source.Token; - - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly - RepositorySettings.CheckRepositoryStore(); + _cancellationToken = _source.Token; + + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); } protected override void StopProcessing() @@ -155,19 +155,11 @@ protected override void ProcessRecord() break; case CommandNameParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("CommandNameParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "CommandParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); + ProcessCommandOrDscParameterSet(isSearchingForCommands: true); break; case DscResourceNameParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("DscResourceNameParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "DscResourceParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); + ProcessCommandOrDscParameterSet(isSearchingForCommands: false); break; default: @@ -256,6 +248,93 @@ private void ProcessResourceNameParameterSet() } } + private void ProcessCommandOrDscParameterSet(bool isSearchingForCommands) + { + var commandOrDSCNamesToSearch = Utils.ProcessNameWildcards( + pkgNames: isSearchingForCommands ? CommandName : DscResourceName, + errorMsgs: out string[] errorMsgs, + isContainWildcard: out bool nameContainsWildcard); + + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Wilcards are not supported for -CommandName or -DSCResourceName for Find-PSResource. So all CommandName or DSCResourceName entries will be discarded."), + "CommandDSCResourceNameWithWildcardsNotSupported", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringCommandDscResourceNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 commandOrDSCNamesToSearch + if (commandOrDSCNamesToSearch.Length == 0) + { + return; + } + + var moduleNamesToSearch = Utils.ProcessNameWildcards( + pkgNames: ModuleName, + errorMsgs: out string[] moduleErrorMsgs, + isContainWildcard: out bool _); + + foreach (string error in moduleErrorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringModuleNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + if (moduleNamesToSearch.Length == 0) + { + moduleNamesToSearch = new string[] {"*"}; + } + + FindHelper findHelper = new FindHelper(_cancellationToken, this); + List foundPackages = new List(); + + foreach (PSResourceInfo package in findHelper.FindByResourceName( + name: moduleNamesToSearch, + // provide type so Scripts endpoint for PSGallery won't be searched + type: isSearchingForCommands? ResourceType.Command : ResourceType.DscResource, + version: Version, + prerelease: Prerelease, + tag: Tag, + repository: Repository, + credential: Credential, + includeDependencies: IncludeDependencies)) + { + foundPackages.Add(package); + } + + // if a single package contains multiple commands we are interested in, return a unique entry for each: + // Command1 , PackageA + // Command2 , PackageA + foreach (string nameToSearch in commandOrDSCNamesToSearch) + { + foreach (var package in foundPackages) + { + // this check ensures DSC names provided as a Command name won't get returned mistakenly + // -CommandName "command1", "dsc1" <- (will not return or add DSC name) + if ((isSearchingForCommands && package.Includes.Command.Contains(nameToSearch)) || + (!isSearchingForCommands && package.Includes.DscResource.Contains(nameToSearch))) + { + WriteObject(new PSCommandResourceInfo(nameToSearch, package)); + } + } + } + } + #endregion } } diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index a70922618..5d681825c 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -199,6 +199,37 @@ public Dependency(string dependencyName, VersionRange dependencyVersionRange) #endregion + #region PSCommandResourceInfo + public sealed class PSCommandResourceInfo + { + // this object will represent a Command or DSCResource + // included by the PSResourceInfo property + + #region Properties + public string Name { get; } + + public PSResourceInfo ParentResource { get; } + #endregion + + #region Constructor + + /// + /// Constructor + /// + /// + /// Name of the command or DSC resource + /// the parent module resource the command or dsc resource belongs to + public PSCommandResourceInfo(string name, PSResourceInfo parentResource) + { + Name = name; + ParentResource = parentResource; + } + + #endregion + } + + #endregion + #region PSResourceInfo public sealed class PSResourceInfo @@ -485,7 +516,14 @@ public static bool TryConvert( } try - { + { + var typeInfo = ParseMetadataType(metadataToParse, repositoryName, type, out ArrayList commandNames, out ArrayList dscResourceNames); + var resourceHashtable = new Hashtable(); + resourceHashtable.Add(nameof(PSResourceInfo.Includes.Command), new PSObject(commandNames)); + resourceHashtable.Add(nameof(PSResourceInfo.Includes.DscResource), new PSObject(dscResourceNames)); + var includes = new ResourceIncludes(resourceHashtable); + + psGetInfo = new PSResourceInfo( additionalMetadata: null, author: ParseMetadataAuthor(metadataToParse), @@ -494,7 +532,7 @@ public static bool TryConvert( dependencies: ParseMetadataDependencies(metadataToParse), description: ParseMetadataDescription(metadataToParse), iconUri: ParseMetadataIconUri(metadataToParse), - includes: null, + includes: includes, installedDate: null, installedLocation: null, isPrelease: ParseMetadataIsPrerelease(metadataToParse), @@ -509,7 +547,8 @@ public static bool TryConvert( repository: repositoryName, repositorySourceLocation: null, tags: ParseMetadataTags(metadataToParse), - type: ParseMetadataType(metadataToParse, repositoryName, type), + // type: ParseMetadataType(metadataToParse, repositoryName, type), + type: typeInfo, updatedDate: null, version: ParseMetadataVersion(metadataToParse)); @@ -803,7 +842,11 @@ private static string[] ParseMetadataTags(IPackageSearchMetadata pkg) return pkg.Tags.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); } - private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, string repoName, ResourceType? pkgType) + private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, + string repoName, + ResourceType? pkgType, + out ArrayList commandNames, + out ArrayList dscResourceNames) { // possible type combinations: // M, C @@ -811,6 +854,8 @@ private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, string // M // S + commandNames = new ArrayList(); + dscResourceNames = new ArrayList(); string[] tags = ParseMetadataTags(pkg); ResourceType currentPkgType = ResourceType.Module; @@ -838,15 +883,18 @@ private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, string currentPkgType &= ~ResourceType.Module; currentPkgType |= ResourceType.Script; } - if (tag.StartsWith("PSCommand_")) + if (tag.StartsWith("PSCommand_", StringComparison.InvariantCultureIgnoreCase)) { currentPkgType |= ResourceType.Command; + commandNames.Add(tag.Split('_')[1]); } - if (String.Equals(tag, "PSIncludes_DscResource", StringComparison.InvariantCultureIgnoreCase)) + if (tag.StartsWith("PSDscResource_", StringComparison.InvariantCultureIgnoreCase)) { currentPkgType |= ResourceType.DscResource; + dscResourceNames.Add(tag.Split('_')[1]); } } + return currentPkgType; } diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 71805f03c..57ab7a23b 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -9,6 +9,9 @@ Describe 'Test Find-PSResource for Module' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName + $commandName = "Get-TargetResource" + $dscResourceName = "SystemLocale" + $parentModuleName = "SystemLocaleDsc" Get-NewPSResourceRepositoryFile Register-LocalRepos } @@ -239,4 +242,34 @@ Describe 'Test Find-PSResource for Module' { $resNonDefault = Find-PSResource -Name $moduleName -Repository $repoLowerPriorityRanking $resNonDefault.Repository | Should -Be $repoLowerPriorityRanking } + + It "find resource given CommandName (CommandNameParameterSet)" { + $res = Find-PSResource -CommandName $commandName -Repository $PSGalleryName + foreach ($item in $res) { + $item.Name | Should -Be $commandName + $item.ParentResource.Includes.Command | Should -Contain $commandName + } + } + + It "find resource given CommandName and ModuleName (CommandNameParameterSet)" { + $res = Find-PSResource -CommandName $commandName -ModuleName $parentModuleName -Repository $PSGalleryName + $res.Name | Should -Be $commandName + $res.ParentResource.Name | Should -Be $parentModuleName + $res.ParentResource.Includes.Command | Should -Contain $commandName + } + + It "find resource given DSCResourceName (DSCResourceNameParameterSet)" { + $res = Find-PSResource -DscResourceName $dscResourceName -Repository $PSGalleryName + foreach ($item in $res) { + $item.Name | Should -Be $dscResourceName + $item.ParentResource.Includes.DscResource | Should -Contain $dscResourceName + } + } + + It "find resource given DscResourceName and ModuleName (DSCResourceNameParameterSet)" { + $res = Find-PSResource -DscResourceName $dscResourceName -ModuleName $parentModuleName -Repository $PSGalleryName + $res.Name | Should -Be $dscResourceName + $res.ParentResource.Name | Should -Be $parentModuleName + $res.ParentResource.Includes.DscResource | Should -Contain $dscResourceName + } } From 820351b79ed6e3ecf458d27cccf9c2c678198b8d Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 28 Sep 2021 20:21:32 -0400 Subject: [PATCH 077/276] Tag type paramset (#478) implement Tag and Type parameter set for Find --- help/Find-PSResource.md | 4 +- src/PSGet.Format.ps1xml | 2 + src/code/FindHelper.cs | 93 ++++++++++++++++++++++++------ src/code/FindPSResource.cs | 38 ++++--------- test/FindPSResource.Tests.ps1 | 104 ++++++++++++++++++++++++++++++++-- 5 files changed, 188 insertions(+), 53 deletions(-) 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 @@ Name Version PrereleaseLabel + Repository Description 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 From baadd0ced0c2e7a74bc60f8da231585a14c2a5a4 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 5 Oct 2021 10:29:39 -0700 Subject: [PATCH 078/276] Remove unnecessary .nupkg.metadata from module after installation (#500) --- src/code/InstallHelper.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 926f13c8f..15998e30e 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -362,20 +362,16 @@ private List InstallPackage(IEnumerable pkgsToInstall, s _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); // Prompt if module requires license acceptance (need to read info license acceptance info from the module manifest) - // pkgIdentity.Version.Version gets the version without metadata or release labels. - - + // pkgIdentity.Version.Version gets the version without metadata or release labels. string newVersion = pkgIdentity.Version.ToNormalizedString(); - // string normalizedVersionNoPrereleaseLabel = newVersion; if (pkgIdentity.Version.IsPrerelease) { - // 2.0.2 + // eg: 2.0.2 normalizedVersionNoPrereleaseLabel = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); } - //p.Version = new System.Version(normalizedVersionNoPrereleaseLabel); - + string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); string moduleManifestVersion = string.Empty; @@ -463,7 +459,7 @@ private List InstallPackage(IEnumerable pkgsToInstall, s return pkgsSuccessfullyInstalled; } - + private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string tempInstallPath, string newVersion) { var requireLicenseAcceptance = false; @@ -563,9 +559,10 @@ private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgId { // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module var pkgIdString = pkgIdentity.ToString(); - var nupkgSHAToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.sha512").ToLower()); - var nuspecToDelete = Path.Combine(dirNameVersion, (pkgIdentity.Id + ".nuspec").ToLower()); - var nupkgToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg").ToLower()); + var nupkgSHAToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.sha512")); + var nuspecToDelete = Path.Combine(dirNameVersion, (pkgIdentity.Id + ".nuspec")); + var nupkgToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg")); + var nupkgMetadataToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.metadata")); var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); var packageDirToDelete = Path.Combine(dirNameVersion, "package"); @@ -586,6 +583,11 @@ private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgId _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgToDelete)); File.Delete(nupkgToDelete); } + if (File.Exists(nupkgMetadataToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgMetadataToDelete)); + File.Delete(nupkgMetadataToDelete); + } if (File.Exists(contentTypesToDelete)) { _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", contentTypesToDelete)); From 272efb3fce5af4c24f8c7e691cff112ff7a444c0 Mon Sep 17 00:00:00 2001 From: Keith Jackson <8988864+keithallenjackson@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:48:01 -0500 Subject: [PATCH 079/276] Fix failing tests on Windows when not an admin (#502) --- test/InstallPSResource.Tests.ps1 | 2 +- test/PSGetTestUtils.psm1 | 9 +++++++++ test/UpdatePSResource.Tests.ps1 | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index ef206fece..4a61f1549 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -143,7 +143,7 @@ Describe 'Test Install-PSResource for Module' { } # Windows only - It "Install resource under AllUsers scope - Windows only" -Skip:(!(Get-IsWindows)) { + It "Install resource under AllUsers scope - Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index 4cae5c5ec..6b83bd5d4 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -100,6 +100,15 @@ $script:moduleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:CurrentPSGetFormatVersion = "1.0" $script:PSGetFormatVersionPrefix = "PowerShellGetFormatVersion_" +function Test-IsAdmin { + [OutputType([bool])] + param() + + [System.Security.Principal.WindowsPrincipal]::new( + [Security.Principal.WindowsIdentity]::GetCurrent() + ).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) +} + function Get-IsWindows { return $script:IsWindows } diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 12c84574c..834823bbe 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -177,7 +177,7 @@ Describe 'Test Update-PSResource' { } # Windows only - It "update resource under AllUsers scope" -skip:(!$IsWindows) { + It "update resource under AllUsers scope" -skip:(!($IsWindows -and (Test-IsAdmin))) { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser From dd0e7fe8482235ac7ab5a84180b1c5093af5327b Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 5 Oct 2021 13:41:18 -0700 Subject: [PATCH 080/276] Update README.md (#503) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 39b74a765..8fde2ba70 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Important Note ============== This version of PowerShellGet is currently under development and is not feature complete. -As a result, we are currently not accepting PRs to this repository. +As a result, we are currently only accepting PRs for tests. +If you would like to open a PR please open an issue first so that necessary discussion can take place. Please open an issue for any feature requests, bug reports, or questions for PowerShellGet version 3.0 (currently available as a preview release). Please note, the repository for previous versions of PowerShellGet has a new location at [PowerShell/PowerShellGetv2](https://github.com/PowerShell/PowerShellGetv2). From ae5865fe6d8a436f4e2ea722495e137977e88064 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 8 Oct 2021 12:37:26 -0700 Subject: [PATCH 081/276] Add Sbom to release package (#507) --- .ci/ci_release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 457544d32..c6ec3dfaa 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -240,6 +240,12 @@ stages: displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + - ${{ if ne(variables.SkipSigning, 'True') }}: + - template: Sbom.yml@ComplianceRepo + parameters: + BuildDropPath: $(signOutPath) + Build_Repository_Uri: 'https://github.com/powershell/powershellget' + - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' $env:PSModulePath = $modulePath + [System.IO.Path]::PathSeparator + $env:PSModulePath From dc15254dba2965f4ca494226cb6f7cfcda2004e3 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 8 Oct 2021 13:04:49 -0700 Subject: [PATCH 082/276] Fix bug with some modules installing as scripts (#504) --- src/code/InstallHelper.cs | 82 ++++++++++++++++---------------- test/InstallPSResource.Tests.ps1 | 8 ++++ 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 15998e30e..ed5d89a47 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -376,9 +376,12 @@ private List InstallPackage(IEnumerable pkgsToInstall, s var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); string moduleManifestVersion = string.Empty; var scriptPath = Path.Combine(tempDirNameVersion, (p.Name + ".ps1")); - var isScript = File.Exists(scriptPath) ? true : false; + var modulePath = Path.Combine(tempDirNameVersion, (p.Name + ".psd1")); + // Check if the package is a module or a script + var isModule = File.Exists(modulePath); - if (!isScript) + + if (isModule) { var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); if (!File.Exists(moduleManifest)) @@ -420,16 +423,16 @@ private List InstallPackage(IEnumerable pkgsToInstall, s /// ./Modules /// ./Scripts /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list - installPath = isScript ? _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)) - : _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)); + installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) + : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); } if (_includeXML) { - CreateMetadataXMLFile(tempDirNameVersion, installPath, repoName, p, isScript); + CreateMetadataXMLFile(tempDirNameVersion, installPath, repoName, p, isModule); } - MoveFilesIntoInstallPath(p, isScript, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); + MoveFilesIntoInstallPath(p, isModule, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", p.Name, installPath)); pkgsSuccessfullyInstalled.Add(p.Name); @@ -535,12 +538,12 @@ private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string t return success; } - private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isScript) + private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isModule) { // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" // Modules will have the metadata file: "PSGetModuleInfo.xml" - var metadataXMLPath = isScript ? Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")) - : Path.Combine(dirNameVersion, "PSGetModuleInfo.xml"); + var metadataXMLPath = isModule ? Path.Combine(dirNameVersion, "PSGetModuleInfo.xml") + : Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")); pkg.InstalledDate = DateTime.Now; pkg.InstalledLocation = installPath; @@ -627,7 +630,7 @@ private bool TryDeleteDirectory( private void MoveFilesIntoInstallPath( PSResourceInfo p, - bool isScript, + bool isModule, bool isLocalRepo, string dirNameVersion, string tempInstallPath, @@ -639,18 +642,42 @@ private void MoveFilesIntoInstallPath( string scriptPath) { // Creating the proper installation path depending on whether pkg is a module or script - var newPathParent = isScript ? installPath : Path.Combine(installPath, p.Name); - var finalModuleVersionDir = isScript ? installPath : Path.Combine(installPath, p.Name, moduleManifestVersion); // versionWithoutPrereleaseTag + var newPathParent = isModule ? Path.Combine(installPath, p.Name) : installPath; + var finalModuleVersionDir = isModule ? Path.Combine(installPath, p.Name, moduleManifestVersion) : installPath; // versionWithoutPrereleaseTag // If script, just move the files over, if module, move the version directory over - var tempModuleVersionDir = (isScript || isLocalRepo) ? dirNameVersion + var tempModuleVersionDir = (!isModule || isLocalRepo) ? dirNameVersion : Path.Combine(tempInstallPath, p.Name.ToLower(), newVersion); _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); - _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); - if (isScript) + if (isModule) { + // If new path does not exist + if (!Directory.Exists(newPathParent)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Directory.CreateDirectory(newPathParent); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); + } + else + { + _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); + + // At this point if + if (Directory.Exists(finalModuleVersionDir)) + { + // Delete the directory path before replacing it with the new module + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", finalModuleVersionDir)); + Directory.Delete(finalModuleVersionDir, true); + } + + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); + } + } + else { if (!_savePkg) { // Need to delete old xml files because there can only be 1 per script @@ -677,31 +704,6 @@ private void MoveFilesIntoInstallPath( _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); } - else - { - // If new path does not exist - if (!Directory.Exists(newPathParent)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Directory.CreateDirectory(newPathParent); - Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); - } - else - { - _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); - - // At this point if - if (Directory.Exists(finalModuleVersionDir)) - { - // Delete the directory path before replacing it with the new module - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", finalModuleVersionDir)); - Directory.Delete(finalModuleVersionDir, true); - } - - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); - } - } } } } diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 4a61f1549..9dcfa1f30 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -243,6 +243,14 @@ Describe 'Test Install-PSResource for Module' { $res = Get-Module "TestModule" -ListAvailable $res | Should -BeNullOrEmpty } + + It "Validates that a module with module-name script files (like Pester) installs under Modules path" { + + Install-PSResource -Name "testModuleWithScript" -Repository $TestGalleryName + + $res = Get-Module "testModuleWithScript" -ListAvailable + $res.Path.Contains("Modules") | Should -Be $true + } } <# Temporarily commented until -Tag is implemented for this Describe block From 0c9d93bc27bf871168c88e58c1f9dac747fc79d7 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 18 Oct 2021 14:00:26 -0400 Subject: [PATCH 083/276] Value from pipeline cleanup (#511) Cmdlets should only have ValueFromPipeline and/or ValueFromPipelineByPropertyName attributes per the cases discussed --- src/code/FindPSResource.cs | 1 - src/code/GetInstalledPSResource.cs | 2 +- src/code/GetPSResourceRepository.cs | 5 ++--- src/code/PublishPSResource.cs | 10 +++++----- src/code/RegisterPSResourceRepository.cs | 6 ++---- src/code/SetPSResourceRepository.cs | 9 +++------ src/code/UnregisterPSResourceRepository.cs | 7 ++----- 7 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 464fddc3d..6dea7f3e3 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -41,7 +41,6 @@ public sealed class FindPSResource : PSCmdlet /// [Parameter(Position = 0, ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true, ParameterSetName = ResourceNameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index 34ac306d1..dfcd7202b 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -30,7 +30,7 @@ public sealed class GetInstalledPSResource : PSCmdlet /// /// Specifies the desired name for the resource to look for. /// - [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [Parameter(Position = 0, ValueFromPipeline = true)] public string[] Name { get; set; } /// diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs index 310549f69..82fdeed5d 100644 --- a/src/code/GetPSResourceRepository.cs +++ b/src/code/GetPSResourceRepository.cs @@ -17,8 +17,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// [Cmdlet(VerbsCommon.Get, - "PSResourceRepository", - HelpUri = "")] + "PSResourceRepository")] public sealed class GetPSResourceRepository : PSCmdlet { @@ -28,7 +27,7 @@ class GetPSResourceRepository : PSCmdlet /// Specifies the name(s) of a registered repository to find. /// Supports wild card characters. /// - [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [Parameter(Position = 0, ValueFromPipeline = true)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] public string[] Name { get; set; } = Utils.EmptyStrArray; diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 5684bfc08..5d7c13176 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -48,7 +48,7 @@ public sealed class PublishPSResource : PSCmdlet /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "PathParameterSet")] + [Parameter(Mandatory = true, Position = 0, ParameterSetName = "PathParameterSet")] [ValidateNotNullOrEmpty] public string Path { @@ -80,7 +80,7 @@ public string Path /// No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. /// Single quotation marks tell PowerShell not to interpret any characters as escape sequences. /// - [Parameter(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "PathLiteralParameterSet")] + [Parameter(Mandatory = true, ParameterSetName = "PathLiteralParameterSet")] [ValidateNotNullOrEmpty] public string LiteralPath { @@ -118,7 +118,7 @@ public string LiteralPath /// /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. /// - [Parameter(ValueFromPipelineByPropertyName = true)] + [Parameter()] [ValidateNotNullOrEmpty] public Uri Proxy { set @@ -135,7 +135,7 @@ public Uri Proxy { /// /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. /// - [Parameter(ValueFromPipelineByPropertyName = true)] + [Parameter()] [ValidateNotNullOrEmpty] public PSCredential ProxyCredential { set @@ -163,7 +163,7 @@ public PSCredential ProxyCredential { protected override void BeginProcessing() { // Create a respository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); } diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index be8173488..678c6fb95 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -5,7 +5,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Globalization; using System.Management.Automation; using Dbg = System.Diagnostics.Debug; @@ -20,8 +19,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets [Cmdlet(VerbsLifecycle.Register, "PSResourceRepository", DefaultParameterSetName = NameParameterSet, - SupportsShouldProcess = true, - HelpUri = "")] + SupportsShouldProcess = true)] public sealed class RegisterPSResourceRepository : PSCmdlet { @@ -63,7 +61,7 @@ class RegisterPSResourceRepository : PSCmdlet /// /// Specifies a hashtable of repositories and is used to register multiple repositories at once. /// - [Parameter(Mandatory = true, ParameterSetName = "RepositoriesParameterSet", ValueFromPipeline = true)] + [Parameter(Mandatory = true, ParameterSetName = RepositoriesParameterSet)] [ValidateNotNullOrEmpty] public Hashtable[] Repositories {get; set;} diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 284a27e7e..d74507f6b 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -5,7 +5,6 @@ using System.Collections; using System.Collections.Generic; using Dbg = System.Diagnostics.Debug; -using System.Globalization; using System.Management.Automation; using Microsoft.PowerShell.PowerShellGet.UtilClasses; @@ -17,8 +16,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets [Cmdlet(VerbsCommon.Set, "PSResourceRepository", DefaultParameterSetName = NameParameterSet, - SupportsShouldProcess = true, - HelpUri = "")] + SupportsShouldProcess = true)] public sealed class SetPSResourceRepository : PSCmdlet { @@ -35,8 +33,7 @@ class SetPSResourceRepository : PSCmdlet /// /// Specifies the name of the repository to be set. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] public string Name { get; set; } @@ -51,7 +48,7 @@ class SetPSResourceRepository : PSCmdlet /// /// Specifies a hashtable of repositories and is used to register multiple repositories at once. /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = RepositoriesParameterSet)] + [Parameter(Mandatory = true, ParameterSetName = RepositoriesParameterSet)] [ValidateNotNullOrEmpty] public Hashtable[] Repositories { get; set; } diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index 10a15896f..2d984fc12 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -14,8 +14,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets [Cmdlet(VerbsLifecycle.Unregister, "PSResourceRepository", - SupportsShouldProcess = true, - HelpUri = "")] + SupportsShouldProcess = true)] public sealed class UnregisterPSResourceRepository : PSCmdlet { @@ -24,9 +23,7 @@ class UnregisterPSResourceRepository : PSCmdlet /// /// Specifies the desired name for the repository to be registered. /// - [Parameter(Mandatory= true, Position = 0, - ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true)] + [Parameter(Mandatory= true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] public string[] Name { get; set; } = Utils.EmptyStrArray; From aa116d7d3d73f1cb9b786daae93ef38b2e88fb7f Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 18 Oct 2021 16:05:45 -0400 Subject: [PATCH 084/276] Add InputObject parameter sets for appropriate *-PSResource cmdlets, to provide pipeline support (#510) Add InputObjects for {Install, Save, Uninstall}-PSResource cmdlets. --- src/code/InstallPSResource.cs | 169 +++++++++++++++++------------ src/code/SavePSResource.cs | 164 ++++++++++++++++------------ src/code/UninstallPSResource.cs | 84 +++++++------- test/InstallPSResource.Tests.ps1 | 8 ++ test/SavePSResource.Tests.ps1 | 15 +++ test/UninstallPSResource.Tests.ps1 | 18 +++ 6 files changed, 277 insertions(+), 181 deletions(-) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 78e7ecd62..42be06c52 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -1,4 +1,3 @@ -using System.Collections.Specialized; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; @@ -26,14 +25,14 @@ class InstallPSResource : PSCmdlet /// Specifies the exact names of resources to install from a repository. /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } /// /// Specifies the version or version range of the package to be installed /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] public string Version { get; set; } @@ -54,44 +53,58 @@ class InstallPSResource : PSCmdlet /// /// Specifies a user account that has rights to find a resource from a specific repository. /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public PSCredential Credential { get; set; } /// /// Specifies the scope of installation. /// [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public ScopeType Scope { get; set; } /// /// Suppresses being prompted for untrusted sources. /// [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter TrustRepository { get; set; } /// /// Overwrites a previously installed resource with the same name and version. /// [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter Reinstall { get; set; } /// /// Suppresses progress information. /// [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter Quiet { get; set; } /// /// For modules that require a license, AcceptLicense automatically accepts the license agreement during installation. /// [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter AcceptLicense { get; set; } + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public PSResourceInfo InputObject { get; set; } + #endregion #region Members private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectParameterSet = "InputObjectParameterSet"; private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet"; private const string RequiredResourceParameterSet = "RequiredResourceParameterSet"; List _pathsToInstallPkg; @@ -107,87 +120,51 @@ protected override void BeginProcessing() // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. - // An exact version will be formatted into a version range. - if (ParameterSetName.Equals(NameParameterSet) && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) - - { - var exMessage = "Argument for -Version parameter is not in the proper format."; - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - // if no Version specified, install latest version for the package - if (Version == null) - { - _versionRange = VersionRange.All; - } - _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); } protected override void ProcessRecord() { - if (!ShouldProcess(string.Format("package to install: '{0}'", String.Join(", ", Name)))) - { - WriteVerbose(string.Format("Install operation cancelled by user for packages: {0}", String.Join(", ", Name))); - return; - } - var installHelper = new InstallHelper(updatePkg: false, savePkg: false, cmdletPassedIn: this); - switch (ParameterSetName) { case NameParameterSet: - var namesToInstall = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard); - if (nameContainsWildcard) + // If no Version specified, install latest version for the package. + // Otherwise validate Version can be parsed out successfully. + if (Version == null) { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Name with wildcards is not supported for Install-PSResource cmdlet"), - "NameContainsWildcard", - ErrorCategory.InvalidArgument, - this)); - return; + _versionRange = VersionRange.All; } - - foreach (string error in errorMsgs) + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); } - // 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 namesToInstall - if (namesToInstall.Length == 0) + ProcessInstallHelper(installHelper: installHelper, + pkgNames: Name, + pkgPrerelease: Prerelease, + pkgRepository: Repository); + break; + + case InputObjectParameterSet: + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) { - return; + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); + var ex = new ArgumentException(exMessage); + var ErrorParsingVersion = new ErrorRecord(ex, "ErrorParsingVersion", ErrorCategory.ParserError, null); + WriteError(ErrorParsingVersion); } - installHelper.InstallPackages( - names: namesToInstall, - versionRange: _versionRange, - prerelease: Prerelease, - repository: Repository, - acceptLicense: AcceptLicense, - quiet: Quiet, - reinstall: Reinstall, - force: false, - trustRepository: TrustRepository, - noClobber: false, - credential: Credential, - requiredResourceFile: null, - requiredResourceJson: null, - requiredResourceHash: null, - specifiedPath: null, - asNupkg: false, - includeXML: true, - pathsToInstallPkg: _pathsToInstallPkg); + ProcessInstallHelper(installHelper: installHelper, + pkgNames: new string[] { InputObject.Name }, + pkgPrerelease: InputObject.IsPrerelease, + pkgRepository: new string[]{ InputObject.Repository }); break; - + case RequiredResourceFileParameterSet: ThrowTerminatingError(new ErrorRecord( new PSNotImplementedException("RequiredResourceFileParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), @@ -211,5 +188,63 @@ protected override void ProcessRecord() } #endregion + + #region Methods + private void ProcessInstallHelper(InstallHelper installHelper, string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) + { + var inputNameToInstall = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Install-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToInstall + if (inputNameToInstall.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("package to install: '{0}'", String.Join(", ", inputNameToInstall)))) + { + WriteVerbose(string.Format("Install operation cancelled by user for packages: {0}", String.Join(", ", inputNameToInstall))); + return; + } + + installHelper.InstallPackages( + names: pkgNames, + versionRange: _versionRange, + prerelease: pkgPrerelease, + repository: pkgRepository, + acceptLicense: AcceptLicense, + quiet: Quiet, + reinstall: Reinstall, + force: false, + trustRepository: TrustRepository, + noClobber: false, + credential: Credential, + requiredResourceFile: null, + requiredResourceJson: null, + requiredResourceHash: null, + specifiedPath: null, + asNupkg: false, + includeXML: true, + pathsToInstallPkg: _pathsToInstallPkg); + } + #endregion } } diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index d4af1d151..be5180150 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -22,7 +22,7 @@ public sealed class SavePSResource : PSCmdlet #region Members private const string NameParameterSet = "NameParameterSet"; - private const string InputObjectSet = "InputObjectSet"; + private const string InputObjectParameterSet = "InputObjectParameterSet"; VersionRange _versionRange; #endregion @@ -33,7 +33,7 @@ public sealed class SavePSResource : PSCmdlet /// Specifies the exact names of resources to save from a repository. /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } @@ -54,15 +54,15 @@ public sealed class SavePSResource : PSCmdlet /// Specifies the specific repositories to search within. /// [Parameter(ParameterSetName = NameParameterSet)] - // todo: add tab completion (look at get-psresourcerepository at the name parameter) - [ValidateNotNullOrEmpty] [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] public string[] Repository { get; set; } /// /// Specifies a user account that has rights to save a resource from a specific repository. /// - [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public PSCredential Credential { get; set; } /* @@ -82,7 +82,8 @@ public sealed class SavePSResource : PSCmdlet /// /// The destination where the resource is to be installed. Works for all resource types. /// - [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] [ValidateNotNullOrEmpty] public string Path { @@ -109,15 +110,16 @@ public string Path /// /// Suppresses being prompted for untrusted sources. /// - [Parameter()] + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter TrustRepository { get; set; } /// /// Used for pipeline input. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = InputObjectSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] [ValidateNotNullOrEmpty] - public object[] InputObject { set; get; } + public PSResourceInfo InputObject { get; set; } #endregion @@ -129,18 +131,6 @@ protected override void BeginProcessing() // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. - // an exact version will be formatted into a version range. - if (ParameterSetName.Equals("NameParameterSet") && - Version != null && - !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) - { - var exMessage = "Argument for -Version parameter is not in the proper format."; - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - // If the user does not specify a path to save to, use the user's current working directory if (string.IsNullOrWhiteSpace(_path)) { @@ -150,63 +140,45 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - if (!ShouldProcess(string.Format("Resources to save: '{0}'", String.Join(", ", Name)))) - { - WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", String.Join(", ", Name))); - return; - } - var installHelper = new InstallHelper(updatePkg: false, savePkg: true, cmdletPassedIn: this); - switch (ParameterSetName) { case NameParameterSet: - var namesToSave = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool nameContainsWildcard); - if (nameContainsWildcard) + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (Version == null) { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), - "NameContainsWildcard", - ErrorCategory.InvalidArgument, - this)); - return; + _versionRange = VersionRange.All; } - - foreach (string error in errorMsgs) + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); } - // 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 namesToSave - if (namesToSave.Length == 0) + ProcessSaveHelper(installHelper: installHelper, + pkgNames: Name, + pkgPrerelease: Prerelease, + pkgRepository: Repository); + break; + + case InputObjectParameterSet: + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) { - return; + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); } - - installHelper.InstallPackages( - names: namesToSave, - versionRange: _versionRange, - prerelease: Prerelease, - repository: Repository, - acceptLicense: true, - quiet: true, - reinstall: true, - force: false, - trustRepository: TrustRepository, - noClobber: false, - credential: Credential, - requiredResourceFile: null, - requiredResourceJson: null, - requiredResourceHash: null, - specifiedPath: _path, - asNupkg: false, - includeXML: false, - pathsToInstallPkg: new List { _path } ); + + ProcessSaveHelper(installHelper: installHelper, + pkgNames: new string[] { InputObject.Name }, + pkgPrerelease: InputObject.IsPrerelease, + pkgRepository: new string[] { InputObject.Repository }); + break; default: @@ -216,5 +188,63 @@ protected override void ProcessRecord() } #endregion + + #region Methods + private void ProcessSaveHelper(InstallHelper installHelper, string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) + { + var namesToSave = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToSave + if (namesToSave.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("Resources to save: '{0}'", namesToSave))) + { + WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", namesToSave)); + return; + } + + installHelper.InstallPackages( + names: namesToSave, + versionRange: _versionRange, + prerelease: pkgPrerelease, + repository: pkgRepository, + acceptLicense: true, + quiet: true, + reinstall: true, + force: false, + trustRepository: TrustRepository, + noClobber: false, + credential: Credential, + requiredResourceFile: null, + requiredResourceJson: null, + requiredResourceHash: null, + specifiedPath: _path, + asNupkg: false, + includeXML: false, + pathsToInstallPkg: new List { _path } ); + } + #endregion } } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index e38cd7533..36d16a1a0 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -25,7 +25,7 @@ public sealed class UninstallPSResource : PSCmdlet /// Specifies the exact names of resources to uninstall. /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } @@ -39,19 +39,20 @@ public sealed class UninstallPSResource : PSCmdlet /// /// Used for pipeline input. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = InputObjectSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] [ValidateNotNullOrEmpty] - public PSResourceInfo[] InputObject { get; set; } + public PSResourceInfo InputObject { get; set; } /// /// [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter Force { get; set; } #endregion #region Members private const string NameParameterSet = "NameParameterSet"; - private const string InputObjectSet = "InputObjectSet"; + private const string InputObjectParameterSet = "InputObjectParameterSet"; public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); @@ -60,22 +61,6 @@ public sealed class UninstallPSResource : PSCmdlet #region Methods protected override void BeginProcessing() { - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. - // an exact version will be formatted into a version range. - if (ParameterSetName.Equals("NameParameterSet") && Version != null && !Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) - { - var exMessage = "Argument for -Version parameter is not in the proper format."; - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - // if no Version specified, uninstall all versions for the package - if (Version == null) - { - _versionRange = VersionRange.All; - } - _pathsToSearch = Utils.GetAllResourcePaths(this); } @@ -84,6 +69,21 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: + // if no Version specified, uninstall all versions for the package. + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (Version == null) + { + _versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + Name = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool _); foreach (string error in errorMsgs) @@ -109,34 +109,25 @@ protected override void ProcessRecord() } break; - case InputObjectSet: - // the for loop will use type PSObject in order to pull the properties from the pkg object - foreach (PSResourceInfo pkg in InputObject) + case InputObjectParameterSet: + if (!Utils.TryParseVersionOrVersionRange(InputObject.Version.ToString(), out _versionRange)) { - if (pkg == null) - { - continue; - } - - // attempt to parse version - if (!Utils.TryParseVersionOrVersionRange(pkg.Version.ToString(), out VersionRange _versionRange)) - { - var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", pkg.Version.ToString(), pkg.Name); - var ex = new ArgumentException(exMessage); - var ErrorParsingVersion = new ErrorRecord(ex, "ErrorParsingVersion", ErrorCategory.ParserError, null); - WriteError(ErrorParsingVersion); - } - - Name = new string[] { pkg.Name }; - if (!String.IsNullOrWhiteSpace(pkg.Name) && !UninstallPkgHelper()) - { - // specific errors will be displayed lower in the stack - var exMessage = String.Format(string.Format("Did not successfully uninstall package {0}", pkg.Name)); - var ex = new ArgumentException(exMessage); - var UninstallResourceError = new ErrorRecord(ex, "UninstallResourceError", ErrorCategory.InvalidOperation, null); - WriteError(UninstallResourceError); - } + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); + var ex = new ArgumentException(exMessage); + var ErrorParsingVersion = new ErrorRecord(ex, "ErrorParsingVersion", ErrorCategory.ParserError, null); + WriteError(ErrorParsingVersion); } + + Name = new string[] { InputObject.Name }; + if (!String.IsNullOrWhiteSpace(InputObject.Name) && !UninstallPkgHelper()) + { + // specific errors will be displayed lower in the stack + var exMessage = String.Format(string.Format("Did not successfully uninstall package {0}", InputObject.Name)); + var ex = new ArgumentException(exMessage); + var UninstallResourceError = new ErrorRecord(ex, "UninstallResourceError", ErrorCategory.InvalidOperation, null); + WriteError(UninstallResourceError); + } + break; default: @@ -162,7 +153,6 @@ private bool UninstallPkgHelper() // note that the xml file is located in ./Scripts/InstalledScriptInfos, eg: ./Scripts/InstalledScriptInfos/TestScript_InstalledScriptInfo.xml string pkgName = string.Empty; - foreach (string pkgPath in getHelper.FilterPkgPathsByVersion(_versionRange, dirsToDelete)) { pkgName = Utils.GetInstalledPackageName(pkgPath); diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 9dcfa1f30..fd8be4ba2 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -9,6 +9,7 @@ Describe 'Test Install-PSResource for Module' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName + $testModuleName = "TestModule" Get-NewPSResourceRepositoryFile Register-LocalRepos } @@ -251,6 +252,13 @@ Describe 'Test Install-PSResource for Module' { $res = Get-Module "testModuleWithScript" -ListAvailable $res.Path.Contains("Modules") | Should -Be $true } + + It "Install PSResourceInfo object piped in" { + Find-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName | Install-PSResource + $res = Get-InstalledPSResource -Name $testModuleName + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "1.1.0.0" + } } <# Temporarily commented until -Tag is implemented for this Describe block diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 7f107b21f..910597f7e 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -9,6 +9,7 @@ Describe 'Test Save-PSResource for PSResources' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName + $testModuleName = "test_module" Get-NewPSResourceRepositoryFile Register-LocalRepos @@ -173,6 +174,20 @@ Describe 'Test Save-PSResource for PSResources' { (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } + It "Save PSResourceInfo object piped in" { + Find-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save PSResourceInfo object piped in for prerelease version object" { + Find-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 + } + <# # Tests should not write to module directory It "Save specific module resource by name if no -Path param is specifed" { diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index f20e967ae..8f5f6a9f9 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -8,6 +8,7 @@ Describe 'Test Uninstall-PSResource for Modules' { BeforeAll{ $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName + $testModuleName = "test_module" Get-NewPSResourceRepositoryFile $res = Uninstall-PSResource -name ContosoServer -Version "*" } @@ -162,4 +163,21 @@ Describe 'Test Uninstall-PSResource for Modules' { $pkg = Get-Module "RequiredModule1" -ListAvailable $pkg | Should -Be $null } + + It "Uninstall PSResourceInfo object piped in" { + Install-PSResource -Name "ContosoServer" -Version "1.5.0.0" -Repository $TestGalleryName + Get-InstalledPSResource -Name "ContosoServer" -Version "1.5.0.0" | Uninstall-PSResource + $res = Get-InstalledPSResource -Name "ContosoServer" -Version "1.5.0.0" + $res | Should -BeNullOrEmpty + } + + It "Uninstall PSResourceInfo object piped in for prerelease version object" { + Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName + # Powershell cannot create install locations indicating a prerelease version (with prerelease label indicated in install location). + # To test we can uninstall prerelease versions, we must use the numeric part of the prerelease version only and it must be unique + # of all versions installed for that module. + Get-InstalledPSResource -Name $testModuleName -Version "4.5.2" | Uninstall-PSResource + $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2" + $res | Should -BeNullOrEmpty + } } From 2161ac8b5cda83cbd7c58f58de801ce88f304ba5 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 2 Nov 2021 09:55:48 -0700 Subject: [PATCH 085/276] Fix CI to use latest ubuntu image (#527) --- .ci/ci.yml | 2 +- .ci/ci_auto.yml | 6 +++--- .ci/ci_release.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.ci/ci.yml b/.ci/ci.yml index b4126ca56..7728cf1fa 100644 --- a/.ci/ci.yml +++ b/.ci/ci.yml @@ -125,7 +125,7 @@ stages: - template: test.yml parameters: - jobName: TestPkgUbuntu16 + jobName: TestPkgUbuntu displayName: PowerShell Core on Ubuntu imageName: ubuntu-latest diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 2facb5286..6b1c3bf81 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -322,9 +322,9 @@ stages: - template: test.yml parameters: - jobName: TestPkgUbuntu16 - displayName: PowerShell Core on Ubuntu 16.04 - imageName: ubuntu-16.04 + jobName: TestPkgUbuntu + displayName: PowerShell Core on Ubuntu + imageName: ubuntu-latest - template: test.yml parameters: diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index c6ec3dfaa..6fe9586d1 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -326,9 +326,9 @@ stages: - template: test.yml parameters: - jobName: TestPkgUbuntu16 - displayName: PowerShell Core on Ubuntu 16.04 - imageName: ubuntu-16.04 + jobName: TestPkgUbuntu + displayName: PowerShell Core on Ubuntu + imageName: ubuntu-latest - template: test.yml parameters: From 9afc059b66d5da988be091b76104040bc3df8186 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 2 Nov 2021 10:01:59 -0700 Subject: [PATCH 086/276] Fix test image (#528) --- .ci/ci_auto.yml | 2 +- .ci/ci_release.yml | 2 +- .ci/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 6b1c3bf81..ae0720d8c 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -330,4 +330,4 @@ stages: parameters: jobName: TestPkgWinMacOS displayName: PowerShell Core on macOS - imageName: macOS-10.14 + imageName: macOS-latest diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 6fe9586d1..640365732 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -334,7 +334,7 @@ stages: parameters: jobName: TestPkgWinMacOS displayName: PowerShell Core on macOS - imageName: macOS-10.14 + imageName: macOS-latest - stage: Release displayName: Publish Package to PSGallery diff --git a/.ci/test.yml b/.ci/test.yml index 1879fc37a..aa141662c 100644 --- a/.ci/test.yml +++ b/.ci/test.yml @@ -1,6 +1,6 @@ parameters: jobName: TestPkgWin - imageName: windows-2019 + imageName: windows-latest displayName: PowerShell Core on Windows powershellExecutable: pwsh From 7026ceb543065d85fbea04d61ead37cca1dcf88c Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 2 Nov 2021 15:29:01 -0700 Subject: [PATCH 087/276] Add CI notice generator (#529) --- .ci/ci_release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 640365732..d9133e0cd 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -306,6 +306,13 @@ stages: codeBaseName: 'PowerShellGet_210306' # selections APIScan: false # set to false when not using Windows APIs + # Generate the third party notice file after component detection + - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 + displayName: 'Third Party Notice File Generator' + inputs: + outputfile: ThirdPartyNotice + # output format can be html or text + outputformat: text - stage: Test displayName: Test Package From 72670dbf49162bf0697cf379690bc0d4e7237f1f Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 3 Nov 2021 15:52:51 -0400 Subject: [PATCH 088/276] change Find-PSResource tests to not test against production package Carbon (#530) change Find tests to not test against production package Carbon --- test/FindPSResource.Tests.ps1 | 73 ++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 4e82e383b..f539a67d6 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -9,7 +9,7 @@ Describe 'Test Find-PSResource for Module' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName - $testModuleName = "testmodule" + $testModuleName = "test_module" $testScriptName = "test_script" $commandName = "Get-TargetResource" $dscResourceName = "SystemLocale" @@ -23,8 +23,8 @@ Describe 'Test Find-PSResource for Module' { } It "find Specific Module Resource by Name" { - $specItem = Find-PSResource -Name "Carbon" - $specItem.Name | Should -Be "Carbon" + $specItem = Find-PSResource -Name $testModuleName + $specItem.Name | Should -Be $testModuleName } It "should not find resource given nonexistant name" { @@ -124,56 +124,56 @@ Describe 'Test Find-PSResource for Module' { $res.Count | Should -BeGreaterThan 1 } - $testCases2 = @{Version="[2.10.0.0]"; ExpectedVersions=@("2.10.0.0"); Reason="validate version, exact match"}, - @{Version="2.10.0.0"; ExpectedVersions=@("2.10.0.0"); Reason="validate version, exact match without bracket syntax"}, - @{Version="[2.5.0.0, 2.8.0.0]"; ExpectedVersions=@("2.5.0.0", "2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0", "2.8.0.0"); Reason="validate version, exact range inclusive"}, - @{Version="(2.5.0.0, 2.8.0.0)"; ExpectedVersions=@("2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0"); Reason="validate version, exact range exclusive"}, - @{Version="(2.9.4.0,)"; ExpectedVersions=@("2.10.0.0", "2.10.1.0", "2.10.2.0"); Reason="validate version, minimum version exclusive"}, - @{Version="[2.9.4.0,)"; ExpectedVersions=@("2.9.4.0", "2.10.0.0", "2.10.1.0", "2.10.2.0"); Reason="validate version, minimum version inclusive"}, - @{Version="(,2.0.0.0)"; ExpectedVersions=@("1.9.0.0"); Reason="validate version, maximum version exclusive"}, - @{Version="(,2.0.0.0]"; ExpectedVersions=@("1.9.0.0", "2.0.0.0"); Reason="validate version, maximum version inclusive"}, - @{Version="[2.5.0.0, 2.8.0.0)"; ExpectedVersions=@("2.5.0.0", "2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0", "2.8.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - @{Version="(2.5.0.0, 2.8.0.0]"; ExpectedVersions=@("2.5.1.0", "2.5.2.0", "2.5.3.0", "2.5.4.0", "2.6.0.0", "2.7.0.0", "2.8.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} + $testCases2 = @{Version="[5.0.0.0]"; ExpectedVersions=@("5.0.0.0"); Reason="validate version, exact match"}, + @{Version="5.0.0.0"; ExpectedVersions=@("5.0.0.0"); Reason="validate version, exact match without bracket syntax"}, + @{Version="[2.5.0.0, 5.0.0.0]"; ExpectedVersions=@("2.5.0.0", "3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(2.5.0.0, 5.0.0.0)"; ExpectedVersions=@("3.0.0.0", "4.0.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(2.5.0.0,)"; ExpectedVersions=@("3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[2.5.0.0,)"; ExpectedVersions=@("2.5.0.0", "3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,2.5.0.0)"; ExpectedVersions=@("1.2.0.0", "1.5.0.0", "2.0.0.0"); Reason="validate version, maximum version exclusive"}, + @{Version="(,2.0.0.0]"; ExpectedVersions=@("1.2.0.0", "1.5.0.0", "2.0.0.0", "2.5.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[2.5.0.0, 5.0.0.0)"; ExpectedVersions=@("2.5.0.0", "3.0.0.0", "4.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + @{Version="(2.5.0.0, 5.0.0.0]"; ExpectedVersions=@("3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} It "find resource when given Name to " -TestCases $testCases2{ param($Version, $ExpectedVersions) - $res = Find-PSResource -Name "Carbon" -Version $Version -Repository $PSGalleryName + $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName foreach ($item in $res) { - $item.Name | Should -Be "Carbon" + $item.Name | Should -Be $testModuleName $ExpectedVersions | Should -Contain $item.Version } } It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(2.10.0.0)'; Description="exclusive version (2.10.0.0)"}, - @{Version='[2-10-0-0]'; Description="version formatted with invalid delimiter"} + @{Version='(2.5.0.0)'; Description="exclusive version (2.5.0.0)"}, + @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"} ) { param($Version, $Description) - $res = Find-PSResource -Name "Carbon" -Version $Version -Repository $PSGalleryName + $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName $res | Should -BeNullOrEmpty } $testCases = @{Version='[2.*.0.0]'; Description="version with wilcard in middle"}, - @{Version='[*.10.0.0]'; Description="version with wilcard at start"}, - @{Version='[2.10.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*'; Description="version with wildcard at end"}, - @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[2.5.*.0]'; Description="version with wildcard at third digit"} + @{Version='[2.5.0.*'; Description="version with wildcard at end"}, + @{Version='[2..0.0]'; Description="version with missing digit in middle"}, + @{Version='[2.5.0.]'; Description="version with missing digit at end"}, + @{Version='[2.5.0.0.0]'; Description="version with more than 4 digits"} It "not find resource and throw exception with incorrectly formatted version such as " -TestCases $testCases { param($Version, $Description) - Find-PSResource -Name "Carbon" -Version $Version -Repository $PSGalleryName -ErrorVariable err -ErrorAction SilentlyContinue + Find-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "IncorrectVersionFormat,Microsoft.PowerShell.PowerShellGet.Cmdlets.FindPSResource" } It "find resources when given Name, Version not null --> '*'" { - $res = Find-PSResource -Name "Carbon" -Version "*" -Repository $PSGalleryName + $res = Find-PSResource -Name $testModuleName -Version "*" -Repository $TestGalleryName $res | ForEach-Object { - $_.Name | Should -Be "Carbon" + $_.Name | Should -Be $testModuleName } $res.Count | Should -BeGreaterOrEqual 1 } @@ -203,9 +203,9 @@ Describe 'Test Find-PSResource for Module' { } It "find resource when given Name, Version param null" { - $res = Find-PSResource -Name "Carbon" -Repository $PSGalleryName - $res.Name | Should -Be "Carbon" - $res.Version | Should -Be "2.10.2.0" + $res = Find-PSResource -Name $testModuleName -Repository $TestGalleryName + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "5.0.0.0" } It "find resource with latest (including prerelease) version given Prerelease parameter" { @@ -215,21 +215,22 @@ Describe 'Test Find-PSResource for Module' { $resPrerelease = Find-PSResource -Name "test_module" -Prerelease -Repository $TestGalleryName $resPrerelease.Version | Should -Be "5.2.5.0" + $resPrerelease.PrereleaseLabel | Should -Be "alpha001" } It "find resources, including Prerelease version resources, when given Prerelease parameter" { - $resWithoutPrerelease = Find-PSResource -Name "Carbon" -Version "*" -Repository $PSGalleryName - $resWithPrerelease = Find-PSResource -Name "Carbon" -Version "*" -Repository $PSGalleryName + $resWithoutPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $TestGalleryName + $resWithPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $TestGalleryName $resWithPrerelease.Count | Should -BeGreaterOrEqual $resWithoutPrerelease.Count } - It "find resource of Type script or module from PSGallery, when no Type parameter provided" { + It "find resource of Type script or module from PSGallery/PoshTestGallery, when no Type parameter provided" { $resScript = Find-PSResource -Name "AzureSqlScale" -Repository $PSGalleryName $resScript.Name | Should -Be "AzureSqlScale" $resScript.Type | Should -Be "Script" - $resModule = Find-PSResource -Name "Carbon" -Repository $PSGalleryName - $resModule.Name | Should -Be "Carbon" + $resModule = Find-PSResource -Name $testModuleName -Repository $TestGalleryName + $resModule.Name | Should -Be $testModuleName $resModuleType = Out-String -InputObject $resModule.Type $resModuleType.Replace(",", " ").Split() | Should -Contain "Module" } @@ -274,7 +275,7 @@ Describe 'Test Find-PSResource for Module' { It "find all resources with specified tag given Tag property" { $foundTestModule = $False $foundTestScript = $False - $tagToFind = "Tag1" + $tagToFind = "Tag2" $res = Find-PSResource -Tag $tagToFind -Repository $TestGalleryName foreach ($item in $res) { $item.Tags -contains $tagToFind | Should -Be $True From 213380a7e9e25db6b18ae10b57b9f168c95a43ea Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 3 Nov 2021 14:22:24 -0700 Subject: [PATCH 089/276] Fix for Install-PSResource always reinstall issue (#525) * Fix for always reinstall issue and general clean up * Added restore option for reinstall, in case the install fails --- LICENSE | 4 +- doBuild.ps1 | 57 +++---- src/PowerShellGet.psd1 | 2 +- src/code/FindHelper.cs | 41 +++-- src/code/GetHelper.cs | 13 +- src/code/GetInstalledPSResource.cs | 8 +- src/code/InstallHelper.cs | 259 +++++++++++++++-------------- src/code/InstallPSResource.cs | 3 +- src/code/PowerShellGet.csproj | 6 +- src/code/SavePSResource.cs | 5 +- src/code/UpdatePSResource.cs | 22 +-- src/code/Utils.cs | 70 ++++++++ test/InstallPSResource.Tests.ps1 | 26 +++ 13 files changed, 310 insertions(+), 206 deletions(-) diff --git a/LICENSE b/LICENSE index 4448db3d5..4c3581d3b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -MIT License +Copyright (c) Microsoft Corporation. -Copyright (c) 2020 PowerShell Team +MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/doBuild.ps1 b/doBuild.ps1 index a024b035d..119f8d9a8 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -36,6 +36,14 @@ function DoBuild Write-Verbose -Verbose -Message "Copying help files to '$BuildOutPath'" Copy-Item -Path "${HelpPath}/${Culture}" -Dest "$BuildOutPath" -Recurse -Force + # Copy license + Write-Verbose -Verbose -Message "Copying LICENSE file to '$BuildOutPath'" + Copy-Item -Path "./LICENSE" -Dest "$BuildOutPath" + + # Copy notice + # Write-Verbose -Verbose -Message "Copying ThirdPartyNotices.txt to '$BuildOutPath'" + # Copy-Item -Path "./ThirdPartyNotices.txt" -Dest "$BuildOutPath" + # # Copy DSC resources # TODO: This should not be part of PowerShellGet build/publish and should be moved to its own project @@ -65,40 +73,21 @@ function DoBuild } # Place build results - if ($BuildFramework -eq "netstandard2.0") { - $assemblyNames = @( - 'PowerShellGet' - 'Microsoft.Extensions.Logging.Abstractions' - 'MoreLinq' - 'NuGet.Commands' - 'NuGet.Common' - 'NuGet.Configuration' - 'NuGet.Frameworks' - 'NuGet.Packaging' - 'NuGet.ProjectModel' - 'NuGet.Protocol' - 'NuGet.Repositories' - 'NuGet.Versioning' - 'Newtonsoft.Json' - ) - } elseif ($BuildFramework -eq 'net472') { - $assemblyNames = @( - 'PowerShellGet' - 'Microsoft.Extensions.Logging.Abstractions' - 'MoreLinq' - 'NuGet.Commands' - 'NuGet.Common' - 'NuGet.Configuration' - 'NuGet.Frameworks' - 'NuGet.Packaging' - 'NuGet.ProjectModel' - 'NuGet.Protocol' - 'NuGet.Repositories' - 'NuGet.Versioning' - 'Newtonsoft.Json' - 'System.Security.Principal.Windows' - ) - } + $assemblyNames = @( + 'PowerShellGet' + 'Microsoft.Extensions.Logging.Abstractions' + 'MoreLinq' + 'NuGet.Commands' + 'NuGet.Common' + 'NuGet.Configuration' + 'NuGet.Frameworks' + 'NuGet.Packaging' + 'NuGet.ProjectModel' + 'NuGet.Protocol' + 'NuGet.Repositories' + 'NuGet.Versioning' + 'Newtonsoft.Json' + ) $buildSuccess = $true foreach ($fileName in $assemblyNames) diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 6b4bcc2a6..90ef61a52 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.11' + ModuleVersion = '3.0.12' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 8ed8db1cc..143590345 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1,23 +1,23 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using MoreLinq.Extensions; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; using System; using System.Collections.Generic; using System.Data; -using Dbg = System.Diagnostics.Debug; using System.Linq; using System.Management.Automation; using System.Net; using System.Net.Http; using System.Threading; -using MoreLinq.Extensions; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using static Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; + +using Dbg = System.Diagnostics.Debug; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -26,6 +26,8 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// internal class FindHelper { + #region Members + private CancellationToken _cancellationToken; private readonly PSCmdlet _cmdletPassedIn; private List _pkgsLeftToFind; @@ -50,12 +52,22 @@ internal class FindHelper private const int SearchAsyncMaxReturned = 5990; private const int GalleryMax = 12000; + #endregion + + #region Constructor + + private FindHelper() { } + public FindHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) { _cancellationToken = cancellationToken; _cmdletPassedIn = cmdletPassedIn; } + #endregion + + #region Public methods + public IEnumerable FindByResourceName( string[] name, ResourceType type, @@ -175,7 +187,11 @@ public IEnumerable FindByResourceName( } } - public IEnumerable SearchFromRepository( + #endregion + + #region Private methods + + private IEnumerable SearchFromRepository( string repositoryName, Uri repositoryUrl) { @@ -255,7 +271,7 @@ public IEnumerable SearchFromRepository( } } - public IEnumerable SearchAcrossNamesInRepository( + private IEnumerable SearchAcrossNamesInRepository( string repositoryName, PackageSearchResource pkgSearchResource, PackageMetadataResource pkgMetadataResource, @@ -637,5 +653,6 @@ SourceCacheContext sourceCacheContext } } } + #endregion } -} \ No newline at end of file +} diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 18cd5ab29..213569cf5 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -1,16 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; using System; using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; using System.IO; -using System.Linq; using System.Management.Automation; -using System.Threading; -using MoreLinq.Extensions; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +using Dbg = System.Diagnostics.Debug; using static Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo; -using NuGet.Versioning; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -38,7 +37,7 @@ public GetHelper(PSCmdlet cmdletPassedIn) #region Public methods - public IEnumerable FilterPkgPaths( + public IEnumerable GetPackagesFromPath( string[] name, VersionRange versionRange, List pathsToSearch) diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index dfcd7202b..612940dc1 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -1,13 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; using System; using System.Collections.Generic; -using System.IO; using System.Management.Automation; -using System.Threading; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using NuGet.Versioning; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -130,7 +128,7 @@ protected override void ProcessRecord() } GetHelper getHelper = new GetHelper(this); - foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(namesToSearch, _versionRange, _pathsToSearch)) + foreach (PSResourceInfo pkg in getHelper.GetPackagesFromPath(namesToSearch, _versionRange, _pathsToSearch)) { WriteObject(pkg); } diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index ed5d89a47..7edd67461 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -1,5 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using MoreLinq.Extensions; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.Packaging.PackageExtraction; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; using System; using System.Collections; using System.Collections.Generic; @@ -10,16 +21,6 @@ using System.Net; using System.Text.RegularExpressions; using System.Threading; -using MoreLinq.Extensions; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging; -using NuGet.Packaging.Core; -using NuGet.Packaging.PackageExtraction; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -28,33 +29,37 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// internal class InstallHelper : PSCmdlet { + #region Members + + private const string MsgRepositoryNotTrusted = "Untrusted repository"; + private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; + private CancellationToken _cancellationToken; - private readonly bool _updatePkg; private readonly bool _savePkg; private readonly PSCmdlet _cmdletPassedIn; - List _pathsToInstallPkg; - VersionRange _versionRange; - bool _prerelease; - bool _acceptLicense; - bool _quiet; - bool _reinstall; - bool _force; - bool _trustRepository; - bool _noClobber; - PSCredential _credential; - string _specifiedPath; - bool _asNupkg; - bool _includeXML; - - public InstallHelper(bool updatePkg, bool savePkg, PSCmdlet cmdletPassedIn) + private List _pathsToInstallPkg; + private VersionRange _versionRange; + private bool _prerelease; + private bool _acceptLicense; + private bool _quiet; + private bool _reinstall; + private bool _force; + private bool _trustRepository; + private PSCredential _credential; + private string _specifiedPath; + private bool _asNupkg; + private bool _includeXML; + + #endregion + + #region Public methods + + public InstallHelper(bool savePkg, PSCmdlet cmdletPassedIn) { - // Define the cancellation token. CancellationTokenSource source = new CancellationTokenSource(); - _cancellationToken = source.Token; - - this._updatePkg = updatePkg; - this._savePkg = savePkg; - this._cmdletPassedIn = cmdletPassedIn; + _cancellationToken = source.Token; + _savePkg = savePkg; + _cmdletPassedIn = cmdletPassedIn; } public void InstallPackages( @@ -67,7 +72,6 @@ public void InstallPackages( bool reinstall, bool force, bool trustRepository, - bool noClobber, PSCredential credential, string requiredResourceFile, string requiredResourceJson, @@ -78,7 +82,7 @@ public void InstallPackages( List pathsToInstallPkg) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}';", string.Join(",", names), (versionRange != null ? versionRange.OriginalString : string.Empty), prerelease.ToString(), @@ -86,8 +90,7 @@ public void InstallPackages( acceptLicense.ToString(), quiet.ToString(), reinstall.ToString(), - trustRepository.ToString(), - noClobber.ToString())); + trustRepository.ToString())); _versionRange = versionRange; _prerelease = prerelease; @@ -96,7 +99,6 @@ public void InstallPackages( _reinstall = reinstall; _force = force; _trustRepository = trustRepository; - _noClobber = noClobber; _credential = credential; _specifiedPath = specifiedPath; _asNupkg = asNupkg; @@ -107,27 +109,30 @@ public void InstallPackages( ProcessRepositories(names, repository, _trustRepository, _credential); } + #endregion + + #region Private methods + // This method calls iterates through repositories (by priority order) to search for the pkgs to install - public void ProcessRepositories(string[] packageNames, string[] repository, bool trustRepository, PSCredential credential) + private void ProcessRepositories(string[] packageNames, string[] repository, bool trustRepository, PSCredential credential) { var listOfRepositories = RepositorySettings.Read(repository, out string[] _); - List packagesToInstall = packageNames.ToList(); + List pckgNamesToInstall = packageNames.ToList(); var yesToAll = false; var noToAll = false; - var repositoryIsNotTrusted = "Untrusted repository"; - var queryInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; + var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); foreach (var repo in listOfRepositories) { // If no more packages to install, then return - if (!packagesToInstall.Any()) return; + if (!pckgNamesToInstall.Any()) return; - var sourceTrusted = false; string repoName = repo.Name; _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true // OR the user issues trust interactively via console. + var sourceTrusted = true; if (repo.Trusted == false && !trustRepository && !_force) { _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); @@ -135,89 +140,74 @@ public void ProcessRepositories(string[] packageNames, string[] repository, bool if (!(yesToAll || noToAll)) { // Prompt for installation of package from untrusted repository - var message = string.Format(CultureInfo.InvariantCulture, queryInstallUntrustedPackage, repoName); - sourceTrusted = _cmdletPassedIn.ShouldContinue(message, repositoryIsNotTrusted, true, ref yesToAll, ref noToAll); + var message = string.Format(CultureInfo.InvariantCulture, MsgInstallUntrustedPackage, repoName); + sourceTrusted = _cmdletPassedIn.ShouldContinue(message, MsgRepositoryNotTrusted, true, ref yesToAll, ref noToAll); } } - else - { - sourceTrusted = true; - } - if (sourceTrusted || yesToAll) + if (!sourceTrusted && !yesToAll) { - _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); + continue; + } - // If it can't find the pkg in one repository, it'll look for it in the next repo in the list - var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); + _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); + // If it can't find the pkg in one repository, it'll look for it in the next repo in the list + var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); - var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); - // Finds parent packages and dependencies - IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( - name: packageNames, - type: ResourceType.None, - version: _versionRange != null ? _versionRange.OriginalString : null, - prerelease: _prerelease, - tag: null, - repository: new string[] { repoName }, - credential: credential, - includeDependencies: true); + // Finds parent packages and dependencies + IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( + name: packageNames, + type: ResourceType.None, + version: _versionRange != null ? _versionRange.OriginalString : null, + prerelease: _prerelease, + tag: null, + repository: new string[] { repoName }, + credential: credential, + includeDependencies: true); - foreach (PSResourceInfo a in pkgsFromRepoToInstall) - { - var test = a; - _cmdletPassedIn.WriteVerbose(a.Version.ToString()); - } - - // Select the first package from each name group, which is guaranteed to be the latest version. - // We should only have one version returned for each package name - // e.g.: - // PackageA (version 1.0) - // PackageB (version 2.0) - // PackageC (version 1.0) - pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( - m => new { m.Name }).Select( - group => group.First()).ToList(); - - if (!pkgsFromRepoToInstall.Any()) - { - _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); - // Check in the next repository - continue; - } + if (!pkgsFromRepoToInstall.Any()) + { + _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); + // Check in the next repository + continue; + } - // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) - if (!_reinstall) - { - // Removes all of the names that are already installed from the list of names to search for - pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); - } + // Select the first package from each name group, which is guaranteed to be the latest version. + // We should only have one version returned for each package name + // e.g.: + // PackageA (version 1.0) + // PackageB (version 2.0) + // PackageC (version 1.0) + pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( + m => new { m.Name }).Select( + group => group.First()).ToList(); + + // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) + if (!_reinstall) + { + // Removes all of the names that are already installed from the list of names to search for + pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); + } - if (!pkgsFromRepoToInstall.Any()) - { - continue; - } + if (!pkgsFromRepoToInstall.Any()) + { + continue; + } - List pkgsInstalled = InstallPackage(pkgsFromRepoToInstall, repoName, repo.Url.AbsoluteUri, credential, isLocalRepo); + List pkgsInstalled = InstallPackage(pkgsFromRepoToInstall, repoName, repo.Url.AbsoluteUri, credential, isLocalRepo); - foreach (string name in pkgsInstalled) - { - packagesToInstall.Remove(name); - } + foreach (string name in pkgsInstalled) + { + pckgNamesToInstall.Remove(name); } } } // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install - public IEnumerable FilterByInstalledPkgs(IEnumerable packagesToInstall) + private IEnumerable FilterByInstalledPkgs(IEnumerable packages) { - List pkgNames = new List(); - foreach (var pkg in packagesToInstall) - { - pkgNames.Add(pkg.Name); - } - + // Create list of installation paths to search. List _pathsToSearch = new List(); GetHelper getHelper = new GetHelper(_cmdletPassedIn); // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) @@ -232,21 +222,34 @@ public IEnumerable FilterByInstalledPkgs(IEnumerable pkgsAlreadyInstalled = getHelper.FilterPkgPaths(pkgNames.ToArray(), _versionRange, _pathsToSearch); + var filteredPackages = new Dictionary(); + foreach (var pkg in packages) + { + filteredPackages.Add(pkg.Name, pkg); + } - // If any pkg versions are already installed, write a message saying it is already installed and continue processing other pkg names - if (pkgsAlreadyInstalled.Any()) + // Get currently installed packages. + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( + name: filteredPackages.Keys.ToArray(), + versionRange: _versionRange, + pathsToSearch: _pathsToSearch); + if (!pkgsAlreadyInstalled.Any()) { - foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) - { - _cmdletPassedIn.WriteWarning(string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", pkg.Name, pkg.Version)); + return packages; + } - // remove this pkg from the list of pkg names install - packagesToInstall.ToList().Remove(pkg); - } + // Remove from list package versions that are already installed. + foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) + { + _cmdletPassedIn.WriteWarning( + string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", + pkg.Name, + pkg.Version)); + + filteredPackages.Remove(pkg.Name); } - return packagesToInstall; + return filteredPackages.Values.ToArray(); } private List InstallPackage(IEnumerable pkgsToInstall, string repoName, string repoUrl, PSCredential credential, bool isLocalRepo) @@ -439,7 +442,14 @@ private List InstallPackage(IEnumerable pkgsToInstall, s } catch (Exception e) { - _cmdletPassedIn.WriteVerbose(string.Format("Unable to successfully install package '{0}': '{1}'", p.Name, e.Message)); + _cmdletPassedIn.WriteError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Unable to successfully install package '{p.Name}': '{e.Message}'", + innerException: e), + "InstallPackageFailed", + ErrorCategory.InvalidOperation, + _cmdletPassedIn)); } finally { @@ -665,12 +675,13 @@ private void MoveFilesIntoInstallPath( { _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); - // At this point if if (Directory.Exists(finalModuleVersionDir)) { - // Delete the directory path before replacing it with the new module - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", finalModuleVersionDir)); - Directory.Delete(finalModuleVersionDir, true); + // Delete the directory path before replacing it with the new module. + // If deletion fails (usually due to binary file in use), then attempt restore so that the currently + // installed module is not corrupted. + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete with restore on failure.'{0}'", finalModuleVersionDir)); + Utils.DeleteDirectoryWithRestore(finalModuleVersionDir); } _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); @@ -705,5 +716,7 @@ private void MoveFilesIntoInstallPath( Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); } } + + #endregion } } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 42be06c52..cc2021d92 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -125,7 +125,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - var installHelper = new InstallHelper(updatePkg: false, savePkg: false, cmdletPassedIn: this); + var installHelper = new InstallHelper(savePkg: false, cmdletPassedIn: this); switch (ParameterSetName) { case NameParameterSet: @@ -235,7 +235,6 @@ private void ProcessInstallHelper(InstallHelper installHelper, string[] pkgNames reinstall: Reinstall, force: false, trustRepository: TrustRepository, - noClobber: false, credential: Credential, requiredResourceFile: null, requiredResourceJson: null, diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 2dfd10cbe..9452ccff4 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.11.0 - 3.0.11 - 3.0.11 + 3.0.12.0 + 3.0.12 + 3.0.12 netstandard2.0 8.0 diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index be5180150..dd8bf7d84 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -140,7 +140,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - var installHelper = new InstallHelper(updatePkg: false, savePkg: true, cmdletPassedIn: this); + var installHelper = new InstallHelper(savePkg: true, cmdletPassedIn: this); switch (ParameterSetName) { case NameParameterSet: @@ -234,8 +234,7 @@ private void ProcessSaveHelper(InstallHelper installHelper, string[] pkgNames, b quiet: true, reinstall: true, force: false, - trustRepository: TrustRepository, - noClobber: false, + trustRepository: TrustRepository, credential: Credential, requiredResourceFile: null, requiredResourceJson: null, diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 0cf0a8fe5..fe2eb92a4 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -1,16 +1,12 @@ -using System.Collections.Specialized; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; using System; using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; using System.Linq; using System.Management.Automation; -using System.Text; -using System.Threading; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using NuGet.Versioning; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -103,9 +99,9 @@ public sealed class UpdatePSResource : PSCmdlet #region Override Methods protected override void BeginProcessing() - { - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + { + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); @@ -144,7 +140,6 @@ protected override void ProcessRecord() } InstallHelper installHelper = new InstallHelper( - updatePkg: true, savePkg: false, cmdletPassedIn: this); @@ -155,10 +150,9 @@ protected override void ProcessRecord() repository: Repository, acceptLicense: AcceptLicense, quiet: Quiet, - reinstall: false, + reinstall: true, force: Force, trustRepository: TrustRepository, - noClobber: false, credential: Credential, requiredResourceFile: null, requiredResourceJson: null, @@ -211,7 +205,7 @@ private string[] ProcessPackageNameWildCards(string[] namesToProcess, VersionRan GetHelper getHelper = new GetHelper( cmdletPassedIn: this); - namesToProcess = getHelper.FilterPkgPaths( + namesToProcess = getHelper.GetPackagesFromPath( name: namesToProcess, versionRange: versionRange, pathsToSearch: Utils.GetAllResourcePaths(this)).Select(p => p.Name).ToArray(); @@ -221,4 +215,4 @@ private string[] ProcessPackageNameWildCards(string[] namesToProcess, VersionRan } #endregion } -} \ No newline at end of file +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index aaca16bbc..ecfbc62b0 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -457,6 +457,51 @@ public static void WriteVerboseOnCmdlet( #region Directory and File + /// + /// Deletes a directory and its contents. + /// Attempts to restore the directory and contents if deletion fails. + /// + public static void DeleteDirectoryWithRestore(string dirPath) + { + string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + + try + { + // Create temporary directory for restore operation if needed. + CopyDirContents(dirPath, tempDirPath, overwrite: true); + + try + { + DeleteDirectory(dirPath); + } + catch (Exception ex) + { + // Delete failed. Attempt to restore the saved directory content. + try + { + RestoreDirContents(tempDirPath, dirPath); + } + catch (Exception exx) + { + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", + ex); + } + + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. The previous package contents have been restored.", + ex); + } + } + finally + { + if (Directory.Exists(tempDirPath)) + { + DeleteDirectory(tempDirPath); + } + } + } + /// /// Deletes a directory and its contents /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell @@ -535,6 +580,31 @@ private static void CopyDirContents( } } + private static void RestoreDirContents( + string sourceDirPath, + string destDirPath) + { + if (!Directory.Exists(destDirPath)) + { + Directory.CreateDirectory(destDirPath); + } + + foreach (string filePath in Directory.GetFiles(sourceDirPath)) + { + string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + if (!File.Exists(destFilePath)) + { + File.Copy(filePath, destFilePath); + } + } + + foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + RestoreDirContents(srcSubDirPath, destSubDirPath); + } + } + #endregion } } diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index fd8be4ba2..8762290a9 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -196,6 +196,32 @@ Describe 'Test Install-PSResource for Module' { $pkg.Version | Should -Be "1.3.0" } + It "Restore resource after reinstall fails" { + Install-PSResource -Name "TestModule" -Repository $TestGalleryName + $pkg = Get-Module "TestModule" -ListAvailable + $pkg.Name | Should -Be "TestModule" + $pkg.Version | Should -Be "1.3.0" + + $resourcePath = Split-Path -Path $pkg.Path -Parent + $resourceFiles = Get-ChildItem -Path $resourcePath -Recurse + + # Lock resource file to prevent reinstall from succeeding. + $fs = [System.IO.File]::Open($resourceFiles[0].FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read) + try + { + # Reinstall of resource should fail with one of its files locked. + Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Reinstall -ErrorVariable ev -ErrorAction Silent + $ev.FullyQualifiedErrorId | Should -BeExactly 'InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource' + } + finally + { + $fs.Close() + } + + # Verify that resource module has been restored. + (Get-ChildItem -Path $resourcePath -Recurse).Count | Should -BeExactly $resourceFiles.Count + } + It "Install resource that requires accept license with -AcceptLicense flag" { Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName -AcceptLicense $pkg = Get-InstalledPSResource "testModuleWithlicense" From 592979e57b6283091976076d4d9a39bf37915a43 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 4 Nov 2021 13:42:42 -0400 Subject: [PATCH 090/276] update error message to mention repo name, also clean up some success/fail messages (#531) --- src/code/PublishPSResource.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 5d7c13176..bb74a005e 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -374,7 +374,7 @@ protected override void ProcessRecord() return; } - PushNupkg(outputNupkgDir, repositoryUrl); + PushNupkg(outputNupkgDir, repository.Name, repositoryUrl); } finally { WriteVerbose(string.Format("Deleting temporary directory '{0}'", outputDir)); @@ -831,13 +831,13 @@ private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFil } else { - WriteVerbose("Successfully packed the resource into a .nupkg"); + WriteVerbose("Not able to successfully pack the resource into a .nupkg"); } return success; } - private void PushNupkg(string outputNupkgDir, string repoUrl) + private void PushNupkg(string outputNupkgDir, string repoName, string repoUrl) { // Push the nupkg to the appropriate repository // Pkg version is parsed from .ps1 file or .psd1 file @@ -875,7 +875,7 @@ private void PushNupkg(string outputNupkgDir, string repoUrl) // look in PS repo for how httpRequestExceptions are handled // Unfortunately there is no response message are no status codes provided with the exception and no - var ex = new ArgumentException(e.Message); + var ex = new ArgumentException(String.Format("Repository '{0}': {1}", repoName, e.Message)); if (e.Message.Contains("401")) { if (e.Message.Contains("API")) @@ -924,7 +924,7 @@ private void PushNupkg(string outputNupkgDir, string repoUrl) } else { - WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUrl)); + WriteVerbose(string.Format("Not able to publish resource to '{0}'", repoUrl)); } } } From 36a630570aa010809c124d3ffeb23638701ca6fd Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 4 Nov 2021 18:48:22 -0400 Subject: [PATCH 091/276] Uninstall and Get-Installed prerelease support for Version parameter (#523) implement prerelease versioning search support for Get and Uninstall --- src/code/GetHelper.cs | 31 ++++++++++--------- src/code/UninstallPSResource.cs | 7 +++-- src/code/Utils.cs | 43 +++++++++++++++++++++++++++ test/GetInstalledPSResource.Tests.ps1 | 22 ++++++++++++++ test/UninstallPSResource.Tests.ps1 | 38 +++++++++++++++++++---- 5 files changed, 118 insertions(+), 23 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 213569cf5..11d31813e 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -111,19 +111,18 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li foreach (string versionPath in versionsDirs) { _cmdletPassedIn.WriteVerbose(string.Format("Searching through package version path: '{0}'", versionPath)); - DirectoryInfo dirInfo = new DirectoryInfo(versionPath); - - // if the version is not valid, we'll just skip it and output a debug message - if (!NuGetVersion.TryParse(dirInfo.Name, out NuGetVersion dirAsNugetVersion)) + if(!Utils.GetVersionForInstallPath(installedPkgPath: versionPath, + isModule: true, + cmdletPassedIn: _cmdletPassedIn, + out NuGetVersion pkgNugetVersion)) { - _cmdletPassedIn.WriteVerbose(string.Format("Leaf directory in path '{0}' cannot be parsed into a version.", versionPath)); - // skip to next iteration of the loop continue; } - _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); - if (versionRange.Satisfies(dirAsNugetVersion)) + _cmdletPassedIn.WriteVerbose(string.Format("Package version parsed as NuGet version: '{0}'", pkgNugetVersion)); + + if (versionRange.Satisfies(pkgNugetVersion)) { // This will be one version or a version range. // yield results then continue with this iteration of the loop @@ -149,17 +148,17 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // check to make sure it's within the version range. // script versions will be parsed from the script xml file PSResourceInfo scriptInfo = OutputPackageObject(pkgPath, _scriptDictionary); - if (scriptInfo == null) + if(!Utils.GetVersionForInstallPath(installedPkgPath: pkgPath, + isModule: false, + cmdletPassedIn: _cmdletPassedIn, + out NuGetVersion pkgNugetVersion)) { - // if script was not found skip to the next iteration of the loop - continue; + // skip to next iteration of the loop + yield return pkgPath; } - if (!NuGetVersion.TryParse(scriptInfo.Version.ToString(), out NuGetVersion scriptVersion)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Version '{0}' could not be properly parsed from the script metadata file from the script installed at '{1}'", scriptInfo.Version.ToString(), scriptInfo.InstalledLocation)); - } - else if (versionRange.Satisfies(scriptVersion)) + _cmdletPassedIn.WriteVerbose(string.Format("Package version parsed as NuGet version: '{0}'", pkgNugetVersion)); + if (versionRange.Satisfies(pkgNugetVersion)) { _scriptDictionary.Add(pkgPath, scriptInfo); yield return pkgPath; diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 36d16a1a0..7964c0deb 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,4 +1,3 @@ -using System.Text; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; @@ -110,7 +109,11 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - if (!Utils.TryParseVersionOrVersionRange(InputObject.Version.ToString(), out _versionRange)) + string inputObjectPrereleaseLabel = InputObject.PrereleaseLabel; + string inputObjectVersion = String.IsNullOrEmpty(inputObjectPrereleaseLabel) ? InputObject.Version.ToString() : Utils.GetNormalizedVersionString(versionString: InputObject.Version.ToString(), prerelease: inputObjectPrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange( + version: inputObjectVersion, + versionRange: out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); var ex = new ArgumentException(exMessage); diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ecfbc62b0..1c034124a 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -180,6 +180,49 @@ public static bool TryParseVersionOrVersionRange( return VersionRange.TryParse(version, out versionRange); } + public static bool GetVersionForInstallPath( + string installedPkgPath, + bool isModule, + PSCmdlet cmdletPassedIn, + out NuGetVersion pkgNuGetVersion) + { + // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file + // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. + // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current + // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. + + // for Modules, installedPkgPath will look like this: + // ./PowerShell/Modules/test_module/3.0.0 + // for Scripts, installedPkgPath will look like this: + // ./PowerShell/Scripts/test_script.ps1 + string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); + + string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); + if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + cmdletPassedIn.WriteVerbose(String.Format( + "The {0} file found at location: {1} cannot be parsed due to {2}", + isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", + packageInfoXMLFilePath, + errorMsg)); + pkgNuGetVersion = null; + return false; + } + + string version = psGetInfo.Version.ToString(); + string prereleaseLabel = psGetInfo.PrereleaseLabel; + + if (!NuGetVersion.TryParse( + value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), + version: out pkgNuGetVersion)) + { + cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); + return false; + } + + return true; + } + #endregion #region Url methods diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 937ab4e72..95b51406d 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -7,6 +7,8 @@ Describe 'Test Get-InstalledPSResource for Module' { BeforeAll{ $TestGalleryName = Get-PoshTestGalleryName + $testModuleName = "test_module" + $testScriptName = "test_script" Get-NewPSResourceRepositoryFile Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository @@ -106,4 +108,24 @@ $testCases = $pkgs = Get-InstalledPSResource -Name ContosoServer -Version "*" $pkgs.Count | Should -BeGreaterOrEqual 2 } + + It "Get prerelease version module when version with correct prerelease label is specified" { + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName + $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5" + $res | Should -BeNullOrEmpty + $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "5.2.5" + $res.PrereleaseLabel | Should -Be "alpha001" + } + + It "Get prerelease version script when version with correct prerelease label is specified" { + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName + $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0" + $res | Should -BeNullOrEmpty + $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res.Name | Should -Be $testScriptName + $res.Version | Should -Be "3.0.0" + $res.PrereleaseLabel | Should -Be "alpha001" + } } diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 8f5f6a9f9..225623dcf 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -9,6 +9,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $testModuleName = "test_module" + $testScriptName = "test_script" Get-NewPSResourceRepositoryFile $res = Uninstall-PSResource -name ContosoServer -Version "*" } @@ -137,6 +138,36 @@ Describe 'Test Uninstall-PSResource for Modules' { $pkg.Version | Should -Be "2.5" } + It "Uninstall prerelease version module when prerelease version specified" { + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName + Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res = Get-InstalledPSResource $testModuleName -Version "5.2.5-alpha001" + $res | Should -BeNullOrEmpty + } + + It "Not uninstall non-prerelease version module when similar prerelease version is specified" { + Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" + $res = Get-InstalledPSResource -Name $testModuleName -Version "5.0.0.0" + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "5.0.0.0" + } + + It "Uninstall prerelease version script when prerelease version specified" { + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName + Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res = Get-InstalledPSResource -Name $testScriptName + $res | Should -BeNullOrEmpty + } + + It "Not uninstall non-prerelease version module when prerelease version specified" { + Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testScriptName -Version "2.5.0-alpha001" + $res = Get-InstalledPSResource -Name $testScriptName -Version "2.5.0.0" + $res.Name | Should -Be $testScriptName + $res.Version | Should -Be "2.5.0.0" + } + It "Uninstall module using -WhatIf, should not uninstall the module" { $res = Uninstall-PSResource -Name "ContosoServer" -WhatIf @@ -173,11 +204,8 @@ Describe 'Test Uninstall-PSResource for Modules' { It "Uninstall PSResourceInfo object piped in for prerelease version object" { Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - # Powershell cannot create install locations indicating a prerelease version (with prerelease label indicated in install location). - # To test we can uninstall prerelease versions, we must use the numeric part of the prerelease version only and it must be unique - # of all versions installed for that module. - Get-InstalledPSResource -Name $testModuleName -Version "4.5.2" | Uninstall-PSResource - $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2" + Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource + $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" $res | Should -BeNullOrEmpty } } From a47af8adfb3e74d52409faa9e179ad08b3e78298 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 4 Nov 2021 21:44:43 -0700 Subject: [PATCH 092/276] Add -NoClobber functionality to Install-PSResource (#509) --- src/code/InstallHelper.cs | 85 +++++++++++++++++++++++++++++--- src/code/InstallPSResource.cs | 14 ++++-- src/code/SavePSResource.cs | 4 +- src/code/UpdatePSResource.cs | 4 +- test/InstallPSResource.Tests.ps1 | 11 ++++- 5 files changed, 100 insertions(+), 18 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 7edd67461..d92d9c7d6 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -49,6 +49,8 @@ internal class InstallHelper : PSCmdlet private string _specifiedPath; private bool _asNupkg; private bool _includeXML; + private bool _noClobber; + List _pathsToSearch; #endregion @@ -72,17 +74,15 @@ public void InstallPackages( bool reinstall, bool force, bool trustRepository, + bool noClobber, PSCredential credential, - string requiredResourceFile, - string requiredResourceJson, - Hashtable requiredResourceHash, string specifiedPath, bool asNupkg, bool includeXML, List pathsToInstallPkg) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}';", + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", string.Join(",", names), (versionRange != null ? versionRange.OriginalString : string.Empty), prerelease.ToString(), @@ -90,7 +90,8 @@ public void InstallPackages( acceptLicense.ToString(), quiet.ToString(), reinstall.ToString(), - trustRepository.ToString())); + trustRepository.ToString(), + noClobber.ToString())); _versionRange = versionRange; _prerelease = prerelease; @@ -99,12 +100,28 @@ public void InstallPackages( _reinstall = reinstall; _force = force; _trustRepository = trustRepository; + _noClobber = noClobber; _credential = credential; _specifiedPath = specifiedPath; _asNupkg = asNupkg; _includeXML = includeXML; _pathsToInstallPkg = pathsToInstallPkg; + // Create list of installation paths to search. + _pathsToSearch = new List(); + + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // e.g.: + // ./InstallPackagePath1/PackageA + // ./InstallPackagePath1/PackageB + // ./InstallPackagePath2/PackageC + // ./InstallPackagePath3/PackageD + foreach (var path in _pathsToInstallPkg) + { + _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); + } + // Go through the repositories and see which is the first repository to have the pkg version available ProcessRepositories(names, repository, _trustRepository, _credential); } @@ -209,7 +226,6 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable _pathsToSearch = new List(); - GetHelper getHelper = new GetHelper(_cmdletPassedIn); // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations // e.g.: @@ -228,6 +244,7 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( name: filteredPackages.Keys.ToArray(), @@ -410,6 +427,12 @@ private List InstallPackage(IEnumerable pkgsToInstall, s { continue; } + + // If NoClobber is specified, ensure command clobbering does not happen + if (_noClobber && !DetectClobber(p.Name, tempDirNameVersion, parsedMetadataHashtable)) + { + continue; + } } // Delete the extra nupkg related files that are not needed and not part of the module/script @@ -548,6 +571,56 @@ private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string t return success; } + private bool DetectClobber(string pkgName, string tempDirNameVersion, Hashtable parsedMetadataHashtable) + { + // Get installed modules, then get all possible paths + bool foundClobber = false; + GetHelper getHelper = new GetHelper(_cmdletPassedIn); + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath(new string[] { "*" }, VersionRange.All, _pathsToSearch); + // user parsed metadata hash + List listOfCmdlets = new List(); + foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) + { + listOfCmdlets.Add(cmdletName as string); + + } + + foreach (var pkg in pkgsAlreadyInstalled) + { + List duplicateCmdlets = new List(); + List duplicateCmds = new List(); + // See if any of the cmdlets or commands in the pkg we're trying to install exist within a package that's already installed + if (pkg.Includes.Cmdlet != null && pkg.Includes.Cmdlet.Any()) + { + duplicateCmdlets = listOfCmdlets.Where(cmdlet => pkg.Includes.Cmdlet.Contains(cmdlet)).ToList(); + + } + if (pkg.Includes.Command != null && pkg.Includes.Command.Any()) + { + duplicateCmds = listOfCmdlets.Where(commands => pkg.Includes.Command.Contains(commands, StringComparer.InvariantCultureIgnoreCase)).ToList(); + } + if (duplicateCmdlets.Any() || duplicateCmds.Any()) + { + + duplicateCmdlets.AddRange(duplicateCmds); + + var errMessage = string.Format( + "The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", + String.Join(", ", duplicateCmdlets), pkgName); + + var ex = new ArgumentException(errMessage); + var noClobberError = new ErrorRecord(ex, "CommandAlreadyExists", ErrorCategory.ResourceExists, null); + + _cmdletPassedIn.WriteError(noClobberError); + foundClobber = true; + + return foundClobber; + } + } + + return foundClobber; + } + private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isModule) { // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index cc2021d92..ea5e6812c 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -70,7 +70,7 @@ class InstallPSResource : PSCmdlet [Parameter(ParameterSetName = NameParameterSet)] [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter TrustRepository { get; set; } - + /// /// Overwrites a previously installed resource with the same name and version. /// @@ -92,6 +92,12 @@ class InstallPSResource : PSCmdlet [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter AcceptLicense { get; set; } + /// + /// Prevents installing a package that contains cmdlets that already exist on the machine. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter NoClobber { get; set; } + /// /// Used for pipeline input. /// @@ -235,11 +241,9 @@ private void ProcessInstallHelper(InstallHelper installHelper, string[] pkgNames reinstall: Reinstall, force: false, trustRepository: TrustRepository, + noClobber: NoClobber, credential: Credential, - requiredResourceFile: null, - requiredResourceJson: null, - requiredResourceHash: null, - specifiedPath: null, + specifiedPath: null, asNupkg: false, includeXML: true, pathsToInstallPkg: _pathsToInstallPkg); diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index dd8bf7d84..5449333af 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -236,9 +236,7 @@ private void ProcessSaveHelper(InstallHelper installHelper, string[] pkgNames, b force: false, trustRepository: TrustRepository, credential: Credential, - requiredResourceFile: null, - requiredResourceJson: null, - requiredResourceHash: null, + noClobber: false, specifiedPath: _path, asNupkg: false, includeXML: false, diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index fe2eb92a4..7158bc4c6 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -154,9 +154,7 @@ protected override void ProcessRecord() force: Force, trustRepository: TrustRepository, credential: Credential, - requiredResourceFile: null, - requiredResourceJson: null, - requiredResourceHash: null, + noClobber: false, specifiedPath: null, asNupkg: false, includeXML: true, diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 8762290a9..9e5f56fd7 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -279,7 +279,16 @@ Describe 'Test Install-PSResource for Module' { $res.Path.Contains("Modules") | Should -Be $true } - It "Install PSResourceInfo object piped in" { + It "Install module using -NoClobber, should throw clobber error and not install the module" { + Install-PSResource -Name "ClobberTestModule1" -Repository $TestGalleryName + + $res = Get-Module "ClobberTestModule1" -ListAvailable + $res.Name | Should -Be "ClobberTestModule1" + + Install-PSResource -Name "ClobberTestModule2" -Repository $TestGalleryName -NoClobber -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "CommandAlreadyExists,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + } + It "Install PSResourceInfo object piped in" { Find-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName | Install-PSResource $res = Get-InstalledPSResource -Name $testModuleName $res.Name | Should -Be $testModuleName From 5d82ff1a932da8fcd8ae370fc7709eb04aa48579 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 5 Nov 2021 00:01:37 -0700 Subject: [PATCH 093/276] Implement -DestinationPath parameter for Publish-PSResource (#506) --- src/code/PublishPSResource.cs | 65 ++++++++++++++++++++++++-------- test/PublishPSResource.Tests.ps1 | 27 ++++++++----- 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index bb74a005e..af2b5c690 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -48,7 +48,7 @@ public sealed class PublishPSResource : PSCmdlet /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). /// - [Parameter(Mandatory = true, Position = 0, ParameterSetName = "PathParameterSet")] + [Parameter()] [ValidateNotNullOrEmpty] public string Path { @@ -74,32 +74,47 @@ public string Path } } private string _path; - + /// - /// Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is used exactly as entered. - /// No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. - /// Single quotation marks tell PowerShell not to interpret any characters as escape sequences. + /// Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the + /// -Repository parameter to publish to a repository and also save the exact same package to the local file system. /// - [Parameter(Mandatory = true, ParameterSetName = "PathLiteralParameterSet")] + [Parameter()] [ValidateNotNullOrEmpty] - public string LiteralPath + public string DestinationPath { get - { return _literalPath; } + { return _destinationPath; } set { - if (Directory.Exists(value)) + string resolvedPath = string.Empty; + if (!string.IsNullOrEmpty(value)) { - _literalPath = value; + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } - else if (File.Exists(value) && value.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + + if (Directory.Exists(resolvedPath)) { - _literalPath = value; + _destinationPath = resolvedPath; + } + else { + // try to create the path + try + { + Directory.CreateDirectory(value); + } + catch (Exception e) + { + var exMessage = string.Format("Destination path does not exist and cannot be created: {0}", e.Message); + var ex = new ArgumentException(exMessage); + var InvalidDestinationPath = new ErrorRecord(ex, "InvalidDestinationPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidDestinationPath); + } } } } - private string _literalPath; + private string _destinationPath; /// /// Specifies a user account that has rights to a specific repository (used for finding dependencies). @@ -173,8 +188,6 @@ protected override void ProcessRecord() FileInfo moduleFileInfo; Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); - // _path has been resolved, literal path does not need to be resolved - _path = string.IsNullOrEmpty(_path) ? _literalPath : _path; // Returns the name of the file or the name of the directory, depending on path var pkgFileOrDir = new DirectoryInfo(_path); bool isScript = _path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase); @@ -374,7 +387,29 @@ protected override void ProcessRecord() return; } + // If -DestinationPath is specified then also publish the .nupkg there + if (!string.IsNullOrWhiteSpace(_destinationPath)) + { + try + { + var nupkgName = _pkgName + "." + _pkgVersion.ToNormalizedString() + ".nupkg"; + Utils.MoveFiles(System.IO.Path.Combine(outputNupkgDir, nupkgName), System.IO.Path.Combine(_destinationPath, nupkgName)); + } + catch (Exception e) { + var message = string.Format("Error moving .nupkg into destination path '{0}' due to: '{1}'.", _destinationPath, e.Message); + + var ex = new ArgumentException(message); + var ErrorMovingNupkg = new ErrorRecord(ex, "ErrorMovingNupkg", ErrorCategory.NotSpecified, null); + WriteError(ErrorMovingNupkg); + + // exit process record + return; + } + } + + // This call does not throw any exceptions, but it will write unsuccessful responses to the console PushNupkg(outputNupkgDir, repository.Name, repositoryUrl); + } finally { WriteVerbose(string.Format("Deleting temporary directory '{0}'", outputDir)); diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 2a49a1799..2a4feb5b2 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -74,16 +74,6 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } - It "Publish a module with -LiteralPath" { - $version = "1.0.0" - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" - - Publish-PSResource -LiteralPath $script:PublishModuleBase - - $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath - } - <# Temporarily comment this test out until Find Helper is complete and code within PublishPSResource is uncommented It "Publish a module with dependencies" { # Create dependency module @@ -271,4 +261,21 @@ Describe "Test Publish-PSResource" { $Error[0].FullyQualifiedErrorId | Should -be "403Error,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" } + + It "Publish a module with -Path -Repository and -DestinationPath" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + $tmpPath = Join-Path -Path $TestDrive -ChildPath "testtmppath" + New-Item $tmpPath -Itemtype directory -Force + + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 -DestinationPath $tmpPath + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + + $expectedPath = Join-Path -Path $tmpPath -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $tmpPath).FullName | Should -Be $expectedPath + } } From a3a732cabb7d08dcd5d33748b8d612be10880123 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 8 Nov 2021 14:22:11 -0800 Subject: [PATCH 094/276] Updates for Update-PSResource (#534) * Changes to UpdatePSResource command * Add stop processing to UpdatePSResource. Removed multiple instantiations of helper objects. * Reverting to original source * Create InstallHelper object only once. --- Notice.txt | 2167 +++++++++++++++++++++++++++++++++ doBuild.ps1 | 4 +- src/code/FindPSResource.cs | 31 +- src/code/InstallHelper.cs | 1603 ++++++++++++------------ src/code/InstallPSResource.cs | 511 ++++---- src/code/SavePSResource.cs | 499 ++++---- src/code/UpdatePSResource.cs | 153 ++- src/code/Utils.cs | 32 +- 8 files changed, 3655 insertions(+), 1345 deletions(-) create mode 100644 Notice.txt diff --git a/Notice.txt b/Notice.txt new file mode 100644 index 000000000..9e8581321 --- /dev/null +++ b/Notice.txt @@ -0,0 +1,2167 @@ +NOTICES AND INFORMATION +Do Not Translate or Localize + +This software incorporates material from third parties. +Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com, +or you may send a check or money order for US $5.00, including the product name, +the open source component name, platform, and version number, to: + +Source Code Compliance Team +Microsoft Corporation +One Microsoft Way +Redmond, WA 98052 +USA + +Notwithstanding any other terms, you may reverse engineer this software to the extent +required to debug changes to any libraries licensed under the GNU Lesser General Public License. + +--------------------------------------------------------- + +NuGet.Commands 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Common 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Configuration 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Credentials 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.DependencyResolver.Core 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Frameworks 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.LibraryModel 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Packaging 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.ProjectModel 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Protocol 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +NuGet.Versioning 5.8.0 - Apache-2.0 + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +--------------------------------------------------------- + +--------------------------------------------------------- + +morelinq 3.3.2 - Apache-2.0 AND MIT + + +(c) 2008 VeriSign, Inc. +(c) 2008 Jonathan Skeet. +Portions (c) 2017 Jonas Nyrup +Portions (c) 2015 Felipe Sateler +Copyright (c) Microsoft Corporation +Portions (c) 2010 Johannes Rudolph, Leopold Bushkin. +Portions (c) 2009 Atif Aziz, Chris Ammerman, Konrad Rudolph. +Portions (c) 2016 Andreas Gullberg Larsen, Leandro F. Vieira + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +============================================================================== +The following notice applies to a small portion of the code: + +The MIT License (MIT) + +Copyright (c) Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +LinqKit.Core 1.1.17 - MIT + + +(c) 2008 VeriSign, Inc. + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Bcl.AsyncInterfaces 1.0.0 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2007 James Newton-King +Copyright (c) 1991-2017 Unicode, Inc. +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Extensions.DependencyInjection 5.0.0-preview.7.20364.11 - MIT + + + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Extensions.DependencyInjection.Abstractions 5.0.0-preview.7.20364.11 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright 2012 the V8 project +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +Copyright (c) 1998 Microsoft. To +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2018 Alexander Chermyanin +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) The Internet Society 1997. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) The Internet Society (2003). +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Extensions.Logging 5.0.0-preview.7.20364.11 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright 2012 the V8 project +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +Copyright (c) 1998 Microsoft. To +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2018 Alexander Chermyanin +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) The Internet Society 1997. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) The Internet Society (2003). +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Extensions.Logging.Abstractions 5.0.0-preview.7.20364.11 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright 2012 the V8 project +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +Copyright (c) 1998 Microsoft. To +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2018 Alexander Chermyanin +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) The Internet Society 1997. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) The Internet Society (2003). +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Extensions.Options 5.0.0-preview.7.20364.11 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright 2012 the V8 project +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +Copyright (c) 1998 Microsoft. To +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2018 Alexander Chermyanin +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) The Internet Society 1997. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) The Internet Society (2003). +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Microsoft.Extensions.Primitives 5.0.0-preview.7.20364.11 - MIT + + + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +Newtonsoft.Json 9.0.1 - MIT + + +(c) 2008 VeriSign, Inc. +Copyright James Newton-King 2008 + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------------------------- + +--------------------------------------------------------- + +PowerShellStandard.Library 7.0.0-preview.1 - MIT + + + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------------------------- + +--------------------------------------------------------- + +System.Data.DataSetExtensions 4.6.0-preview3.19128.7 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) 2011, Google Inc. +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 1991-2017 Unicode, Inc. +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) .NET Foundation Contributors +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +System.Memory 4.5.3 - MIT + + +(c) 2008 VeriSign, Inc. +Copyright (c) 2011, Google Inc. +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 1991-2017 Unicode, Inc. +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) .NET Foundation Contributors +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +System.Runtime.CompilerServices.Unsafe 5.0.0-preview.7.20364.11 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright 2012 the V8 project +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +Copyright (c) 1998 Microsoft. To +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2018 Alexander Chermyanin +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) The Internet Society 1997. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) The Internet Society (2003). +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +System.Security.Cryptography.Pkcs 5.0.0-preview.3.20214.6 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +Copyright (c) Andrew Arnott +Copyright 2018 Daniel Lemire +Copyright 2012 the V8 project +Copyright (c) .NET Foundation. +Copyright (c) 2011, Google Inc. +Copyright (c) 1998 Microsoft. To +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2005-2007, Nick Galbreath +Portions (c) International Organization +Copyright (c) 2015 The Chromium Authors. +Copyright (c) The Internet Society 1997. +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) 2016-2017, Matthieu Darbois +Copyright (c) .NET Foundation Contributors +Copyright (c) The Internet Society (2003). +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + +--------------------------------------------------------- + +System.Security.Cryptography.ProtectedData 4.4.0 - MIT + + +(c) 2008 VeriSign, Inc. +(c) Microsoft Corporation. +(c) 1997-2005 Sean Eron Anderson. +Copyright (c) 1991-2017 Unicode, Inc. +Portions (c) International Organization +Copyright (c) 2004-2006 Intel Corporation +Copyright (c) .NET Foundation Contributors +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2011 Novell, Inc (http://www.novell.com) +Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +--------------------------------------------------------- + diff --git a/doBuild.ps1 b/doBuild.ps1 index 119f8d9a8..a23afa510 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -41,8 +41,8 @@ function DoBuild Copy-Item -Path "./LICENSE" -Dest "$BuildOutPath" # Copy notice - # Write-Verbose -Verbose -Message "Copying ThirdPartyNotices.txt to '$BuildOutPath'" - # Copy-Item -Path "./ThirdPartyNotices.txt" -Dest "$BuildOutPath" + Write-Verbose -Verbose -Message "Copying ThirdPartyNotices.txt to '$BuildOutPath'" + Copy-Item -Path "./Notice.txt" -Dest "$BuildOutPath" # # Copy DSC resources diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 6dea7f3e3..f6a3c9ccf 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.PowerShell.PowerShellGet.UtilClasses; using System; using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; using System.Linq; using System.Management.Automation; using System.Threading; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +using Dbg = System.Diagnostics.Debug; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -29,8 +30,8 @@ public sealed class FindPSResource : PSCmdlet private const string ResourceNameParameterSet = "ResourceNameParameterSet"; private const string CommandNameParameterSet = "CommandNameParameterSet"; private const string DscResourceNameParameterSet = "DscResourceNameParameterSet"; - private CancellationTokenSource _source; - private CancellationToken _cancellationToken; + private CancellationTokenSource _cancellationTokenSource; + private FindHelper _findHelper; #endregion @@ -132,17 +133,25 @@ public sealed class FindPSResource : PSCmdlet protected override void BeginProcessing() { - _source = new CancellationTokenSource(); - _cancellationToken = _source.Token; + _cancellationTokenSource = new CancellationTokenSource(); + _findHelper = new FindHelper( + cancellationToken: _cancellationTokenSource.Token, + cmdletPassedIn: this); - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // Create a repository story (the PSResourceRepository.xml file) if it does not already exist // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); } protected override void StopProcessing() { - _source.Cancel(); + _cancellationTokenSource?.Cancel(); + } + + protected override void EndProcessing() + { + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = null; } protected override void ProcessRecord() @@ -207,10 +216,9 @@ private void ProcessResourceNameParameterSet() return; } - FindHelper findHelper = new FindHelper(_cancellationToken, this); List foundPackages = new List(); - foreach (PSResourceInfo package in findHelper.FindByResourceName( + foreach (PSResourceInfo package in _findHelper.FindByResourceName( Name, Type, Version, @@ -283,10 +291,9 @@ private void ProcessCommandOrDscParameterSet(bool isSearchingForCommands) moduleNamesToSearch = new string[] {"*"}; } - FindHelper findHelper = new FindHelper(_cancellationToken, this); List foundPackages = new List(); - foreach (PSResourceInfo package in findHelper.FindByResourceName( + foreach (PSResourceInfo package in _findHelper.FindByResourceName( name: moduleNamesToSearch, // provide type so Scripts endpoint for PSGallery won't be searched type: isSearchingForCommands? ResourceType.Command : ResourceType.DscResource, diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index d92d9c7d6..d7b74640c 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -1,795 +1,808 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using MoreLinq.Extensions; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging; -using NuGet.Packaging.Core; -using NuGet.Packaging.PackageExtraction; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Net; -using System.Text.RegularExpressions; -using System.Threading; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// Install helper class - /// - internal class InstallHelper : PSCmdlet - { - #region Members - - private const string MsgRepositoryNotTrusted = "Untrusted repository"; - private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; - - private CancellationToken _cancellationToken; - private readonly bool _savePkg; - private readonly PSCmdlet _cmdletPassedIn; - private List _pathsToInstallPkg; - private VersionRange _versionRange; - private bool _prerelease; - private bool _acceptLicense; - private bool _quiet; - private bool _reinstall; - private bool _force; - private bool _trustRepository; - private PSCredential _credential; - private string _specifiedPath; - private bool _asNupkg; - private bool _includeXML; - private bool _noClobber; - List _pathsToSearch; - - #endregion - - #region Public methods - - public InstallHelper(bool savePkg, PSCmdlet cmdletPassedIn) - { - CancellationTokenSource source = new CancellationTokenSource(); - _cancellationToken = source.Token; - _savePkg = savePkg; - _cmdletPassedIn = cmdletPassedIn; - } - - public void InstallPackages( - string[] names, - VersionRange versionRange, - bool prerelease, - string[] repository, - bool acceptLicense, - bool quiet, - bool reinstall, - bool force, - bool trustRepository, - bool noClobber, - PSCredential credential, - string specifiedPath, - bool asNupkg, - bool includeXML, - List pathsToInstallPkg) - { - _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", - string.Join(",", names), - (versionRange != null ? versionRange.OriginalString : string.Empty), - prerelease.ToString(), - repository != null ? string.Join(",", repository) : string.Empty, - acceptLicense.ToString(), - quiet.ToString(), - reinstall.ToString(), - trustRepository.ToString(), - noClobber.ToString())); - - _versionRange = versionRange; - _prerelease = prerelease; - _acceptLicense = acceptLicense; - _quiet = quiet; - _reinstall = reinstall; - _force = force; - _trustRepository = trustRepository; - _noClobber = noClobber; - _credential = credential; - _specifiedPath = specifiedPath; - _asNupkg = asNupkg; - _includeXML = includeXML; - _pathsToInstallPkg = pathsToInstallPkg; - - // Create list of installation paths to search. - _pathsToSearch = new List(); - - // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) - // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations - // e.g.: - // ./InstallPackagePath1/PackageA - // ./InstallPackagePath1/PackageB - // ./InstallPackagePath2/PackageC - // ./InstallPackagePath3/PackageD - foreach (var path in _pathsToInstallPkg) - { - _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); - } - - // Go through the repositories and see which is the first repository to have the pkg version available - ProcessRepositories(names, repository, _trustRepository, _credential); - } - - #endregion - - #region Private methods - - // This method calls iterates through repositories (by priority order) to search for the pkgs to install - private void ProcessRepositories(string[] packageNames, string[] repository, bool trustRepository, PSCredential credential) - { - var listOfRepositories = RepositorySettings.Read(repository, out string[] _); - List pckgNamesToInstall = packageNames.ToList(); - var yesToAll = false; - var noToAll = false; - - var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); - foreach (var repo in listOfRepositories) - { - // If no more packages to install, then return - if (!pckgNamesToInstall.Any()) return; - - string repoName = repo.Name; - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); - - // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true - // OR the user issues trust interactively via console. - var sourceTrusted = true; - if (repo.Trusted == false && !trustRepository && !_force) - { - _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); - - if (!(yesToAll || noToAll)) - { - // Prompt for installation of package from untrusted repository - var message = string.Format(CultureInfo.InvariantCulture, MsgInstallUntrustedPackage, repoName); - sourceTrusted = _cmdletPassedIn.ShouldContinue(message, MsgRepositoryNotTrusted, true, ref yesToAll, ref noToAll); - } - } - - if (!sourceTrusted && !yesToAll) - { - continue; - } - - _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); - - // If it can't find the pkg in one repository, it'll look for it in the next repo in the list - var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); - - // Finds parent packages and dependencies - IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( - name: packageNames, - type: ResourceType.None, - version: _versionRange != null ? _versionRange.OriginalString : null, - prerelease: _prerelease, - tag: null, - repository: new string[] { repoName }, - credential: credential, - includeDependencies: true); - - if (!pkgsFromRepoToInstall.Any()) - { - _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); - // Check in the next repository - continue; - } - - // Select the first package from each name group, which is guaranteed to be the latest version. - // We should only have one version returned for each package name - // e.g.: - // PackageA (version 1.0) - // PackageB (version 2.0) - // PackageC (version 1.0) - pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( - m => new { m.Name }).Select( - group => group.First()).ToList(); - - // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) - if (!_reinstall) - { - // Removes all of the names that are already installed from the list of names to search for - pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); - } - - if (!pkgsFromRepoToInstall.Any()) - { - continue; - } - - List pkgsInstalled = InstallPackage(pkgsFromRepoToInstall, repoName, repo.Url.AbsoluteUri, credential, isLocalRepo); - - foreach (string name in pkgsInstalled) - { - pckgNamesToInstall.Remove(name); - } - } - } - - // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install - private IEnumerable FilterByInstalledPkgs(IEnumerable packages) - { - // Create list of installation paths to search. - List _pathsToSearch = new List(); - // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) - // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations - // e.g.: - // ./InstallPackagePath1/PackageA - // ./InstallPackagePath1/PackageB - // ./InstallPackagePath2/PackageC - // ./InstallPackagePath3/PackageD - foreach (var path in _pathsToInstallPkg) - { - _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); - } - - var filteredPackages = new Dictionary(); - foreach (var pkg in packages) - { - filteredPackages.Add(pkg.Name, pkg); - } - - GetHelper getHelper = new GetHelper(_cmdletPassedIn); - // Get currently installed packages. - IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( - name: filteredPackages.Keys.ToArray(), - versionRange: _versionRange, - pathsToSearch: _pathsToSearch); - if (!pkgsAlreadyInstalled.Any()) - { - return packages; - } - - // Remove from list package versions that are already installed. - foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) - { - _cmdletPassedIn.WriteWarning( - string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", - pkg.Name, - pkg.Version)); - - filteredPackages.Remove(pkg.Name); - } - - return filteredPackages.Values.ToArray(); - } - - private List InstallPackage(IEnumerable pkgsToInstall, string repoName, string repoUrl, PSCredential credential, bool isLocalRepo) - { - List pkgsSuccessfullyInstalled = new List(); - foreach (PSResourceInfo p in pkgsToInstall) - { - var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - try - { - // Create a temp directory to install to - var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly - // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator - // with a mask (bitwise complement of desired attributes combination). - // TODO: check the attributes and if it's read only then set it - // attribute may be inherited from the parent - // TODO: are there Linux accommodations we need to consider here? - dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; - - _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", p.Name)); - - // TODO: add progress bar here - - // Create PackageIdentity in order to download - string createFullVersion = p.Version.ToString(); - if (p.IsPrerelease) - { - createFullVersion = p.Version.ToString() + "-" + p.PrereleaseLabel; - } - - if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", p.Name, p.Version.ToString())); - continue; - } - var pkgIdentity = new PackageIdentity(p.Name, pkgVersion); - var cacheContext = new SourceCacheContext(); - - if (isLocalRepo) - { - /* Download from a local repository -- this is slightly different process than from a server */ - var localResource = new FindLocalPackagesResourceV2(repoUrl); - var resource = new LocalDownloadResource(repoUrl, localResource); - - // Actually downloading the .nupkg from a local repo - var result = resource.GetDownloadResourceResultAsync( - identity: pkgIdentity, - downloadContext: new PackageDownloadContext(cacheContext), - globalPackagesFolder: tempInstallPath, - logger: NullLogger.Instance, - token: _cancellationToken).GetAwaiter().GetResult(); - - if (_asNupkg) // this is Save functionality - { - DirectoryInfo nupkgPath = new DirectoryInfo(((System.IO.FileStream)result.PackageStream).Name); - File.Copy(nupkgPath.FullName, Path.Combine(tempInstallPath, pkgIdentity.Id + pkgIdentity.Version + ".nupkg")); - - continue; - } - - // Create the package extraction context - PackageExtractionContext packageExtractionContext = new PackageExtractionContext( - packageSaveMode: PackageSaveMode.Nupkg, - xmlDocFileSaveMode: PackageExtractionBehavior.XmlDocFileSaveMode, - clientPolicyContext: null, - logger: NullLogger.Instance); - - // Extracting from .nupkg and placing files into tempInstallPath - result.PackageReader.CopyFiles( - destination: tempInstallPath, - packageFiles: result.PackageReader.GetFiles(), - extractFile: (new PackageFileExtractor(result.PackageReader.GetFiles(), packageExtractionContext.XmlDocFileSaveMode)).ExtractPackageFile, - logger: NullLogger.Instance, - token: _cancellationToken); - result.Dispose(); - } - else - { - /* Download from a non-local repository */ - // Set up NuGet API resource for download - PackageSource source = new PackageSource(repoUrl); - if (credential != null) - { - string password = new NetworkCredential(string.Empty, credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, credential.UserName, password, true, null); - } - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - SourceRepository repository = new SourceRepository(source, provider); - - /* Download from a non-local repository -- ie server */ - var downloadResource = repository.GetResourceAsync().GetAwaiter().GetResult(); - DownloadResourceResult result = null; - try - { - result = downloadResource.GetDownloadResourceResultAsync( - identity: pkgIdentity, - downloadContext: new PackageDownloadContext(cacheContext), - globalPackagesFolder: tempInstallPath, - logger: NullLogger.Instance, - token: _cancellationToken).GetAwaiter().GetResult(); - } - catch (Exception e) - { - _cmdletPassedIn.WriteVerbose(string.Format("Error attempting download: '{0}'", e.Message)); - } - finally - { - // Need to close the .nupkg - if (result != null) result.Dispose(); - } - } - - _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); - - // Prompt if module requires license acceptance (need to read info license acceptance info from the module manifest) - // pkgIdentity.Version.Version gets the version without metadata or release labels. - string newVersion = pkgIdentity.Version.ToNormalizedString(); - - string normalizedVersionNoPrereleaseLabel = newVersion; - if (pkgIdentity.Version.IsPrerelease) - { - // eg: 2.0.2 - normalizedVersionNoPrereleaseLabel = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); - } - - string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); - var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); - string moduleManifestVersion = string.Empty; - var scriptPath = Path.Combine(tempDirNameVersion, (p.Name + ".ps1")); - var modulePath = Path.Combine(tempDirNameVersion, (p.Name + ".psd1")); - // Check if the package is a module or a script - var isModule = File.Exists(modulePath); - - - if (isModule) - { - var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); - if (!File.Exists(moduleManifest)) - { - var message = String.Format("Module manifest file: {0} does not exist. This is not a valid PowerShell module.", moduleManifest); - - var ex = new ArgumentException(message); - var psdataFileDoesNotExistError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); - _cmdletPassedIn.WriteError(psdataFileDoesNotExistError); - continue; - } - - if (!Utils.TryParseModuleManifest(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) - { - // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. - continue; - } - - moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; - - // Accept License verification - if (!_savePkg && !CallAcceptLicense(p, moduleManifest, tempInstallPath, newVersion)) - { - continue; - } - - // If NoClobber is specified, ensure command clobbering does not happen - if (_noClobber && !DetectClobber(p.Name, tempDirNameVersion, parsedMetadataHashtable)) - { - continue; - } - } - - // Delete the extra nupkg related files that are not needed and not part of the module/script - DeleteExtraneousFiles(tempInstallPath, pkgIdentity, tempDirNameVersion); - - string installPath; - if (_savePkg) - { - // For save the installation path is what is passed in via -Path - installPath = _pathsToInstallPkg.FirstOrDefault(); - } - else { - // PSModules: - /// ./Modules - /// ./Scripts - /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list - installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) - : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); - } - - if (_includeXML) - { - CreateMetadataXMLFile(tempDirNameVersion, installPath, repoName, p, isModule); - } - - MoveFilesIntoInstallPath(p, isModule, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); - - _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", p.Name, installPath)); - pkgsSuccessfullyInstalled.Add(p.Name); - } - catch (Exception e) - { - _cmdletPassedIn.WriteError( - new ErrorRecord( - new PSInvalidOperationException( - message: $"Unable to successfully install package '{p.Name}': '{e.Message}'", - innerException: e), - "InstallPackageFailed", - ErrorCategory.InvalidOperation, - _cmdletPassedIn)); - } - finally - { - // Delete the temp directory and all its contents - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); - - if (Directory.Exists(tempInstallPath)) - { - if (!TryDeleteDirectory(tempInstallPath, out ErrorRecord errorMsg)) - { - _cmdletPassedIn.WriteError(errorMsg); - } - else - { - _cmdletPassedIn.WriteVerbose(String.Format("Successfully deleted '{0}'", tempInstallPath)); - } - } - } - } - - return pkgsSuccessfullyInstalled; - } - - private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string tempInstallPath, string newVersion) - { - var requireLicenseAcceptance = false; - var success = true; - - if (File.Exists(moduleManifest)) - { - using (StreamReader sr = new StreamReader(moduleManifest)) - { - var text = sr.ReadToEnd(); - - var pattern = "RequireLicenseAcceptance\\s*=\\s*\\$true"; - var patternToSkip1 = "#\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; - var patternToSkip2 = "\\*\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; - - Regex rgx = new Regex(pattern); - Regex rgxComment1 = new Regex(patternToSkip1); - Regex rgxComment2 = new Regex(patternToSkip2); - if (rgx.IsMatch(text) && !rgxComment1.IsMatch(text) && !rgxComment2.IsMatch(text)) - { - requireLicenseAcceptance = true; - } - } - - // Licesnse agreement processing - if (requireLicenseAcceptance) - { - // If module requires license acceptance and -AcceptLicense is not passed in, display prompt - if (!_acceptLicense) - { - var PkgTempInstallPath = Path.Combine(tempInstallPath, p.Name, newVersion); - var LicenseFilePath = Path.Combine(PkgTempInstallPath, "License.txt"); - - if (!File.Exists(LicenseFilePath)) - { - var exMessage = "License.txt not Found. License.txt must be provided when user license acceptance is required."; - var ex = new ArgumentException(exMessage); - var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); - - _cmdletPassedIn.WriteError(acceptLicenseError); - success = false; - } - - // Otherwise read LicenseFile - string licenseText = System.IO.File.ReadAllText(LicenseFilePath); - var acceptanceLicenseQuery = $"Do you accept the license terms for module '{p.Name}'."; - var message = licenseText + "`r`n" + acceptanceLicenseQuery; - - var title = "License Acceptance"; - var yesToAll = false; - var noToAll = false; - var shouldContinueResult = _cmdletPassedIn.ShouldContinue(message, title, true, ref yesToAll, ref noToAll); - - if (shouldContinueResult || yesToAll) - { - _acceptLicense = true; - } - } - - // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install - if (!_acceptLicense) - { - var message = $"License Acceptance is required for module '{p.Name}'. Please specify '-AcceptLicense' to perform this operation."; - var ex = new ArgumentException(message); - var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); - - _cmdletPassedIn.WriteError(acceptLicenseError); - success = false; - } - } - } - - return success; - } - - private bool DetectClobber(string pkgName, string tempDirNameVersion, Hashtable parsedMetadataHashtable) - { - // Get installed modules, then get all possible paths - bool foundClobber = false; - GetHelper getHelper = new GetHelper(_cmdletPassedIn); - IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath(new string[] { "*" }, VersionRange.All, _pathsToSearch); - // user parsed metadata hash - List listOfCmdlets = new List(); - foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) - { - listOfCmdlets.Add(cmdletName as string); - - } - - foreach (var pkg in pkgsAlreadyInstalled) - { - List duplicateCmdlets = new List(); - List duplicateCmds = new List(); - // See if any of the cmdlets or commands in the pkg we're trying to install exist within a package that's already installed - if (pkg.Includes.Cmdlet != null && pkg.Includes.Cmdlet.Any()) - { - duplicateCmdlets = listOfCmdlets.Where(cmdlet => pkg.Includes.Cmdlet.Contains(cmdlet)).ToList(); - - } - if (pkg.Includes.Command != null && pkg.Includes.Command.Any()) - { - duplicateCmds = listOfCmdlets.Where(commands => pkg.Includes.Command.Contains(commands, StringComparer.InvariantCultureIgnoreCase)).ToList(); - } - if (duplicateCmdlets.Any() || duplicateCmds.Any()) - { - - duplicateCmdlets.AddRange(duplicateCmds); - - var errMessage = string.Format( - "The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", - String.Join(", ", duplicateCmdlets), pkgName); - - var ex = new ArgumentException(errMessage); - var noClobberError = new ErrorRecord(ex, "CommandAlreadyExists", ErrorCategory.ResourceExists, null); - - _cmdletPassedIn.WriteError(noClobberError); - foundClobber = true; - - return foundClobber; - } - } - - return foundClobber; - } - - private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isModule) - { - // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" - // Modules will have the metadata file: "PSGetModuleInfo.xml" - var metadataXMLPath = isModule ? Path.Combine(dirNameVersion, "PSGetModuleInfo.xml") - : Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")); - - pkg.InstalledDate = DateTime.Now; - pkg.InstalledLocation = installPath; - - // Write all metadata into metadataXMLPath - if (!pkg.TryWrite(metadataXMLPath, out string error)) - { - var message = string.Format("Error parsing metadata into XML: '{0}'", error); - var ex = new ArgumentException(message); - var ErrorParsingMetadata = new ErrorRecord(ex, "ErrorParsingMetadata", ErrorCategory.ParserError, null); - WriteError(ErrorParsingMetadata); - } - } - - private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgIdentity, string dirNameVersion) - { - // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module - var pkgIdString = pkgIdentity.ToString(); - var nupkgSHAToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.sha512")); - var nuspecToDelete = Path.Combine(dirNameVersion, (pkgIdentity.Id + ".nuspec")); - var nupkgToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg")); - var nupkgMetadataToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.metadata")); - var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); - var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); - var packageDirToDelete = Path.Combine(dirNameVersion, "package"); - - // Unforunately have to check if each file exists because it may or may not be there - if (File.Exists(nupkgSHAToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgSHAToDelete)); - File.Delete(nupkgSHAToDelete); - } - if (File.Exists(nuspecToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nuspecToDelete)); - File.Delete(nuspecToDelete); - } - if (File.Exists(nupkgToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgToDelete)); - File.Delete(nupkgToDelete); - } - if (File.Exists(nupkgMetadataToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgMetadataToDelete)); - File.Delete(nupkgMetadataToDelete); - } - if (File.Exists(contentTypesToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", contentTypesToDelete)); - File.Delete(contentTypesToDelete); - } - if (Directory.Exists(relsDirToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", relsDirToDelete)); - Directory.Delete(relsDirToDelete, true); - } - if (Directory.Exists(packageDirToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", packageDirToDelete)); - Directory.Delete(packageDirToDelete, true); - } - } - - private bool TryDeleteDirectory( - string tempInstallPath, - out ErrorRecord errorMsg) - { - errorMsg = null; - - try - { - Utils.DeleteDirectory(tempInstallPath); - } - catch (Exception e) - { - var TempDirCouldNotBeDeletedError = new ErrorRecord(e, "errorDeletingTempInstallPath", ErrorCategory.InvalidResult, null); - errorMsg = TempDirCouldNotBeDeletedError; - return false; - } - - return true; - } - - private void MoveFilesIntoInstallPath( - PSResourceInfo p, - bool isModule, - bool isLocalRepo, - string dirNameVersion, - string tempInstallPath, - string installPath, - string newVersion, - string moduleManifestVersion, - string nupkgVersion, - string versionWithoutPrereleaseTag, - string scriptPath) - { - // Creating the proper installation path depending on whether pkg is a module or script - var newPathParent = isModule ? Path.Combine(installPath, p.Name) : installPath; - var finalModuleVersionDir = isModule ? Path.Combine(installPath, p.Name, moduleManifestVersion) : installPath; // versionWithoutPrereleaseTag - - // If script, just move the files over, if module, move the version directory over - var tempModuleVersionDir = (!isModule || isLocalRepo) ? dirNameVersion - : Path.Combine(tempInstallPath, p.Name.ToLower(), newVersion); - - _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); - _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); - - if (isModule) - { - // If new path does not exist - if (!Directory.Exists(newPathParent)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Directory.CreateDirectory(newPathParent); - Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); - } - else - { - _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); - - if (Directory.Exists(finalModuleVersionDir)) - { - // Delete the directory path before replacing it with the new module. - // If deletion fails (usually due to binary file in use), then attempt restore so that the currently - // installed module is not corrupted. - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete with restore on failure.'{0}'", finalModuleVersionDir)); - Utils.DeleteDirectoryWithRestore(finalModuleVersionDir); - } - - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); - } - } - else { - if (!_savePkg) - { - // Need to delete old xml files because there can only be 1 per script - var scriptXML = p.Name + "_InstalledScriptInfo.xml"; - _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); - if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting script metadata XML")); - File.Delete(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); - } - - _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); - Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); - - // Need to delete old script file, if that exists - _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); - if (File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); - File.Delete(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); - } - } - - _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); - Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); - } - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using MoreLinq.Extensions; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.Packaging.PackageExtraction; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Install helper class + /// + internal class InstallHelper : PSCmdlet + { + #region Members + + private const string MsgRepositoryNotTrusted = "Untrusted repository"; + private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; + + private CancellationToken _cancellationToken; + private readonly bool _savePkg; + private readonly PSCmdlet _cmdletPassedIn; + private List _pathsToInstallPkg; + private VersionRange _versionRange; + private bool _prerelease; + private bool _acceptLicense; + private bool _quiet; + private bool _reinstall; + private bool _force; + private bool _trustRepository; + private PSCredential _credential; + private string _specifiedPath; + private bool _asNupkg; + private bool _includeXML; + private bool _noClobber; + List _pathsToSearch; + + #endregion + + #region Public methods + + public InstallHelper(bool savePkg, PSCmdlet cmdletPassedIn) + { + CancellationTokenSource source = new CancellationTokenSource(); + _cancellationToken = source.Token; + _savePkg = savePkg; + _cmdletPassedIn = cmdletPassedIn; + } + + public void InstallPackages( + string[] names, + VersionRange versionRange, + bool prerelease, + string[] repository, + bool acceptLicense, + bool quiet, + bool reinstall, + bool force, + bool trustRepository, + bool noClobber, + PSCredential credential, + string specifiedPath, + bool asNupkg, + bool includeXML, + List pathsToInstallPkg) + { + _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", + string.Join(",", names), + versionRange != null ? versionRange.OriginalString : string.Empty, + prerelease.ToString(), + repository != null ? string.Join(",", repository) : string.Empty, + acceptLicense.ToString(), + quiet.ToString(), + reinstall.ToString(), + trustRepository.ToString(), + noClobber.ToString())); + + _versionRange = versionRange; + _prerelease = prerelease; + _acceptLicense = acceptLicense || force; + _quiet = quiet; + _reinstall = reinstall; + _force = force; + _trustRepository = trustRepository || force; + _noClobber = noClobber; + _credential = credential; + _specifiedPath = specifiedPath; + _asNupkg = asNupkg; + _includeXML = includeXML; + _pathsToInstallPkg = pathsToInstallPkg; + + // Create list of installation paths to search. + _pathsToSearch = new List(); + + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // e.g.: + // ./InstallPackagePath1/PackageA + // ./InstallPackagePath1/PackageB + // ./InstallPackagePath2/PackageC + // ./InstallPackagePath3/PackageD + foreach (var path in _pathsToInstallPkg) + { + _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); + } + + // Go through the repositories and see which is the first repository to have the pkg version available + ProcessRepositories(names, repository, _trustRepository, _credential); + } + + #endregion + + #region Private methods + + // This method calls iterates through repositories (by priority order) to search for the pkgs to install + private void ProcessRepositories( + string[] packageNames, + string[] repository, + bool trustRepository, + PSCredential credential) + { + var listOfRepositories = RepositorySettings.Read(repository, out string[] _); + List pckgNamesToInstall = packageNames.ToList(); + var yesToAll = false; + var noToAll = false; + + var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); + foreach (var repo in listOfRepositories) + { + // If no more packages to install, then return + if (!pckgNamesToInstall.Any()) return; + + string repoName = repo.Name; + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); + + // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true + // OR the user issues trust interactively via console. + var sourceTrusted = true; + if (repo.Trusted == false && !trustRepository && !_force) + { + _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); + + if (!(yesToAll || noToAll)) + { + // Prompt for installation of package from untrusted repository + var message = string.Format(CultureInfo.InvariantCulture, MsgInstallUntrustedPackage, repoName); + sourceTrusted = _cmdletPassedIn.ShouldContinue(message, MsgRepositoryNotTrusted, true, ref yesToAll, ref noToAll); + } + } + + if (!sourceTrusted && !yesToAll) + { + continue; + } + + _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); + + // If it can't find the pkg in one repository, it'll look for it in the next repo in the list + var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); + + // Finds parent packages and dependencies + IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( + name: pckgNamesToInstall.ToArray(), + type: ResourceType.None, + version: _versionRange != null ? _versionRange.OriginalString : null, + prerelease: _prerelease, + tag: null, + repository: new string[] { repoName }, + credential: credential, + includeDependencies: true); + + if (!pkgsFromRepoToInstall.Any()) + { + _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); + // Check in the next repository + continue; + } + + // Select the first package from each name group, which is guaranteed to be the latest version. + // We should only have one version returned for each package name + // e.g.: + // PackageA (version 1.0) + // PackageB (version 2.0) + // PackageC (version 1.0) + pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( + m => new { m.Name }).Select( + group => group.First()).ToList(); + + // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) + if (!_reinstall) + { + // Removes all of the names that are already installed from the list of names to search for + pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); + } + + if (!pkgsFromRepoToInstall.Any()) + { + continue; + } + + List pkgsInstalled = InstallPackage( + pkgsFromRepoToInstall, + repoName, + repo.Url.AbsoluteUri, + credential, + isLocalRepo); + + foreach (string name in pkgsInstalled) + { + pckgNamesToInstall.Remove(name); + } + } + } + + // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install + private IEnumerable FilterByInstalledPkgs(IEnumerable packages) + { + // Create list of installation paths to search. + List _pathsToSearch = new List(); + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // e.g.: + // ./InstallPackagePath1/PackageA + // ./InstallPackagePath1/PackageB + // ./InstallPackagePath2/PackageC + // ./InstallPackagePath3/PackageD + foreach (var path in _pathsToInstallPkg) + { + _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); + } + + var filteredPackages = new Dictionary(); + foreach (var pkg in packages) + { + filteredPackages.Add(pkg.Name, pkg); + } + + GetHelper getHelper = new GetHelper(_cmdletPassedIn); + // Get currently installed packages. + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( + name: filteredPackages.Keys.ToArray(), + versionRange: _versionRange, + pathsToSearch: _pathsToSearch); + if (!pkgsAlreadyInstalled.Any()) + { + return packages; + } + + // Remove from list package versions that are already installed. + foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) + { + _cmdletPassedIn.WriteWarning( + string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", + pkg.Name, + pkg.Version)); + + filteredPackages.Remove(pkg.Name); + } + + return filteredPackages.Values.ToArray(); + } + + private List InstallPackage( + IEnumerable pkgsToInstall, + string repoName, + string repoUrl, + PSCredential credential, + bool isLocalRepo) + { + List pkgsSuccessfullyInstalled = new List(); + foreach (PSResourceInfo p in pkgsToInstall) + { + var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + try + { + // Create a temp directory to install to + var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly + // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator + // with a mask (bitwise complement of desired attributes combination). + // TODO: check the attributes and if it's read only then set it + // attribute may be inherited from the parent + // TODO: are there Linux accommodations we need to consider here? + dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; + + _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", p.Name)); + + // TODO: add progress bar here + + // Create PackageIdentity in order to download + string createFullVersion = p.Version.ToString(); + if (p.IsPrerelease) + { + createFullVersion = p.Version.ToString() + "-" + p.PrereleaseLabel; + } + + if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", p.Name, p.Version.ToString())); + continue; + } + var pkgIdentity = new PackageIdentity(p.Name, pkgVersion); + var cacheContext = new SourceCacheContext(); + + if (isLocalRepo) + { + /* Download from a local repository -- this is slightly different process than from a server */ + var localResource = new FindLocalPackagesResourceV2(repoUrl); + var resource = new LocalDownloadResource(repoUrl, localResource); + + // Actually downloading the .nupkg from a local repo + var result = resource.GetDownloadResourceResultAsync( + identity: pkgIdentity, + downloadContext: new PackageDownloadContext(cacheContext), + globalPackagesFolder: tempInstallPath, + logger: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + + if (_asNupkg) // this is Save functionality + { + DirectoryInfo nupkgPath = new DirectoryInfo(((System.IO.FileStream)result.PackageStream).Name); + File.Copy(nupkgPath.FullName, Path.Combine(tempInstallPath, pkgIdentity.Id + pkgIdentity.Version + ".nupkg")); + + continue; + } + + // Create the package extraction context + PackageExtractionContext packageExtractionContext = new PackageExtractionContext( + packageSaveMode: PackageSaveMode.Nupkg, + xmlDocFileSaveMode: PackageExtractionBehavior.XmlDocFileSaveMode, + clientPolicyContext: null, + logger: NullLogger.Instance); + + // Extracting from .nupkg and placing files into tempInstallPath + result.PackageReader.CopyFiles( + destination: tempInstallPath, + packageFiles: result.PackageReader.GetFiles(), + extractFile: (new PackageFileExtractor(result.PackageReader.GetFiles(), packageExtractionContext.XmlDocFileSaveMode)).ExtractPackageFile, + logger: NullLogger.Instance, + token: _cancellationToken); + result.Dispose(); + } + else + { + /* Download from a non-local repository */ + // Set up NuGet API resource for download + PackageSource source = new PackageSource(repoUrl); + if (credential != null) + { + string password = new NetworkCredential(string.Empty, credential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, credential.UserName, password, true, null); + } + var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); + SourceRepository repository = new SourceRepository(source, provider); + + /* Download from a non-local repository -- ie server */ + var downloadResource = repository.GetResourceAsync().GetAwaiter().GetResult(); + DownloadResourceResult result = null; + try + { + result = downloadResource.GetDownloadResourceResultAsync( + identity: pkgIdentity, + downloadContext: new PackageDownloadContext(cacheContext), + globalPackagesFolder: tempInstallPath, + logger: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + } + catch (Exception e) + { + _cmdletPassedIn.WriteVerbose(string.Format("Error attempting download: '{0}'", e.Message)); + } + finally + { + // Need to close the .nupkg + if (result != null) result.Dispose(); + } + } + + _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); + + // Prompt if module requires license acceptance (need to read info license acceptance info from the module manifest) + // pkgIdentity.Version.Version gets the version without metadata or release labels. + string newVersion = pkgIdentity.Version.ToNormalizedString(); + + string normalizedVersionNoPrereleaseLabel = newVersion; + if (pkgIdentity.Version.IsPrerelease) + { + // eg: 2.0.2 + normalizedVersionNoPrereleaseLabel = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); + } + + string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); + var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); + string moduleManifestVersion = string.Empty; + var scriptPath = Path.Combine(tempDirNameVersion, (p.Name + ".ps1")); + var modulePath = Path.Combine(tempDirNameVersion, (p.Name + ".psd1")); + // Check if the package is a module or a script + var isModule = File.Exists(modulePath); + + if (isModule) + { + var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); + if (!File.Exists(moduleManifest)) + { + var message = String.Format("Module manifest file: {0} does not exist. This is not a valid PowerShell module.", moduleManifest); + + var ex = new ArgumentException(message); + var psdataFileDoesNotExistError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); + _cmdletPassedIn.WriteError(psdataFileDoesNotExistError); + continue; + } + + if (!Utils.TryParseModuleManifest(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) + { + // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. + continue; + } + + moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; + + // Accept License verification + if (!_savePkg && !CallAcceptLicense(p, moduleManifest, tempInstallPath, newVersion)) + { + continue; + } + + // If NoClobber is specified, ensure command clobbering does not happen + if (_noClobber && !DetectClobber(p.Name, tempDirNameVersion, parsedMetadataHashtable)) + { + continue; + } + } + + // Delete the extra nupkg related files that are not needed and not part of the module/script + DeleteExtraneousFiles(tempInstallPath, pkgIdentity, tempDirNameVersion); + + string installPath; + if (_savePkg) + { + // For save the installation path is what is passed in via -Path + installPath = _pathsToInstallPkg.FirstOrDefault(); + } + else { + // PSModules: + /// ./Modules + /// ./Scripts + /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list + installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) + : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); + } + + if (_includeXML) + { + CreateMetadataXMLFile(tempDirNameVersion, installPath, repoName, p, isModule); + } + + MoveFilesIntoInstallPath(p, isModule, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); + + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", p.Name, installPath)); + pkgsSuccessfullyInstalled.Add(p.Name); + } + catch (Exception e) + { + _cmdletPassedIn.WriteError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Unable to successfully install package '{p.Name}': '{e.Message}'", + innerException: e), + "InstallPackageFailed", + ErrorCategory.InvalidOperation, + _cmdletPassedIn)); + } + finally + { + // Delete the temp directory and all its contents + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); + + if (Directory.Exists(tempInstallPath)) + { + if (!TryDeleteDirectory(tempInstallPath, out ErrorRecord errorMsg)) + { + _cmdletPassedIn.WriteError(errorMsg); + } + else + { + _cmdletPassedIn.WriteVerbose(String.Format("Successfully deleted '{0}'", tempInstallPath)); + } + } + } + } + + return pkgsSuccessfullyInstalled; + } + + private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string tempInstallPath, string newVersion) + { + var requireLicenseAcceptance = false; + var success = true; + + if (File.Exists(moduleManifest)) + { + using (StreamReader sr = new StreamReader(moduleManifest)) + { + var text = sr.ReadToEnd(); + + var pattern = "RequireLicenseAcceptance\\s*=\\s*\\$true"; + var patternToSkip1 = "#\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; + var patternToSkip2 = "\\*\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; + + Regex rgx = new Regex(pattern); + Regex rgxComment1 = new Regex(patternToSkip1); + Regex rgxComment2 = new Regex(patternToSkip2); + if (rgx.IsMatch(text) && !rgxComment1.IsMatch(text) && !rgxComment2.IsMatch(text)) + { + requireLicenseAcceptance = true; + } + } + + // Licesnse agreement processing + if (requireLicenseAcceptance) + { + // If module requires license acceptance and -AcceptLicense is not passed in, display prompt + if (!_acceptLicense) + { + var PkgTempInstallPath = Path.Combine(tempInstallPath, p.Name, newVersion); + var LicenseFilePath = Path.Combine(PkgTempInstallPath, "License.txt"); + + if (!File.Exists(LicenseFilePath)) + { + var exMessage = "License.txt not Found. License.txt must be provided when user license acceptance is required."; + var ex = new ArgumentException(exMessage); + var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); + + _cmdletPassedIn.WriteError(acceptLicenseError); + success = false; + } + + // Otherwise read LicenseFile + string licenseText = System.IO.File.ReadAllText(LicenseFilePath); + var acceptanceLicenseQuery = $"Do you accept the license terms for module '{p.Name}'."; + var message = licenseText + "`r`n" + acceptanceLicenseQuery; + + var title = "License Acceptance"; + var yesToAll = false; + var noToAll = false; + var shouldContinueResult = _cmdletPassedIn.ShouldContinue(message, title, true, ref yesToAll, ref noToAll); + + if (shouldContinueResult || yesToAll) + { + _acceptLicense = true; + } + } + + // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install + if (!_acceptLicense) + { + var message = $"License Acceptance is required for module '{p.Name}'. Please specify '-AcceptLicense' to perform this operation."; + var ex = new ArgumentException(message); + var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); + + _cmdletPassedIn.WriteError(acceptLicenseError); + success = false; + } + } + } + + return success; + } + + private bool DetectClobber(string pkgName, string tempDirNameVersion, Hashtable parsedMetadataHashtable) + { + // Get installed modules, then get all possible paths + bool foundClobber = false; + GetHelper getHelper = new GetHelper(_cmdletPassedIn); + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath(new string[] { "*" }, VersionRange.All, _pathsToSearch); + // user parsed metadata hash + List listOfCmdlets = new List(); + foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) + { + listOfCmdlets.Add(cmdletName as string); + + } + + foreach (var pkg in pkgsAlreadyInstalled) + { + List duplicateCmdlets = new List(); + List duplicateCmds = new List(); + // See if any of the cmdlets or commands in the pkg we're trying to install exist within a package that's already installed + if (pkg.Includes.Cmdlet != null && pkg.Includes.Cmdlet.Any()) + { + duplicateCmdlets = listOfCmdlets.Where(cmdlet => pkg.Includes.Cmdlet.Contains(cmdlet)).ToList(); + + } + if (pkg.Includes.Command != null && pkg.Includes.Command.Any()) + { + duplicateCmds = listOfCmdlets.Where(commands => pkg.Includes.Command.Contains(commands, StringComparer.InvariantCultureIgnoreCase)).ToList(); + } + if (duplicateCmdlets.Any() || duplicateCmds.Any()) + { + + duplicateCmdlets.AddRange(duplicateCmds); + + var errMessage = string.Format( + "The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", + String.Join(", ", duplicateCmdlets), pkgName); + + var ex = new ArgumentException(errMessage); + var noClobberError = new ErrorRecord(ex, "CommandAlreadyExists", ErrorCategory.ResourceExists, null); + + _cmdletPassedIn.WriteError(noClobberError); + foundClobber = true; + + return foundClobber; + } + } + + return foundClobber; + } + + private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isModule) + { + // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" + // Modules will have the metadata file: "PSGetModuleInfo.xml" + var metadataXMLPath = isModule ? Path.Combine(dirNameVersion, "PSGetModuleInfo.xml") + : Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")); + + pkg.InstalledDate = DateTime.Now; + pkg.InstalledLocation = installPath; + + // Write all metadata into metadataXMLPath + if (!pkg.TryWrite(metadataXMLPath, out string error)) + { + var message = string.Format("Error parsing metadata into XML: '{0}'", error); + var ex = new ArgumentException(message); + var ErrorParsingMetadata = new ErrorRecord(ex, "ErrorParsingMetadata", ErrorCategory.ParserError, null); + WriteError(ErrorParsingMetadata); + } + } + + private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgIdentity, string dirNameVersion) + { + // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module + var pkgIdString = pkgIdentity.ToString(); + var nupkgSHAToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.sha512")); + var nuspecToDelete = Path.Combine(dirNameVersion, (pkgIdentity.Id + ".nuspec")); + var nupkgToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg")); + var nupkgMetadataToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.metadata")); + var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); + var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); + var packageDirToDelete = Path.Combine(dirNameVersion, "package"); + + // Unforunately have to check if each file exists because it may or may not be there + if (File.Exists(nupkgSHAToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgSHAToDelete)); + File.Delete(nupkgSHAToDelete); + } + if (File.Exists(nuspecToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nuspecToDelete)); + File.Delete(nuspecToDelete); + } + if (File.Exists(nupkgToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgToDelete)); + File.Delete(nupkgToDelete); + } + if (File.Exists(nupkgMetadataToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgMetadataToDelete)); + File.Delete(nupkgMetadataToDelete); + } + if (File.Exists(contentTypesToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", contentTypesToDelete)); + File.Delete(contentTypesToDelete); + } + if (Directory.Exists(relsDirToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", relsDirToDelete)); + Directory.Delete(relsDirToDelete, true); + } + if (Directory.Exists(packageDirToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", packageDirToDelete)); + Directory.Delete(packageDirToDelete, true); + } + } + + private bool TryDeleteDirectory( + string tempInstallPath, + out ErrorRecord errorMsg) + { + errorMsg = null; + + try + { + Utils.DeleteDirectory(tempInstallPath); + } + catch (Exception e) + { + var TempDirCouldNotBeDeletedError = new ErrorRecord(e, "errorDeletingTempInstallPath", ErrorCategory.InvalidResult, null); + errorMsg = TempDirCouldNotBeDeletedError; + return false; + } + + return true; + } + + private void MoveFilesIntoInstallPath( + PSResourceInfo p, + bool isModule, + bool isLocalRepo, + string dirNameVersion, + string tempInstallPath, + string installPath, + string newVersion, + string moduleManifestVersion, + string nupkgVersion, + string versionWithoutPrereleaseTag, + string scriptPath) + { + // Creating the proper installation path depending on whether pkg is a module or script + var newPathParent = isModule ? Path.Combine(installPath, p.Name) : installPath; + var finalModuleVersionDir = isModule ? Path.Combine(installPath, p.Name, moduleManifestVersion) : installPath; // versionWithoutPrereleaseTag + + // If script, just move the files over, if module, move the version directory over + var tempModuleVersionDir = (!isModule || isLocalRepo) ? dirNameVersion + : Path.Combine(tempInstallPath, p.Name.ToLower(), newVersion); + + _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); + + if (isModule) + { + // If new path does not exist + if (!Directory.Exists(newPathParent)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Directory.CreateDirectory(newPathParent); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); + } + else + { + _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); + + if (Directory.Exists(finalModuleVersionDir)) + { + // Delete the directory path before replacing it with the new module. + // If deletion fails (usually due to binary file in use), then attempt restore so that the currently + // installed module is not corrupted. + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete with restore on failure.'{0}'", finalModuleVersionDir)); + Utils.DeleteDirectoryWithRestore(finalModuleVersionDir); + } + + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); + } + } + else { + if (!_savePkg) + { + // Need to delete old xml files because there can only be 1 per script + var scriptXML = p.Name + "_InstalledScriptInfo.xml"; + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); + if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting script metadata XML")); + File.Delete(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + } + + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); + Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + + // Need to delete old script file, if that exists + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); + if (File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); + File.Delete(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + } + } + + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); + Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + } + } + + #endregion + } +} diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index ea5e6812c..d08c42efd 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -1,253 +1,258 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -using System; -using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; -using System.Management.Automation; -using System.Threading; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Install-PSResource cmdlet installs a resource. - /// It returns nothing. - /// - - [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] - public sealed - class InstallPSResource : PSCmdlet - { - #region Parameters - - /// - /// Specifies the exact names of resources to install from a repository. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] - [ValidateNotNullOrEmpty] - public string[] Name { get; set; } - - /// - /// Specifies the version or version range of the package to be installed - /// - [Parameter(ParameterSetName = NameParameterSet)] - [ValidateNotNullOrEmpty] - public string Version { get; set; } - - /// - /// Specifies to allow installation of prerelease versions - /// - [Parameter(ParameterSetName = NameParameterSet)] - public SwitchParameter Prerelease { get; set; } - - /// - /// Specifies the repositories from which to search for the resource to be installed. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string[] Repository { get; set; } - - /// - /// Specifies a user account that has rights to find a resource from a specific repository. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public PSCredential Credential { get; set; } - - /// - /// Specifies the scope of installation. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public ScopeType Scope { get; set; } - - /// - /// Suppresses being prompted for untrusted sources. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter TrustRepository { get; set; } - - /// - /// Overwrites a previously installed resource with the same name and version. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter Reinstall { get; set; } - - /// - /// Suppresses progress information. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter Quiet { get; set; } - - /// - /// For modules that require a license, AcceptLicense automatically accepts the license agreement during installation. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter AcceptLicense { get; set; } - - /// - /// Prevents installing a package that contains cmdlets that already exist on the machine. - /// - [Parameter(ParameterSetName = NameParameterSet)] - public SwitchParameter NoClobber { get; set; } - - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] - [ValidateNotNullOrEmpty] - public PSResourceInfo InputObject { get; set; } - - #endregion - - #region Members - - private const string NameParameterSet = "NameParameterSet"; - private const string InputObjectParameterSet = "InputObjectParameterSet"; - private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet"; - private const string RequiredResourceParameterSet = "RequiredResourceParameterSet"; - List _pathsToInstallPkg; - VersionRange _versionRange; - - #endregion - - #region Method overrides - - protected override void BeginProcessing() - { - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly - RepositorySettings.CheckRepositoryStore(); - - _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); - } - - protected override void ProcessRecord() - { - var installHelper = new InstallHelper(savePkg: false, cmdletPassedIn: this); - switch (ParameterSetName) - { - case NameParameterSet: - // If no Version specified, install latest version for the package. - // Otherwise validate Version can be parsed out successfully. - if (Version == null) - { - _versionRange = VersionRange.All; - } - else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) - { - var exMessage = "Argument for -Version parameter is not in the proper format."; - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - ProcessInstallHelper(installHelper: installHelper, - pkgNames: Name, - pkgPrerelease: Prerelease, - pkgRepository: Repository); - break; - - case InputObjectParameterSet: - string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); - if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) - { - var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); - var ex = new ArgumentException(exMessage); - var ErrorParsingVersion = new ErrorRecord(ex, "ErrorParsingVersion", ErrorCategory.ParserError, null); - WriteError(ErrorParsingVersion); - } - - ProcessInstallHelper(installHelper: installHelper, - pkgNames: new string[] { InputObject.Name }, - pkgPrerelease: InputObject.IsPrerelease, - pkgRepository: new string[]{ InputObject.Repository }); - break; - - case RequiredResourceFileParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("RequiredResourceFileParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "CommandParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); - break; - - case RequiredResourceParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("RequiredResourceParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "CommandParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); - break; - - default: - Dbg.Assert(false, "Invalid parameter set"); - break; - } - } - - #endregion - - #region Methods - private void ProcessInstallHelper(InstallHelper installHelper, string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) - { - var inputNameToInstall = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); - if (nameContainsWildcard) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Name with wildcards is not supported for Install-PSResource cmdlet"), - "NameContainsWildcard", - ErrorCategory.InvalidArgument, - this)); - return; - } - - foreach (string error in errorMsgs) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); - } - - // 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 namesToInstall - if (inputNameToInstall.Length == 0) - { - return; - } - - if (!ShouldProcess(string.Format("package to install: '{0}'", String.Join(", ", inputNameToInstall)))) - { - WriteVerbose(string.Format("Install operation cancelled by user for packages: {0}", String.Join(", ", inputNameToInstall))); - return; - } - - installHelper.InstallPackages( - names: pkgNames, - versionRange: _versionRange, - prerelease: pkgPrerelease, - repository: pkgRepository, - acceptLicense: AcceptLicense, - quiet: Quiet, - reinstall: Reinstall, - force: false, - trustRepository: TrustRepository, - noClobber: NoClobber, - credential: Credential, - specifiedPath: null, - asNupkg: false, - includeXML: true, - pathsToInstallPkg: _pathsToInstallPkg); - } - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; +using System; +using System.Collections.Generic; +using System.Management.Automation; + +using Dbg = System.Diagnostics.Debug; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Install-PSResource cmdlet installs a resource. + /// It returns nothing. + /// + + [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] + public sealed + class InstallPSResource : PSCmdlet + { + #region Parameters + + /// + /// Specifies the exact names of resources to install from a repository. + /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies the version or version range of the package to be installed + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// Specifies to allow installation of prerelease versions + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies the repositories from which to search for the resource to be installed. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies a user account that has rights to find a resource from a specific repository. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public PSCredential Credential { get; set; } + + /// + /// Specifies the scope of installation. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public ScopeType Scope { get; set; } + + /// + /// Suppresses being prompted for untrusted sources. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Overwrites a previously installed resource with the same name and version. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter Reinstall { get; set; } + + /// + /// Suppresses progress information. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter Quiet { get; set; } + + /// + /// For modules that require a license, AcceptLicense automatically accepts the license agreement during installation. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter AcceptLicense { get; set; } + + /// + /// Prevents installing a package that contains cmdlets that already exist on the machine. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter NoClobber { get; set; } + + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public PSResourceInfo InputObject { get; set; } + + #endregion + + #region Members + + private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectParameterSet = "InputObjectParameterSet"; + private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet"; + private const string RequiredResourceParameterSet = "RequiredResourceParameterSet"; + List _pathsToInstallPkg; + VersionRange _versionRange; + InstallHelper _installHelper; + + #endregion + + #region Method overrides + + protected override void BeginProcessing() + { + // Create a repository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); + + _installHelper = new InstallHelper(savePkg: false, cmdletPassedIn: this); + } + + protected override void ProcessRecord() + { + switch (ParameterSetName) + { + case NameParameterSet: + // If no Version specified, install latest version for the package. + // Otherwise validate Version can be parsed out successfully. + if (Version == null) + { + _versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + ProcessInstallHelper( + pkgNames: Name, + pkgPrerelease: Prerelease, + pkgRepository: Repository); + break; + + case InputObjectParameterSet: + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) + { + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); + var ex = new ArgumentException(exMessage); + var ErrorParsingVersion = new ErrorRecord(ex, "ErrorParsingVersion", ErrorCategory.ParserError, null); + WriteError(ErrorParsingVersion); + } + + ProcessInstallHelper( + pkgNames: new string[] { InputObject.Name }, + pkgPrerelease: InputObject.IsPrerelease, + pkgRepository: new string[]{ InputObject.Repository }); + break; + + case RequiredResourceFileParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("RequiredResourceFileParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "CommandParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + case RequiredResourceParameterSet: + ThrowTerminatingError(new ErrorRecord( + new PSNotImplementedException("RequiredResourceParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), + "CommandParameterSetNotImplementedYet", + ErrorCategory.NotImplemented, + this)); + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + } + + #endregion + + #region Methods + + private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) + { + var inputNameToInstall = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Install-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToInstall + if (inputNameToInstall.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("package to install: '{0}'", String.Join(", ", inputNameToInstall)))) + { + WriteVerbose(string.Format("Install operation cancelled by user for packages: {0}", String.Join(", ", inputNameToInstall))); + return; + } + + _installHelper.InstallPackages( + names: pkgNames, + versionRange: _versionRange, + prerelease: pkgPrerelease, + repository: pkgRepository, + acceptLicense: AcceptLicense, + quiet: Quiet, + reinstall: Reinstall, + force: false, + trustRepository: TrustRepository, + noClobber: NoClobber, + credential: Credential, + specifiedPath: null, + asNupkg: false, + includeXML: true, + pathsToInstallPkg: _pathsToInstallPkg); + } + + #endregion + } +} diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 5449333af..9c8b292f7 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -1,247 +1,252 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -using System; -using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Threading; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Save-PSResource cmdlet saves a resource to a machine. - /// It returns nothing. - /// - [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] - public sealed class SavePSResource : PSCmdlet - { - #region Members - - private const string NameParameterSet = "NameParameterSet"; - private const string InputObjectParameterSet = "InputObjectParameterSet"; - VersionRange _versionRange; - - #endregion - - #region Parameters - - /// - /// Specifies the exact names of resources to save from a repository. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] - [ValidateNotNullOrEmpty] - public string[] Name { get; set; } - - /// - /// Specifies the version or version range of the package to be saved - /// - [Parameter(ParameterSetName = NameParameterSet)] - [ValidateNotNullOrEmpty] - public string Version { get; set; } - - /// - /// Specifies to allow saveing of prerelease versions - /// - [Parameter(ParameterSetName = NameParameterSet)] - public SwitchParameter Prerelease { get; set; } - - /// - /// Specifies the specific repositories to search within. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string[] Repository { get; set; } - - /// - /// Specifies a user account that has rights to save a resource from a specific repository. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public PSCredential Credential { get; set; } - - /* - /// - /// Saves as a .nupkg - /// - [Parameter()] - public SwitchParameter AsNupkg { get; set; } - - /// - /// Saves the metadata XML file with the resource - /// - [Parameter()] - public SwitchParameter IncludeXML { get; set; } - */ - - /// - /// The destination where the resource is to be installed. Works for all resource types. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - [ValidateNotNullOrEmpty] - public string Path - { - get - { return _path; } - - set - { - string resolvedPath = string.Empty; - if (!string.IsNullOrEmpty(value)) - { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } - - // Path where resource is saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _path = resolvedPath; - } - } - } - private string _path; - - /// - /// Suppresses being prompted for untrusted sources. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter TrustRepository { get; set; } - - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] - [ValidateNotNullOrEmpty] - public PSResourceInfo InputObject { get; set; } - - #endregion - - #region Method overrides - - protected override void BeginProcessing() - { - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly - RepositorySettings.CheckRepositoryStore(); - - // If the user does not specify a path to save to, use the user's current working directory - if (string.IsNullOrWhiteSpace(_path)) - { - _path = SessionState.Path.CurrentLocation.Path; - } - } - - protected override void ProcessRecord() - { - var installHelper = new InstallHelper(savePkg: true, cmdletPassedIn: this); - switch (ParameterSetName) - { - case NameParameterSet: - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. - // an exact version will be formatted into a version range. - if (Version == null) - { - _versionRange = VersionRange.All; - } - else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) - { - var exMessage = "Argument for -Version parameter is not in the proper format."; - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - ProcessSaveHelper(installHelper: installHelper, - pkgNames: Name, - pkgPrerelease: Prerelease, - pkgRepository: Repository); - break; - - case InputObjectParameterSet: - string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); - if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) - { - var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - ProcessSaveHelper(installHelper: installHelper, - pkgNames: new string[] { InputObject.Name }, - pkgPrerelease: InputObject.IsPrerelease, - pkgRepository: new string[] { InputObject.Repository }); - - break; - - default: - Dbg.Assert(false, "Invalid parameter set"); - break; - } - } - - #endregion - - #region Methods - private void ProcessSaveHelper(InstallHelper installHelper, string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) - { - var namesToSave = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); - if (nameContainsWildcard) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), - "NameContainsWildcard", - ErrorCategory.InvalidArgument, - this)); - return; - } - - foreach (string error in errorMsgs) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); - } - - // 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 namesToSave - if (namesToSave.Length == 0) - { - return; - } - - if (!ShouldProcess(string.Format("Resources to save: '{0}'", namesToSave))) - { - WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", namesToSave)); - return; - } - - installHelper.InstallPackages( - names: namesToSave, - versionRange: _versionRange, - prerelease: pkgPrerelease, - repository: pkgRepository, - acceptLicense: true, - quiet: true, - reinstall: true, - force: false, - trustRepository: TrustRepository, - credential: Credential, - noClobber: false, - specifiedPath: _path, - asNupkg: false, - includeXML: false, - pathsToInstallPkg: new List { _path } ); - } - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Management.Automation; + +using Dbg = System.Diagnostics.Debug; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Save-PSResource cmdlet saves a resource to a machine. + /// It returns nothing. + /// + [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] + public sealed class SavePSResource : PSCmdlet + { + #region Members + + private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectParameterSet = "InputObjectParameterSet"; + VersionRange _versionRange; + InstallHelper _installHelper; + + #endregion + + #region Parameters + + /// + /// Specifies the exact names of resources to save from a repository. + /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies the version or version range of the package to be saved + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// Specifies to allow saveing of prerelease versions + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies the specific repositories to search within. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies a user account that has rights to save a resource from a specific repository. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public PSCredential Credential { get; set; } + + /* + /// + /// Saves as a .nupkg + /// + [Parameter()] + public SwitchParameter AsNupkg { get; set; } + + /// + /// Saves the metadata XML file with the resource + /// + [Parameter()] + public SwitchParameter IncludeXML { get; set; } + */ + + /// + /// The destination where the resource is to be installed. Works for all resource types. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public string Path + { + get + { return _path; } + + set + { + string resolvedPath = string.Empty; + if (!string.IsNullOrEmpty(value)) + { + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + } + + // Path where resource is saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _path = resolvedPath; + } + } + } + private string _path; + + /// + /// Suppresses being prompted for untrusted sources. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public PSResourceInfo InputObject { get; set; } + + #endregion + + #region Method overrides + + protected override void BeginProcessing() + { + // Create a repository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + + // If the user does not specify a path to save to, use the user's current working directory + if (string.IsNullOrWhiteSpace(_path)) + { + _path = SessionState.Path.CurrentLocation.Path; + } + + _installHelper = new InstallHelper(savePkg: true, cmdletPassedIn: this); + } + + protected override void ProcessRecord() + { + switch (ParameterSetName) + { + case NameParameterSet: + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (Version == null) + { + _versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + ProcessSaveHelper( + pkgNames: Name, + pkgPrerelease: Prerelease, + pkgRepository: Repository); + break; + + case InputObjectParameterSet: + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) + { + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + ProcessSaveHelper( + pkgNames: new string[] { InputObject.Name }, + pkgPrerelease: InputObject.IsPrerelease, + pkgRepository: new string[] { InputObject.Repository }); + + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + } + + #endregion + + #region Methods + + private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) + { + var namesToSave = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToSave + if (namesToSave.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("Resources to save: '{0}'", namesToSave))) + { + WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", namesToSave)); + return; + } + + _installHelper.InstallPackages( + names: namesToSave, + versionRange: _versionRange, + prerelease: pkgPrerelease, + repository: pkgRepository, + acceptLicense: true, + quiet: true, + reinstall: true, + force: false, + trustRepository: TrustRepository, + credential: Credential, + noClobber: false, + specifiedPath: _path, + asNupkg: false, + includeXML: false, + pathsToInstallPkg: new List { _path } ); + } + + #endregion + } +} diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 7158bc4c6..90fcb0ea0 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Threading; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -23,6 +24,9 @@ public sealed class UpdatePSResource : PSCmdlet { #region Members private List _pathsToInstallPkg; + private CancellationTokenSource _cancellationTokenSource; + private FindHelper _findHelper; + private InstallHelper _installHelper; #endregion @@ -65,7 +69,7 @@ public sealed class UpdatePSResource : PSCmdlet public ScopeType Scope { get; set; } /// - /// When specified, supresses being prompted for untrusted sources. + /// When specified, suppresses prompting for untrusted sources. /// [Parameter] public SwitchParameter TrustRepository { get; set; } @@ -77,7 +81,7 @@ public sealed class UpdatePSResource : PSCmdlet public PSCredential Credential { get; set; } /// - /// Supresses progress information. + /// Suppresses progress information. /// [Parameter] public SwitchParameter Quiet { get; set; } @@ -100,11 +104,20 @@ public sealed class UpdatePSResource : PSCmdlet protected override void BeginProcessing() { - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist + // Create a repository story (the PSResourceRepository.xml file) if it does not already exist // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); + + _cancellationTokenSource = new CancellationTokenSource(); + _findHelper = new FindHelper( + cancellationToken: _cancellationTokenSource.Token, + cmdletPassedIn: this); + + _installHelper = new InstallHelper( + savePkg: false, + cmdletPassedIn: this); } protected override void ProcessRecord() @@ -126,7 +139,7 @@ protected override void ProcessRecord() return; } - var namesToUpdate = ProcessPackageNameWildCards(Name, versionRange); + var namesToUpdate = ProcessPackageNames(Name, versionRange); if (namesToUpdate.Length == 0) { @@ -139,11 +152,7 @@ protected override void ProcessRecord() return; } - InstallHelper installHelper = new InstallHelper( - savePkg: false, - cmdletPassedIn: this); - - installHelper.InstallPackages( + _installHelper.InstallPackages( names: namesToUpdate, versionRange: versionRange, prerelease: Prerelease, @@ -161,17 +170,38 @@ protected override void ProcessRecord() pathsToInstallPkg: _pathsToInstallPkg); } + protected override void StopProcessing() + { + _cancellationTokenSource?.Cancel(); + } + + protected override void EndProcessing() + { + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = null; + } + #endregion #region Private Methods /// - /// This method checks all provided package names for wild card characters and removes any name containing invalid characters. - /// If any name contains a single '*' wildcard character then it is returned alone, indicating all packages should be processed. + /// This method performs a number of functions on the list of resource package names to update. + /// - Processes the name list for wild card characters. + /// - Writes errors for names with unsupported wild characters. + /// - Finds installed packages that match the names list. + /// - Finds repository packages that match the names list and update version. + /// - Compares installed packages and repository search results with name list. + /// - Returns a final list of packages for reinstall, that meet update criteria. /// - private string[] ProcessPackageNameWildCards(string[] namesToProcess, VersionRange versionRange) + private string[] ProcessPackageNames( + string[] namesToProcess, + VersionRange versionRange) { - namesToProcess = Utils.ProcessNameWildcards(namesToProcess, out string[] errorMsgs, out bool nameContainsWildcard); + namesToProcess = Utils.ProcessNameWildcards( + pkgNames: namesToProcess, + errorMsgs: out string[] errorMsgs, + isContainWildcard: out bool _); foreach (string error in errorMsgs) { @@ -182,11 +212,11 @@ private string[] ProcessPackageNameWildCards(string[] namesToProcess, VersionRan this)); } - // this catches the case where namesToProcess wasn't passed in as null or empty, - // but after filtering out unsupported wildcard names there are no elements left in namesToProcess + // This catches the case where namesToProcess wasn't passed in as null or empty, + // but after filtering out unsupported wildcard names there are no elements left in namesToProcess. if (namesToProcess.Length == 0) { - return namesToProcess; + return Utils.EmptyStrArray; } if (String.Equals(namesToProcess[0], "*", StringComparison.InvariantCultureIgnoreCase)) @@ -194,23 +224,92 @@ private string[] ProcessPackageNameWildCards(string[] namesToProcess, VersionRan WriteVerbose("Package names were detected to be (or contain an element equal to): '*', so all packages will be updated"); } - if (nameContainsWildcard) + // Get all installed packages selected for updating. + GetHelper getHelper = new GetHelper(cmdletPassedIn: this); + var installedPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (var installedPackage in getHelper.GetPackagesFromPath( + name: namesToProcess, + versionRange: VersionRange.All, + pathsToSearch: Utils.GetAllResourcePaths(this, Scope))) { - // if any of the namesToProcess entries contains a supported wildcard - // then we need to use GetHelper (Get-InstalledPSResource logic) to find which packages are installed that match - // the wildcard pattern name for each package name with wildcard + if (!installedPackages.ContainsKey(installedPackage.Name)) + { + installedPackages.Add(installedPackage.Name, installedPackage); + } + } + + if (installedPackages.Count is 0) + { + WriteWarning($"No installed packages were found with name '{string.Join(",", namesToProcess)}' in scope '{Scope}'. First install package using 'Install-PSResource'."); + return Utils.EmptyStrArray; + } + + // Find all packages selected for updating in provided repositories. + var repositoryPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (var foundResource in _findHelper.FindByResourceName( + name: installedPackages.Keys.ToArray(), + type: ResourceType.None, + version: Version, + prerelease: Prerelease, + tag: null, + repository: Repository, + credential: Credential, + includeDependencies: false)) + { + if (!repositoryPackages.ContainsKey(foundResource.Name)) + { + repositoryPackages.Add(foundResource.Name, foundResource); + } + } - GetHelper getHelper = new GetHelper( - cmdletPassedIn: this); + // Check if named package is installed or can be found in the repositories. + foreach (var nameToProcess in namesToProcess) + { + if (!WildcardPattern.ContainsWildcardCharacters(nameToProcess)) + { + if (!installedPackages.ContainsKey(nameToProcess)) + { + WriteWarning( + $"Package '{nameToProcess}' not installed in scope '{Scope}'. First install package using 'Install-PSResource'."); + } + else if (!repositoryPackages.ContainsKey(nameToProcess)) + { + WriteWarning( + $"Installed package '{nameToProcess}':'{Version}' was not found in repositories and cannot be updated."); + } + } + } - namesToProcess = getHelper.GetPackagesFromPath( - name: namesToProcess, - versionRange: versionRange, - pathsToSearch: Utils.GetAllResourcePaths(this)).Select(p => p.Name).ToArray(); + // Create list of packages to update. + List namesToUpdate = new List(); + foreach (PSResourceInfo repositoryPackage in repositoryPackages.Values) + { + if (!installedPackages.TryGetValue(repositoryPackage.Name, out PSResourceInfo installedPackage)) + { + continue; + } + + // If the current package is out of range, install it with the correct version. + if (!NuGetVersion.TryParse(installedPackage.Version.ToString(), out NuGetVersion installedVersion)) + { + WriteWarning($"Cannot parse nuget version in installed package '{installedPackage.Name}'. Cannot update package."); + continue; + } + + if ((versionRange == VersionRange.All && repositoryPackage.Version > installedPackage.Version) || + !versionRange.Satisfies(installedVersion)) + { + namesToUpdate.Add(repositoryPackage.Name); + } + else + { + WriteVerbose($"Installed package {repositoryPackage.Name} is up to date."); + } } - return namesToProcess; + return namesToUpdate.ToArray(); } + #endregion } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 1c034124a..55b222571 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -320,27 +320,41 @@ public static string GetInstalledPackageName(string pkgPath) } } - public static List GetAllResourcePaths(PSCmdlet psCmdlet) + public static List GetAllResourcePaths( + PSCmdlet psCmdlet, + ScopeType? scope = null) { GetStandardPlatformPaths( psCmdlet, out string myDocumentsPath, out string programFilesPath); - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - List resourcePaths = psModulePath.Split(';').ToList(); - List pathsToSearch = new List(); + List resourcePaths = new List(); + + // Path search order is PSModulePath paths first, then default paths. + if (scope is null) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + resourcePaths.AddRange(psModulePath.Split(';').ToList()); + } - // will search first in PSModulePath, then will search in default paths - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); + if (scope is null || scope.Value is ScopeType.CurrentUser) + { + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); + } + + if (scope is null || scope.Value is ScopeType.AllUsers) + { + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); + } // resourcePaths should now contain, eg: // ./PowerShell/Scripts // ./PowerShell/Modules // add all module directories or script files + List pathsToSearch = new List(); foreach (string path in resourcePaths) { psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); From 85cb1629b419cd6ecc209d0959e7977fced3237c Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 9 Nov 2021 08:12:52 -0800 Subject: [PATCH 095/276] Fix Publish-PSResource -DestinationPath test failure (#537) --- src/code/PublishPSResource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index af2b5c690..d43babfef 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -393,7 +393,7 @@ protected override void ProcessRecord() try { var nupkgName = _pkgName + "." + _pkgVersion.ToNormalizedString() + ".nupkg"; - Utils.MoveFiles(System.IO.Path.Combine(outputNupkgDir, nupkgName), System.IO.Path.Combine(_destinationPath, nupkgName)); + File.Copy(System.IO.Path.Combine(outputNupkgDir, nupkgName), System.IO.Path.Combine(_destinationPath, nupkgName)); } catch (Exception e) { var message = string.Format("Error moving .nupkg into destination path '{0}' due to: '{1}'.", _destinationPath, e.Message); From 4632fa59f32110e743910a3ac05c5f8f669cbfee Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 9 Nov 2021 15:23:49 -0800 Subject: [PATCH 096/276] Fix clobber tests (#539) --- test/InstallPSResource.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 9e5f56fd7..01a85f1db 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -16,7 +16,8 @@ Describe 'Test Install-PSResource for Module' { AfterEach { Uninstall-PSResource "TestModule", "TestModule99", "myTestModule", "myTestModule2", "testModulePrerelease", - "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule" -Force -ErrorAction SilentlyContinue + "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule","ClobberTestModule1", + "ClobberTestModule2" -Force -ErrorAction SilentlyContinue } AfterAll { From 8d1a5fafff5846bd1a3007e1c75f507a42723583 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:56:37 -0800 Subject: [PATCH 097/276] Uri bug fix (#542) --- src/code/RegisterPSResourceRepository.cs | 8 +-- src/code/SetPSResourceRepository.cs | 4 +- src/code/Utils.cs | 56 ++++++++++----------- test/RegisterPSResourceRepository.Tests.ps1 | 10 +++- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 678c6fb95..11cb8a861 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -126,9 +126,9 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: - if (!Utils.TryCreateValidUrl(urlString: URL, + if (!Utils.TryCreateValidUrl(uriString: URL, cmdletPassedIn: this, - urlResult: out _url, + uriResult: out _url, errorRecord: out ErrorRecord errorRecord)) { ThrowTerminatingError(errorRecord); @@ -312,9 +312,9 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } - if (!Utils.TryCreateValidUrl(urlString: repo["Url"].ToString(), + if (!Utils.TryCreateValidUrl(uriString: repo["Url"].ToString(), cmdletPassedIn: this, - urlResult: out Uri repoURL, + uriResult: out Uri repoURL, errorRecord: out ErrorRecord errorRecord)) { WriteError(errorRecord); diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index d74507f6b..49ed8d272 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -234,9 +234,9 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } - if (!Utils.TryCreateValidUrl(urlString: repo["Url"].ToString(), + if (!Utils.TryCreateValidUrl(uriString: repo["Url"].ToString(), cmdletPassedIn: this, - urlResult: out repoURL, + uriResult: out repoURL, errorRecord: out ErrorRecord errorRecord)) { WriteError(errorRecord); diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 55b222571..d2cf24b03 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -113,7 +113,7 @@ public static string[] ProcessNameWildcards( } #endregion - + #region Version methods public static string GetNormalizedVersionString( @@ -228,48 +228,44 @@ public static bool GetVersionForInstallPath( #region Url methods public static bool TryCreateValidUrl( - string urlString, + string uriString, PSCmdlet cmdletPassedIn, - out Uri urlResult, + out Uri uriResult, out ErrorRecord errorRecord ) { errorRecord = null; - - if (!urlString.StartsWith(Uri.UriSchemeHttps) && - !urlString.StartsWith(Uri.UriSchemeHttp) && - !urlString.StartsWith(Uri.UriSchemeFtp)) + if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) { - // url string could be of type (potentially) UriSchemeFile or invalid type - // can't check for UriSchemeFile because relative paths don't qualify as UriSchemeFile - try - { - // this is needed for a relative path urlstring. Does not throw error for an absolute path - urlString = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(urlString)[0].Path; + return true; + } - } - catch (Exception) + Exception ex; + try + { + // This is needed for a relative path urlstring. Does not throw error for an absolute path + var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; + if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) { - // this should only be reached if the url string is invalid - // i.e www.google.com - var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0} and must be of Uri Scheme: HTTP, HTTPS, FTP or File", urlString); - var ex = new ArgumentException(message); - errorRecord = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); - urlResult = null; - return false; + return true; } - } - bool tryCreateResult = Uri.TryCreate(urlString, UriKind.Absolute, out urlResult); - if (!tryCreateResult) + ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); + } + catch (Exception e) { - var message = string.Format(CultureInfo.InvariantCulture, "The URL provided is not valid: {0}", urlString); - var ex = new ArgumentException(message); - errorRecord = new ErrorRecord(ex, "InvalidUrl", ErrorCategory.InvalidArgument, null); - urlResult = null; + ex = e; } - return tryCreateResult; + errorRecord = new ErrorRecord( + new PSArgumentException( + $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", + ex), + "InvalidUri", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; } #endregion diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index fd4204774..c8c1a659f 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -195,7 +195,7 @@ Describe "Test Register-PSResourceRepository" { $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = "PSGallery"; URL = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, @{Type = "-URL not specified"; IncorrectHashTable = @{Name = "testRepository"}; ErrorId = "NullURLForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = "testRepository"; URL="www.google.com"}; ErrorId = "InvalidUrl,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = "testRepository"; URL="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { param($Type, $IncorrectHashTable, $ErrorId) @@ -230,4 +230,12 @@ Describe "Test Register-PSResourceRepository" { $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } + + It "should register local file share NuGet based repository" { + Register-PSResourceRepository -Name "localFileShareTestRepo" -URL "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + $res = Get-PSResourceRepository -Name "localFileShareTestRepo" + + $res.Name | Should -Be "localFileShareTestRepo" + $res.URL.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + } } From 0868c912b5070558c17e956a86b9c696d99edf80 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 10 Nov 2021 16:37:08 -0800 Subject: [PATCH 098/276] Use Utils.DeleteDirectory consistently (#544) --- src/code/InstallHelper.cs | 4 ++-- src/code/PublishPSResource.cs | 2 +- src/code/UninstallPSResource.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index d7b74640c..a3d8a4846 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -695,12 +695,12 @@ private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgId if (Directory.Exists(relsDirToDelete)) { _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", relsDirToDelete)); - Directory.Delete(relsDirToDelete, true); + Utils.DeleteDirectory(relsDirToDelete); } if (Directory.Exists(packageDirToDelete)) { _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", packageDirToDelete)); - Directory.Delete(packageDirToDelete, true); + Utils.DeleteDirectory(packageDirToDelete); } } diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index d43babfef..4286bab86 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -413,7 +413,7 @@ protected override void ProcessRecord() } finally { WriteVerbose(string.Format("Deleting temporary directory '{0}'", outputDir)); - Directory.Delete(outputDir, recursive:true); + Utils.DeleteDirectory(outputDir); } } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 7964c0deb..1b627a3d4 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -227,7 +227,7 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco { if (Utils.GetSubDirectories(dir.Parent.FullName).Length == 0) { - Directory.Delete(dir.Parent.FullName, true); + Utils.DeleteDirectory(dir.Parent.FullName); } } catch (Exception e) { From 74c45e56cfc8353844e1ff7084774c0a1bd007c1 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:12:53 -0800 Subject: [PATCH 099/276] Change all instances of 'Get-InstalledPSResource' to 'Get-PSResource' (#545) --- Docs/GetPSResource.md | 4 +-- ...stalledPSResource.md => Get-PSResource.md} | 16 +++++----- help/Update-PSResource.md | 4 +-- help/en-US/PowerShellGet.dll-Help.xml | 2 +- src/PowerShellGet.psd1 | 4 +-- src/code/GetHelper.cs | 2 +- ...nstalledPSResource.cs => GetPSResource.cs} | 6 ++-- test/GetInstalledPSResource.Tests.ps1 | 22 +++++++------- test/InstallPSResource.Tests.ps1 | 12 ++++---- test/UninstallPSResource.Tests.ps1 | 16 +++++----- test/UpdatePSResource.Tests.ps1 | 30 +++++++++---------- 11 files changed, 59 insertions(+), 59 deletions(-) rename help/{Get-InstalledPSResource.md => Get-PSResource.md} (78%) rename src/code/{GetInstalledPSResource.cs => GetPSResource.cs} (94%) diff --git a/Docs/GetPSResource.md b/Docs/GetPSResource.md index 98414aec6..fcaf0212f 100644 --- a/Docs/GetPSResource.md +++ b/Docs/GetPSResource.md @@ -1,6 +1,6 @@ -# Get-InstalledPSResource +# Get-PSResource -The `Get-InstalledPSResource` cmdlet combines the `Get-InstalledModule, Get-InstalledScript` cmdlets from V2. +The `Get-PSResource` cmdlet combines the `Get-InstalledModule, Get-InstalledScript` cmdlets from V2. It performs a search within module or script installation paths based on the `-Name` parameter argument. It returns `PSRepositoryItemInfo` objects which describe each resource item found. Other parameters allow the returned results to be filtered by version, prerelease version, and path. diff --git a/help/Get-InstalledPSResource.md b/help/Get-PSResource.md similarity index 78% rename from help/Get-InstalledPSResource.md rename to help/Get-PSResource.md index 0b1d784bd..e04f58b50 100644 --- a/help/Get-InstalledPSResource.md +++ b/help/Get-PSResource.md @@ -5,7 +5,7 @@ online version: schema: 2.0.0 --- -# Get-InstalledPSResource +# Get-PSResource ## SYNOPSIS Returns resources (modules and scripts) installed on the machine via PowerShellGet. @@ -13,45 +13,45 @@ Returns resources (modules and scripts) installed on the machine via PowerShellG ## SYNTAX ``` -Get-InstalledPSResource [[-Name] ] [-Version ] [-Path ] [] +Get-PSResource [[-Name] ] [-Version ] [-Path ] [] ``` ## DESCRIPTION -The Get-InstalledPSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. +The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. ## EXAMPLES ### Example 1 ```powershell -PS C:\> Get-InstalledPSResource Az +PS C:\> Get-PSResource Az ``` This will return versions of the Az module installed via PowerShellGet. ### Example 2 ```powershell -PS C:\> Get-InstalledPSResource Az -version "1.0.0" +PS C:\> Get-PSResource Az -version "1.0.0" ``` This will return version 1.0.0 of the Az module. ### Example 3 ```powershell -PS C:\> Get-InstalledPSResource Az -version "(1.0.0, 3.0.0)" +PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" ``` This will return all versions of the Az module within the specified range. ### Example 4 ```powershell -PS C:\> Get-InstalledPSResource Az -Path . +PS C:\> Get-PSResource Az -Path . ``` This will return all versions of the Az module that have been installed in the current directory. ### Example 5 ```powershell -PS C:\> Get-InstalledPSResource +PS C:\> Get-PSResource ``` This will return all versions and scripts installed on the machine. diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 238abfb6e..77723f3b4 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -27,14 +27,14 @@ It does not return an object. Other parameters allow the package to be updated t ### Example 1 ```powershell -PS C:\> Get-InstalledPSResource -Name "TestModule" +PS C:\> Update-PSResource -Name "TestModule" Name Version Prerelease Description ---- ------- ---------- ----------- TestModule 1.2.0 test PS C:\> Update-PSResource -Name "TestModule" -PS C:\> Get-InstalledPSResource -Name "TestModule" +PS C:\> Update-PSResource -Name "TestModule" Name Version Prerelease Description ---- ------- ---------- ----------- TestModule 1.3.0 test diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 89cd50ebe..5e215e596 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -353,7 +353,7 @@ - Get-InstalledPSResource + Get-PSResource Get PSResource diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 90ef61a52..4df94c15f 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -15,7 +15,7 @@ FormatsToProcess = 'PSGet.Format.ps1xml' CmdletsToExport = @( 'Find-PSResource', - 'Get-InstalledPSResource', + 'Get-PSResource', 'Get-PSResourceRepository', 'Install-PSResource', 'Register-PSResourceRepository', @@ -63,7 +63,7 @@ All tests have been reviewed and rewritten as needed. - Install-PSResource no longer creates version folder with the prerelease tag - Update-PSResource can now update all resources, and no longer requires name param - Save-PSResource properly handles saving scripts -- Get-InstalledPSResource uses default PowerShell paths +- Get-PSResource uses default PowerShell paths '@ } } diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 11d31813e..bdcdfba39 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { /// - /// Get helper class provides the core functionality for Get-InstalledPSResource. + /// Get helper class provides the core functionality for Get-PSResource. /// internal class GetHelper { diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetPSResource.cs similarity index 94% rename from src/code/GetInstalledPSResource.cs rename to src/code/GetPSResource.cs index 612940dc1..ab24dec78 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetPSResource.cs @@ -13,8 +13,8 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// It retrieves a resource that was installed with Install-PSResource /// Returns a single resource or multiple resource. /// - [Cmdlet(VerbsCommon.Get, "InstalledPSResource")] - public sealed class GetInstalledPSResource : PSCmdlet + [Cmdlet(VerbsCommon.Get, "PSResource")] + public sealed class GetPSResource : PSCmdlet { #region Members @@ -108,7 +108,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - WriteVerbose("Entering GetInstalledPSResource"); + WriteVerbose("Entering GetPSResource"); var namesToSearch = Utils.ProcessNameWildcards(Name, out string[] errorMsgs, out bool _); foreach (string error in errorMsgs) diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 95b51406d..523f83908 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -3,7 +3,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force -Describe 'Test Get-InstalledPSResource for Module' { +Describe 'Test Get-PSResource for Module' { BeforeAll{ $TestGalleryName = Get-PoshTestGalleryName @@ -23,17 +23,17 @@ Describe 'Test Get-InstalledPSResource for Module' { } It "Get resources without any parameter values" { - $pkgs = Get-InstalledPSResource + $pkgs = Get-PSResource $pkgs.Count | Should -BeGreaterThan 1 } It "Get specific module resource by name" { - $pkg = Get-InstalledPSResource -Name ContosoServer + $pkg = Get-PSResource -Name ContosoServer $pkg.Name | Should -Contain "ContosoServer" } It "Get specific script resource by name" { - $pkg = Get-InstalledPSResource -Name TestTestScript + $pkg = Get-PSResource -Name TestTestScript $pkg.Name | Should -Be "TestTestScript" } @@ -44,7 +44,7 @@ Describe 'Test Get-InstalledPSResource for Module' { @{Name="Cont*erver"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard in middle of name: Cont*erver"} ) { param($Version, $ExpectedVersion) - $pkgs = Get-InstalledPSResource -Name $Name + $pkgs = Get-PSResource -Name $Name $pkgs.Name | Should -Contain "ContosoServer" } @@ -61,7 +61,7 @@ $testCases = It "Get resource when given Name to " -TestCases $testCases { param($Version, $ExpectedVersion) - $pkgs = Get-InstalledPSResource -Name "ContosoServer" -Version $Version + $pkgs = Get-PSResource -Name "ContosoServer" -Version $Version $pkgs.Name | Should -Contain "ContosoServer" $pkgs.Version | Should -Be $ExpectedVersion } @@ -105,15 +105,15 @@ $testCases = } It "Get resources when given Name, and Version is '*'" { - $pkgs = Get-InstalledPSResource -Name ContosoServer -Version "*" + $pkgs = Get-PSResource -Name ContosoServer -Version "*" $pkgs.Count | Should -BeGreaterOrEqual 2 } It "Get prerelease version module when version with correct prerelease label is specified" { Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5" + $res = Get-PSResource -Name $testModuleName -Version "5.2.5" $res | Should -BeNullOrEmpty - $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res = Get-PSResource -Name $testModuleName -Version "5.2.5-alpha001" $res.Name | Should -Be $testModuleName $res.Version | Should -Be "5.2.5" $res.PrereleaseLabel | Should -Be "alpha001" @@ -121,9 +121,9 @@ $testCases = It "Get prerelease version script when version with correct prerelease label is specified" { Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0" + $res = Get-PSResource -Name $testScriptName -Version "3.0.0" $res | Should -BeNullOrEmpty - $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res = Get-PSResource -Name $testScriptName -Version "3.0.0-alpha001" $res.Name | Should -Be $testScriptName $res.Version | Should -Be "3.0.0" $res.PrereleaseLabel | Should -Be "alpha001" diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 01a85f1db..45d12d99f 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -44,7 +44,7 @@ Describe 'Test Install-PSResource for Module' { It "Install specific script resource by name" { Install-PSResource -Name "TestTestScript" -Repository $TestGalleryName - $pkg = Get-InstalledPSResource "TestTestScript" + $pkg = Get-PSResource "TestTestScript" $pkg.Name | Should -Be "TestTestScript" $pkg.Version | Should -Be "1.3.1.0" } @@ -225,7 +225,7 @@ Describe 'Test Install-PSResource for Module' { It "Install resource that requires accept license with -AcceptLicense flag" { Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName -AcceptLicense - $pkg = Get-InstalledPSResource "testModuleWithlicense" + $pkg = Get-PSResource "testModuleWithlicense" $pkg.Name | Should -Be "testModuleWithlicense" $pkg.Version | Should -Be "0.0.3.0" } @@ -243,12 +243,12 @@ Describe 'Test Install-PSResource for Module' { It "Install resource with cmdlet names from a module already installed (should clobber)" { Install-PSResource -Name "myTestModule" -Repository $TestGalleryName - $pkg = Get-InstalledPSResource "myTestModule" + $pkg = Get-PSResource "myTestModule" $pkg.Name | Should -Be "myTestModule" $pkg.Version | Should -Be "0.0.3.0" Install-PSResource -Name "myTestModule2" -Repository $TestGalleryName - $pkg = Get-InstalledPSResource "myTestModule2" + $pkg = Get-PSResource "myTestModule2" $pkg.Name | Should -Be "myTestModule2" $pkg.Version | Should -Be "0.0.1.0" } @@ -291,7 +291,7 @@ Describe 'Test Install-PSResource for Module' { } It "Install PSResourceInfo object piped in" { Find-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName | Install-PSResource - $res = Get-InstalledPSResource -Name $testModuleName + $res = Get-PSResource -Name $testModuleName $res.Name | Should -Be $testModuleName $res.Version | Should -Be "1.1.0.0" } @@ -328,7 +328,7 @@ Describe 'Test Install-PSResource for interactive and root user scenarios' { # This needs to be manually tested due to prompt It "Install resource that requires accept license without -AcceptLicense flag" { Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName - $pkg = Get-InstalledPSResource "testModuleWithlicense" + $pkg = Get-PSResource "testModuleWithlicense" $pkg.Name | Should -Be "testModuleWithlicense" $pkg.Version | Should -Be "0.0.1.0" } diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 225623dcf..c5b23a9c7 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -141,14 +141,14 @@ Describe 'Test Uninstall-PSResource for Modules' { It "Uninstall prerelease version module when prerelease version specified" { Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" - $res = Get-InstalledPSResource $testModuleName -Version "5.2.5-alpha001" + $res = Get-PSResource $testModuleName -Version "5.2.5-alpha001" $res | Should -BeNullOrEmpty } It "Not uninstall non-prerelease version module when similar prerelease version is specified" { Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $TestGalleryName Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" - $res = Get-InstalledPSResource -Name $testModuleName -Version "5.0.0.0" + $res = Get-PSResource -Name $testModuleName -Version "5.0.0.0" $res.Name | Should -Be $testModuleName $res.Version | Should -Be "5.0.0.0" } @@ -156,14 +156,14 @@ Describe 'Test Uninstall-PSResource for Modules' { It "Uninstall prerelease version script when prerelease version specified" { Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha001" - $res = Get-InstalledPSResource -Name $testScriptName + $res = Get-PSResource -Name $testScriptName $res | Should -BeNullOrEmpty } It "Not uninstall non-prerelease version module when prerelease version specified" { Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $TestGalleryName Uninstall-PSResource -Name $testScriptName -Version "2.5.0-alpha001" - $res = Get-InstalledPSResource -Name $testScriptName -Version "2.5.0.0" + $res = Get-PSResource -Name $testScriptName -Version "2.5.0.0" $res.Name | Should -Be $testScriptName $res.Version | Should -Be "2.5.0.0" } @@ -197,15 +197,15 @@ Describe 'Test Uninstall-PSResource for Modules' { It "Uninstall PSResourceInfo object piped in" { Install-PSResource -Name "ContosoServer" -Version "1.5.0.0" -Repository $TestGalleryName - Get-InstalledPSResource -Name "ContosoServer" -Version "1.5.0.0" | Uninstall-PSResource - $res = Get-InstalledPSResource -Name "ContosoServer" -Version "1.5.0.0" + Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" | Uninstall-PSResource + $res = Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" $res | Should -BeNullOrEmpty } It "Uninstall PSResourceInfo object piped in for prerelease version object" { Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource - $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" + Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource + $res = Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" $res | Should -BeNullOrEmpty } } diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 834823bbe..ee6b7c0cc 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -25,7 +25,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -44,7 +44,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule99" -Version "0.0.4.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule*" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule*" + $res = Get-PSResource -Name "TestModule*" $inputHashtable = @{TestModule = "1.1.0.0"; TestModule99 = "0.0.4.0"} $isTestModuleUpdated = $false @@ -72,7 +72,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) { @@ -102,7 +102,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" foreach ($item in $res) { $item.Name | Should -Be "TestModule" @@ -120,7 +120,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) { @@ -138,7 +138,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "PSGetTestModule" -Version "1.0.2.0" -Repository $TestGalleryName Update-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "PSGetTestModule" + $res = Get-PSResource -Name "PSGetTestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -161,7 +161,7 @@ Describe 'Test Update-PSResource' { Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -Scope CurrentUser - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -183,7 +183,7 @@ Describe 'Test Update-PSResource' { Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -Scope AllUsers - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) { @@ -202,7 +202,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -226,7 +226,7 @@ Describe 'Test Update-PSResource' { Update-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -250,7 +250,7 @@ Describe 'Test Update-PSResource' { Update-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -274,7 +274,7 @@ Describe 'Test Update-PSResource' { Update-PSResource -Name "TestModule" -Repository $TestGalleryName - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -292,7 +292,7 @@ Describe 'Test Update-PSResource' { It "update resource that requires accept license with -AcceptLicense flag" { Install-PSResource -Name "TestModuleWithLicense" -Version "0.0.1.0" -Repository $TestGalleryName -AcceptLicense Update-PSResource -Name "TestModuleWithLicense" -Repository $TestGalleryName -AcceptLicense - $res = Get-InstalledPSResource "TestModuleWithLicense" + $res = Get-PSResource "TestModuleWithLicense" $isPkgUpdated = $false foreach ($pkg in $res) @@ -312,7 +312,7 @@ Describe 'Test Update-PSResource' { Set-PSResourceRepository PoshTestGallery -Trusted:$false Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -TrustRepository - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) @@ -331,7 +331,7 @@ Describe 'Test Update-PSResource' { Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule" -WhatIf - $res = Get-InstalledPSResource -Name "TestModule" + $res = Get-PSResource -Name "TestModule" $isPkgUpdated = $false foreach ($pkg in $res) From 7efcaa503008ef19b4cfb67bf5f27cd247e40a78 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 15 Nov 2021 08:38:25 -0800 Subject: [PATCH 100/276] Code clean up pass (#547) --- src/code/ArgumentCompleter.cs | 3 +- src/code/GetHelper.cs | 3 +- src/code/GetPSResourceRepository.cs | 11 +- src/code/InstallHelper.cs | 89 +++++++------ src/code/NuGetLogger.cs | 16 ++- src/code/PSRepositoryInfo.cs | 1 + src/code/PublishPSResource.cs | 146 ++++++++------------- src/code/RegisterPSResourceRepository.cs | 1 + src/code/RepositorySettings.cs | 25 +++- src/code/SavePSResource.cs | 2 +- src/code/SetPSResourceRepository.cs | 12 +- src/code/UninstallPSResource.cs | 33 +++-- src/code/UnregisterPSResourceRepository.cs | 2 +- src/code/UpdatePSResource.cs | 1 - src/code/Utils.cs | 15 +-- 15 files changed, 187 insertions(+), 173 deletions(-) diff --git a/src/code/ArgumentCompleter.cs b/src/code/ArgumentCompleter.cs index 1afd903df..7862dad74 100644 --- a/src/code/ArgumentCompleter.cs +++ b/src/code/ArgumentCompleter.cs @@ -1,5 +1,4 @@ -using System.ComponentModel; -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Microsoft.PowerShell.PowerShellGet.UtilClasses; diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index bdcdfba39..d9784cdd9 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -9,7 +9,6 @@ using System.Management.Automation; using Dbg = System.Diagnostics.Debug; -using static Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -196,7 +195,7 @@ public PSResourceInfo OutputPackageObject(string pkgPath, Dictionary - - [Cmdlet(VerbsCommon.Get, - "PSResourceRepository")] - public sealed - class GetPSResourceRepository : PSCmdlet + [Cmdlet(VerbsCommon.Get, "PSResourceRepository")] + public sealed class GetPSResourceRepository : PSCmdlet { #region Parameters @@ -40,9 +37,11 @@ protected override void BeginProcessing() { RepositorySettings.CheckRepositoryStore(); } + protected override void ProcessRecord() { - string nameArrayAsString = (Name == null || !Name.Any() || string.Equals(Name[0], "*") || Name[0] == null) ? "all" : string.Join(", ", Name); + string nameArrayAsString = (Name == null || !Name.Any() || string.Equals(Name[0], "*") || Name[0] == null) + ? "all" : string.Join(", ", Name); WriteVerbose(String.Format("reading repository: {0}. Calling Read() API now", nameArrayAsString)); List items = RepositorySettings.Read(Name, out string[] errorList); diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index a3d8a4846..a08011eff 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -286,7 +286,7 @@ private List InstallPackage( bool isLocalRepo) { List pkgsSuccessfullyInstalled = new List(); - foreach (PSResourceInfo p in pkgsToInstall) + foreach (PSResourceInfo pkgInfo in pkgsToInstall) { var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try @@ -300,23 +300,24 @@ private List InstallPackage( // TODO: are there Linux accommodations we need to consider here? dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; - _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", p.Name)); + _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkgInfo.Name)); // TODO: add progress bar here // Create PackageIdentity in order to download - string createFullVersion = p.Version.ToString(); - if (p.IsPrerelease) + string createFullVersion = pkgInfo.Version.ToString(); + if (pkgInfo.IsPrerelease) { - createFullVersion = p.Version.ToString() + "-" + p.PrereleaseLabel; + createFullVersion = pkgInfo.Version.ToString() + "-" + pkgInfo.PrereleaseLabel; } if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) { - _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", p.Name, p.Version.ToString())); + _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", + pkgInfo.Name, pkgInfo.Version.ToString())); continue; } - var pkgIdentity = new PackageIdentity(p.Name, pkgVersion); + var pkgIdentity = new PackageIdentity(pkgInfo.Name, pkgVersion); var cacheContext = new SourceCacheContext(); if (isLocalRepo) @@ -352,7 +353,9 @@ private List InstallPackage( result.PackageReader.CopyFiles( destination: tempInstallPath, packageFiles: result.PackageReader.GetFiles(), - extractFile: (new PackageFileExtractor(result.PackageReader.GetFiles(), packageExtractionContext.XmlDocFileSaveMode)).ExtractPackageFile, + extractFile: new PackageFileExtractor( + result.PackageReader.GetFiles(), + packageExtractionContext.XmlDocFileSaveMode).ExtractPackageFile, logger: NullLogger.Instance, token: _cancellationToken); result.Dispose(); @@ -409,8 +412,8 @@ private List InstallPackage( string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); string moduleManifestVersion = string.Empty; - var scriptPath = Path.Combine(tempDirNameVersion, (p.Name + ".ps1")); - var modulePath = Path.Combine(tempDirNameVersion, (p.Name + ".psd1")); + var scriptPath = Path.Combine(tempDirNameVersion, pkgInfo.Name + ".ps1"); + var modulePath = Path.Combine(tempDirNameVersion, pkgInfo.Name + ".psd1"); // Check if the package is a module or a script var isModule = File.Exists(modulePath); @@ -436,20 +439,20 @@ private List InstallPackage( moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; // Accept License verification - if (!_savePkg && !CallAcceptLicense(p, moduleManifest, tempInstallPath, newVersion)) + if (!_savePkg && !CallAcceptLicense(pkgInfo, moduleManifest, tempInstallPath, newVersion)) { continue; } // If NoClobber is specified, ensure command clobbering does not happen - if (_noClobber && !DetectClobber(p.Name, tempDirNameVersion, parsedMetadataHashtable)) + if (_noClobber && !DetectClobber(pkgInfo.Name, parsedMetadataHashtable)) { continue; } } // Delete the extra nupkg related files that are not needed and not part of the module/script - DeleteExtraneousFiles(tempInstallPath, pkgIdentity, tempDirNameVersion); + DeleteExtraneousFiles(pkgIdentity, tempDirNameVersion); string installPath; if (_savePkg) @@ -468,20 +471,29 @@ private List InstallPackage( if (_includeXML) { - CreateMetadataXMLFile(tempDirNameVersion, installPath, repoName, p, isModule); + CreateMetadataXMLFile(tempDirNameVersion, installPath, pkgInfo, isModule); } - MoveFilesIntoInstallPath(p, isModule, isLocalRepo, tempDirNameVersion, tempInstallPath, installPath, newVersion, moduleManifestVersion, normalizedVersionNoPrereleaseLabel, version4digitNoPrerelease, scriptPath); + MoveFilesIntoInstallPath( + pkgInfo, + isModule, + isLocalRepo, + tempDirNameVersion, + tempInstallPath, + installPath, + newVersion, + moduleManifestVersion, + scriptPath); - _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", p.Name, installPath)); - pkgsSuccessfullyInstalled.Add(p.Name); + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkgInfo.Name, installPath)); + pkgsSuccessfullyInstalled.Add(pkgInfo.Name); } catch (Exception e) { _cmdletPassedIn.WriteError( new ErrorRecord( new PSInvalidOperationException( - message: $"Unable to successfully install package '{p.Name}': '{e.Message}'", + message: $"Unable to successfully install package '{pkgInfo.Name}': '{e.Message}'", innerException: e), "InstallPackageFailed", ErrorCategory.InvalidOperation, @@ -584,7 +596,7 @@ private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string t return success; } - private bool DetectClobber(string pkgName, string tempDirNameVersion, Hashtable parsedMetadataHashtable) + private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) { // Get installed modules, then get all possible paths bool foundClobber = false; @@ -608,10 +620,12 @@ private bool DetectClobber(string pkgName, string tempDirNameVersion, Hashtable duplicateCmdlets = listOfCmdlets.Where(cmdlet => pkg.Includes.Cmdlet.Contains(cmdlet)).ToList(); } + if (pkg.Includes.Command != null && pkg.Includes.Command.Any()) { duplicateCmds = listOfCmdlets.Where(commands => pkg.Includes.Command.Contains(commands, StringComparer.InvariantCultureIgnoreCase)).ToList(); } + if (duplicateCmdlets.Any() || duplicateCmds.Any()) { @@ -634,7 +648,7 @@ private bool DetectClobber(string pkgName, string tempDirNameVersion, Hashtable return foundClobber; } - private void CreateMetadataXMLFile(string dirNameVersion, string installPath, string repoName, PSResourceInfo pkg, bool isModule) + private void CreateMetadataXMLFile(string dirNameVersion, string installPath, PSResourceInfo pkg, bool isModule) { // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" // Modules will have the metadata file: "PSGetModuleInfo.xml" @@ -654,14 +668,14 @@ private void CreateMetadataXMLFile(string dirNameVersion, string installPath, st } } - private void DeleteExtraneousFiles(string tempInstallPath, PackageIdentity pkgIdentity, string dirNameVersion) + private void DeleteExtraneousFiles(PackageIdentity pkgIdentity, string dirNameVersion) { // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module var pkgIdString = pkgIdentity.ToString(); - var nupkgSHAToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.sha512")); - var nuspecToDelete = Path.Combine(dirNameVersion, (pkgIdentity.Id + ".nuspec")); - var nupkgToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg")); - var nupkgMetadataToDelete = Path.Combine(dirNameVersion, (pkgIdString + ".nupkg.metadata")); + var nupkgSHAToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.sha512"); + var nuspecToDelete = Path.Combine(dirNameVersion, pkgIdentity.Id + ".nuspec"); + var nupkgToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg"); + var nupkgMetadataToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.metadata"); var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); var packageDirToDelete = Path.Combine(dirNameVersion, "package"); @@ -725,7 +739,7 @@ private bool TryDeleteDirectory( } private void MoveFilesIntoInstallPath( - PSResourceInfo p, + PSResourceInfo pkgInfo, bool isModule, bool isLocalRepo, string dirNameVersion, @@ -733,17 +747,15 @@ private void MoveFilesIntoInstallPath( string installPath, string newVersion, string moduleManifestVersion, - string nupkgVersion, - string versionWithoutPrereleaseTag, string scriptPath) { // Creating the proper installation path depending on whether pkg is a module or script - var newPathParent = isModule ? Path.Combine(installPath, p.Name) : installPath; - var finalModuleVersionDir = isModule ? Path.Combine(installPath, p.Name, moduleManifestVersion) : installPath; // versionWithoutPrereleaseTag + var newPathParent = isModule ? Path.Combine(installPath, pkgInfo.Name) : installPath; + var finalModuleVersionDir = isModule ? Path.Combine(installPath, pkgInfo.Name, moduleManifestVersion) : installPath; // If script, just move the files over, if module, move the version directory over var tempModuleVersionDir = (!isModule || isLocalRepo) ? dirNameVersion - : Path.Combine(tempInstallPath, p.Name.ToLower(), newVersion); + : Path.Combine(tempInstallPath, pkgInfo.Name.ToLower(), newVersion); _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); @@ -774,11 +786,12 @@ private void MoveFilesIntoInstallPath( Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); } } - else { + else + { if (!_savePkg) { // Need to delete old xml files because there can only be 1 per script - var scriptXML = p.Name + "_InstalledScriptInfo.xml"; + var scriptXML = pkgInfo.Name + "_InstalledScriptInfo.xml"; _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) { @@ -790,16 +803,16 @@ private void MoveFilesIntoInstallPath( Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); // Need to delete old script file, if that exists - _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")))); - if (File.Exists(Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))) + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1")))); + if (File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1"))) { _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); - File.Delete(Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + File.Delete(Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1")); } } - _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1"))); - Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, p.Name + ".ps1")); + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1"))); + Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1")); } } diff --git a/src/code/NuGetLogger.cs b/src/code/NuGetLogger.cs index baa50d42b..d46d4a4d1 100644 --- a/src/code/NuGetLogger.cs +++ b/src/code/NuGetLogger.cs @@ -1,13 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using NuGet.Common; using System; using System.Collections.Concurrent; using System.Threading.Tasks; -using NuGet.Common; -// This class is needed for -public class NuGetLogger : ILogger +#region NuGetLogger + +internal class NuGetLogger : ILogger { private readonly ITestOutputHelper _output; @@ -175,9 +176,13 @@ public async Task LogAsync(ILogMessage message) } } +#endregion + +#region ITestOutputHelper + // Summary: // Represents a class which can be used to provide test output. -public interface ITestOutputHelper +internal interface ITestOutputHelper { // Summary: // Adds a line of text to the output. @@ -185,6 +190,7 @@ public interface ITestOutputHelper // message: // The message void WriteLine(string message); + // Summary: // Formats a line of text and adds it to the output. // Parameters: @@ -194,3 +200,5 @@ public interface ITestOutputHelper // The format arguments void WriteLine(string format, params object[] args); } + +#endregion diff --git a/src/code/PSRepositoryInfo.cs b/src/code/PSRepositoryInfo.cs index ade75833e..b1d99eb08 100644 --- a/src/code/PSRepositoryInfo.cs +++ b/src/code/PSRepositoryInfo.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + using System; using System.Management.Automation; diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 4286bab86..8f29930a0 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -57,11 +57,7 @@ public string Path set { - string resolvedPath = string.Empty; - if (!string.IsNullOrEmpty(value)) - { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } + string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; if (Directory.Exists(resolvedPath)) { @@ -88,18 +84,14 @@ public string DestinationPath set { - string resolvedPath = string.Empty; - if (!string.IsNullOrEmpty(value)) - { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } + string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; if (Directory.Exists(resolvedPath)) { _destinationPath = resolvedPath; } - else { - // try to create the path + else + { try { Directory.CreateDirectory(value); @@ -175,6 +167,7 @@ public PSCredential ProxyCredential { #endregion #region Method overrides + protected override void BeginProcessing() { // Create a respository story (the PSResourceRepository.xml file) if it does not already exist @@ -184,10 +177,6 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - string moduleManifestOrScriptPath; - FileInfo moduleFileInfo; - Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); - // Returns the name of the file or the name of the directory, depending on path var pkgFileOrDir = new DirectoryInfo(_path); bool isScript = _path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase); @@ -198,23 +187,22 @@ protected override void ProcessRecord() WriteVerbose("ShouldProcess is set to false."); return; } - + + string resourceFilePath; + Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); if (isScript) { - // Get the .psd1 file or .ps1 file - moduleManifestOrScriptPath = pkgFileOrDir.FullName; - moduleFileInfo = new FileInfo(moduleManifestOrScriptPath); + resourceFilePath = pkgFileOrDir.FullName; // Check that script metadata is valid - // ParseScriptMetadata will write non-terminating error if it's unsucessful in parsing - parsedMetadataHash = ParseScriptMetadata(moduleFileInfo); + // ParseScriptMetadata will write non-terminating error if it's unsuccessful in parsing + parsedMetadataHash = ParseScriptMetadata(resourceFilePath); - var message = string.Empty; // Check that the value is valid input // If it does not contain 'Version' or the Version empty or whitespace, write error if (!parsedMetadataHash.ContainsKey("Version") || String.IsNullOrWhiteSpace(parsedMetadataHash["Version"].ToString())) { - message = "No version was provided in the script metadata. Script metadata must specify a version, author and description."; + var message = "No version was provided in the script metadata. Script metadata must specify a version, author and description."; var ex = new ArgumentException(message); var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); WriteError(InvalidScriptMetadata); @@ -223,7 +211,7 @@ protected override void ProcessRecord() } if (!parsedMetadataHash.ContainsKey("Author") || String.IsNullOrWhiteSpace(parsedMetadataHash["Author"].ToString())) { - message = "No author was provided in the script metadata. Script metadata must specify a version, author and description."; + var message = "No author was provided in the script metadata. Script metadata must specify a version, author and description."; var ex = new ArgumentException(message); var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); WriteError(InvalidScriptMetadata); @@ -232,7 +220,7 @@ protected override void ProcessRecord() } if (!parsedMetadataHash.ContainsKey("Description") || String.IsNullOrWhiteSpace(parsedMetadataHash["Description"].ToString())) { - message = "No description was provided in the script metadata. Script metadata must specify a version, author and description."; + var message = "No description was provided in the script metadata. Script metadata must specify a version, author and description."; var ex = new ArgumentException(message); var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); WriteError(InvalidScriptMetadata); @@ -243,15 +231,15 @@ protected override void ProcessRecord() // remove '.ps1' extension from file name _pkgName = pkgFileOrDir.Name.Remove(pkgFileOrDir.Name.Length - 4); } - else { + else + { _pkgName = pkgFileOrDir.Name; - moduleManifestOrScriptPath = System.IO.Path.Combine(_path, _pkgName + ".psd1"); - moduleFileInfo = new FileInfo(moduleManifestOrScriptPath); + resourceFilePath = System.IO.Path.Combine(_path, _pkgName + ".psd1"); // Validate that there's a module manifest - if (!File.Exists(moduleManifestOrScriptPath)) + if (!File.Exists(resourceFilePath)) { - var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", moduleManifestOrScriptPath); + var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", resourceFilePath); var ex = new ArgumentException(message); var moduleManifestNotFound = new ErrorRecord(ex, "moduleManifestNotFound", ErrorCategory.ObjectNotFound, null); WriteError(moduleManifestNotFound); @@ -260,7 +248,7 @@ protected override void ProcessRecord() } // validate that the module manifest has correct data - if (!IsValidModuleManifest(moduleManifestOrScriptPath)) + if (!IsValidModuleManifest(resourceFilePath)) { return; } @@ -274,7 +262,8 @@ protected override void ProcessRecord() { Directory.CreateDirectory(outputDir); } - catch (Exception e) { + catch (Exception e) + { var ex = new ArgumentException(e.Message); var ErrorCreatingTempDir = new ErrorRecord(ex, "ErrorCreatingTempDir", ErrorCategory.InvalidData, null); WriteError(ErrorCreatingTempDir); @@ -285,16 +274,21 @@ protected override void ProcessRecord() try { - Hashtable dependencies; - // Create a nuspec // Right now parsedMetadataHash will be empty for modules and will contain metadata for scripts + Hashtable dependencies; string nuspec = string.Empty; try { - nuspec = CreateNuspec(outputDir, moduleFileInfo, out dependencies, parsedMetadataHash); + nuspec = CreateNuspec( + outputDir: outputDir, + filePath: resourceFilePath, + isScript: isScript, + parsedMetadataHash: parsedMetadataHash, + requiredModules: out dependencies); } - catch (Exception e) { + catch (Exception e) + { var message = string.Format("Nuspec creation failed: {0}", e.Message); var ex = new ArgumentException(message); var nuspecCreationFailed = new ErrorRecord(ex, "NuspecCreationFailed", ErrorCategory.ObjectNotFound, null); @@ -311,7 +305,7 @@ protected override void ProcessRecord() } // Find repository - PSRepositoryInfo repository = RepositorySettings.Read(new[] { Repository }, out string[] errorList).FirstOrDefault(); + PSRepositoryInfo repository = RepositorySettings.Read(new[] { Repository }, out string[] _).FirstOrDefault(); if (repository == null) { var message = String.Format("The resource repository '{0}' is not a registered. Please run 'Register-PSResourceRepository' in order to publish to this repository.", Repository); @@ -371,7 +365,7 @@ protected override void ProcessRecord() // pack into a nupkg try { - if(!PackNupkg(outputDir, outputNupkgDir, nuspec)) + if (!PackNupkg(outputDir, outputNupkgDir, nuspec)) { return; } @@ -411,7 +405,8 @@ protected override void ProcessRecord() PushNupkg(outputNupkgDir, repository.Name, repositoryUrl); } - finally { + finally + { WriteVerbose(string.Format("Deleting temporary directory '{0}'", outputDir)); Utils.DeleteDirectory(outputDir); } @@ -423,7 +418,7 @@ protected override void ProcessRecord() private bool IsValidModuleManifest(string moduleManifestPath) { - var isValid = false; + var isValid = true; using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) { // use PowerShell cmdlet Test-ModuleManifest @@ -453,10 +448,7 @@ private bool IsValidModuleManifest(string moduleManifestPath) var ex = new ArgumentException(message); var InvalidModuleManifest = new ErrorRecord(ex, "InvalidModuleManifest", ErrorCategory.InvalidData, null); WriteError(InvalidModuleManifest); - } - else - { - isValid = true; + isValid = false; } } @@ -464,53 +456,30 @@ private bool IsValidModuleManifest(string moduleManifestPath) } private string CreateNuspec( - string outputDir, - FileInfo moduleFileInfo, - out Hashtable requiredModules, - Hashtable parsedMetadataHash) + string outputDir, + string filePath, + bool isScript, + Hashtable parsedMetadataHash, + out Hashtable requiredModules) { WriteVerbose("Creating new nuspec file."); requiredModules = new Hashtable(); - // A script will already have the metadata parsed into the parsedMetadatahash, + // A script will already have the metadata parsed into the parsedMetadatahash, // a module will still need the module manifest to be parsed. - if (moduleFileInfo.Extension.Equals(".psd1", StringComparison.OrdinalIgnoreCase)) + if (!isScript) { - // Parse the module manifest - System.Management.Automation.Language.Token[] tokens; - ParseError[] errors; - var ast = Parser.ParseFile(moduleFileInfo.FullName, out tokens, out errors); - - if (errors.Length > 0) + // Parse the module manifest and *replace* the passed-in metadata with the module manifest metadata. + if (!Utils.TryParseModuleManifest( + moduleFileInfo: filePath, + cmdletPassedIn: this, + parsedMetadataHashtable: out parsedMetadataHash)) { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo.FullName); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - WriteError(psdataParseError); - return string.Empty; } - else - { - // Must search nested script blocks because 'Tags' are located under 'PrivateData' > 'PSData' - var data = ast.Find(a => a is HashtableAst, true); - if (data != null) - { - parsedMetadataHash = (Hashtable) data.SafeGetValue(); - } - else - { - var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo.FullName); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - WriteError(psdataParseError); - - return string.Empty; - } - } } - /// now we have parsedMetadatahash to fill out the nuspec information + // now we have parsedMetadatahash to fill out the nuspec information var nameSpaceUri = "http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"; var doc = new XmlDocument(); @@ -528,7 +497,7 @@ private string CreateNuspec( // id is mandatory metadataElementsDictionary.Add("id", _pkgName); - string version = String.Empty; + string version; if (parsedMetadataHash.ContainsKey("moduleversion")) { version = parsedMetadataHash["moduleversion"].ToString(); @@ -608,7 +577,7 @@ private string CreateNuspec( metadataElementsDictionary.Add("copyright", parsedMetadataHash["copyright"].ToString().Trim()); } - string tags = moduleFileInfo.Extension.Equals(".psd1", StringComparison.OrdinalIgnoreCase) ? "PSModule" : "PSScript"; + string tags = isScript ? "PSScript" : "PSModule"; if (parsedMetadataHash.ContainsKey("tags")) { if (parsedMetadataHash["tags"] != null) @@ -742,7 +711,7 @@ private Hashtable ParseRequiredModules(Hashtable parsedMetadataHash) return dependenciesHash; } - private Hashtable ParseScriptMetadata(FileInfo moduleFileInfo) + private Hashtable ParseScriptMetadata(string filePath) { // parse .ps1 - example .ps1 metadata: /* <#PSScriptInfo @@ -769,13 +738,14 @@ Example cmdlet here Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); // parse comments out - System.Management.Automation.Language.Token[] tokens; - ParseError[] errors; - Parser.ParseFile(moduleFileInfo.FullName, out tokens, out errors); + Parser.ParseFile( + filePath, + out System.Management.Automation.Language.Token[] tokens, + out ParseError[] errors); if (errors.Length > 0) { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo.FullName); + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", filePath); var ex = new ArgumentException(message); var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); WriteError(psdataParseError); diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 11cb8a861..821f05688 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Management.Automation; + using Dbg = System.Diagnostics.Debug; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 529e56186..511c9d651 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Management.Automation; using System.Xml.Linq; -using static System.Environment; + using Dbg = System.Diagnostics.Debug; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses @@ -19,19 +19,24 @@ namespace Microsoft.PowerShell.PowerShellGet.UtilClasses /// internal static class RepositorySettings - { - /// - /// File name for a user's repository store file is 'PSResourceRepository.xml' - /// The repository store file's location is currently only at '%LOCALAPPDATA%\PowerShellGet' for the user account. - /// + { + #region Members + + // File name for a user's repository store file is 'PSResourceRepository.xml' + // The repository store file's location is currently only at '%LOCALAPPDATA%\PowerShellGet' for the user account. private const string PSGalleryRepoName = "PSGallery"; private const string PSGalleryRepoURL = "https://www.powershellgallery.com/api/v2"; private const int defaultPriority = 50; private const bool defaultTrusted = false; private const string RepositoryFileName = "PSResourceRepository.xml"; - private static readonly string RepositoryPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "PowerShellGet"); + private static readonly string RepositoryPath = Path.Combine(Environment.GetFolderPath( + Environment.SpecialFolder.LocalApplicationData), "PowerShellGet"); private static readonly string FullRepositoryPath = Path.Combine(RepositoryPath, RepositoryFileName); + #endregion + + #region Public methods + /// /// Check if repository store xml file exists, if not then create /// @@ -305,6 +310,10 @@ public static List Read(string[] repoNames, out string[] error return reposToReturn.ToList(); } + #endregion + + #region Private methods + private static XElement FindRepositoryElement(XDocument doc, string name) { return doc.Descendants("Repository").Where( @@ -313,5 +322,7 @@ private static XElement FindRepositoryElement(XDocument doc, string name) name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } + + #endregion } } diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 9c8b292f7..64e9e98bc 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -192,7 +192,7 @@ protected override void ProcessRecord() #endregion - #region Methods + #region Private methods private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) { diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 49ed8d272..a2144e3e1 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.PowerShell.PowerShellGet.UtilClasses; using System; using System.Collections; using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; using System.Management.Automation; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +using Dbg = System.Diagnostics.Debug; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -17,8 +18,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets "PSResourceRepository", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true)] - public sealed - class SetPSResourceRepository : PSCmdlet + public sealed class SetPSResourceRepository : PSCmdlet { #region Members @@ -89,7 +89,8 @@ public SwitchParameter Trusted #endregion - #region Methods + #region Private methods + protected override void BeginProcessing() { RepositorySettings.CheckRepositoryStore(); @@ -190,6 +191,7 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr { return null; } + return RepositorySettings.Update(repoName, repoUrl, repoPriority, _trustedNullable); } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 1b627a3d4..4c2be49d9 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,15 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + +using NuGet.Versioning; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Management.Automation; -using System.Threading; -using NuGet.Versioning; -using Microsoft.PowerShell.PowerShellGet.UtilClasses; - namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { @@ -20,6 +19,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets public sealed class UninstallPSResource : PSCmdlet { #region Parameters + /// /// Specifies the exact names of resources to uninstall. /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. @@ -47,17 +47,21 @@ public sealed class UninstallPSResource : PSCmdlet [Parameter(ParameterSetName = NameParameterSet)] [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter Force { get; set; } + #endregion #region Members + private const string NameParameterSet = "NameParameterSet"; private const string InputObjectParameterSet = "InputObjectParameterSet"; public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); + #endregion - #region Methods + #region Method overrides + protected override void BeginProcessing() { _pathsToSearch = Utils.GetAllResourcePaths(this); @@ -139,6 +143,9 @@ protected override void ProcessRecord() } } + #endregion + + #region Private methods private bool UninstallPkgHelper() { @@ -155,7 +162,7 @@ private bool UninstallPkgHelper() // ./Scripts/TestScript.ps1 // note that the xml file is located in ./Scripts/InstalledScriptInfos, eg: ./Scripts/InstalledScriptInfos/TestScript_InstalledScriptInfo.xml - string pkgName = string.Empty; + string pkgName; foreach (string pkgPath in getHelper.FilterPkgPathsByVersion(_versionRange, dirsToDelete)) { pkgName = Utils.GetInstalledPackageName(pkgPath); @@ -230,7 +237,8 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco Utils.DeleteDirectory(dir.Parent.FullName); } } - catch (Exception e) { + catch (Exception e) + { // write error var exMessage = String.Format("Parent directory '{0}' could not be deleted: {1}", dir.Parent.FullName, e.Message); var ex = new ArgumentException(exMessage); @@ -238,7 +246,8 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco errRecord = ErrorDeletingParentDirectory; } } - catch (Exception err) { + catch (Exception err) + { // write error var exMessage = String.Format("Directory '{0}' could not be deleted: {1}", dir.FullName, err.Message); var ex = new ArgumentException(exMessage); @@ -281,7 +290,8 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorReco errRecord = ErrorDeletingScriptMetadataFile; } } - catch (Exception err){ + catch (Exception err) + { var exMessage = String.Format("Script '{0}' could not be deleted: {1}", pkgPath, err.Message); var ex = new ArgumentException(exMessage); var ErrorDeletingScript = new ErrorRecord(ex, "ErrorDeletingScript", ErrorCategory.PermissionDenied, null); @@ -313,7 +323,8 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) p => ((ReadOnlyCollection)p.Properties["RequiredModules"].Value).Where( rm => rm.Name.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)).Any()); } - catch (Exception e) { + catch (Exception e) + { var exMessage = String.Format("Error checking if resource is a dependency: {0}. If you would still like to uninstall, rerun the command with -Force", e.Message); var ex = new ArgumentException(exMessage); var DependencyCheckError = new ErrorRecord(ex, "DependencyCheckError", ErrorCategory.OperationStopped, null); @@ -333,8 +344,10 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) return true; } } + return false; } + #endregion } } diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index 2d984fc12..bf7647082 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -30,7 +30,7 @@ class UnregisterPSResourceRepository : PSCmdlet #endregion - #region Methods + #region Method overrides protected override void BeginProcessing() { diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 90fcb0ea0..86b811888 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -16,7 +16,6 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// It updates an already installed package based on the -Name parameter argument. /// It does not return an object. Other parameters allow the package to be updated to be further filtered. /// - [Cmdlet(VerbsData.Update, "PSResource", SupportsShouldProcess = true)] diff --git a/src/code/Utils.cs b/src/code/Utils.cs index d2cf24b03..c861e6a17 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -4,14 +4,12 @@ using System; using System.Collections; using System.Collections.Generic; -using static System.Environment; using System.IO; using System.Linq; using System.Management.Automation; using System.Management.Automation.Language; using System.Runtime.InteropServices; using NuGet.Versioning; -using System.Globalization; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -425,13 +423,13 @@ private static void GetStandardPlatformPaths( if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; - myDocumentsPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), powerShellType); + myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); } else { // paths are the same for both Linux and macOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "powershell"); + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); } } @@ -453,9 +451,10 @@ public static bool TryParseModuleManifest( if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) { // Parse the module manifest - System.Management.Automation.Language.Token[] tokens; - ParseError[] errors; - var ast = Parser.ParseFile(moduleFileInfo, out tokens, out errors); + var ast = Parser.ParseFile( + moduleFileInfo, + out Token[] tokens, + out ParseError[] errors); if (errors.Length > 0) { From cf75124c067720ab1e4a3d56cab635f9030b1591 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 15 Nov 2021 08:56:03 -0800 Subject: [PATCH 101/276] Remove unneeded Microsoft.Extensions.Logging (#546) --- Notice.txt | 142 ---------------------------------- doBuild.ps1 | 1 - src/code/PowerShellGet.csproj | 1 - 3 files changed, 144 deletions(-) diff --git a/Notice.txt b/Notice.txt index 9e8581321..9fec896f7 100644 --- a/Notice.txt +++ b/Notice.txt @@ -1598,148 +1598,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------- - ---------------------------------------------------------- - -Microsoft.Extensions.Logging 5.0.0-preview.7.20364.11 - MIT - - -(c) 2008 VeriSign, Inc. -(c) Microsoft Corporation. -Copyright (c) Andrew Arnott -Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. -Copyright (c) 2011, Google Inc. -Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2018 Alexander Chermyanin -Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) .NET Foundation Contributors -Copyright (c) The Internet Society (2003). -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -Microsoft.Extensions.Logging.Abstractions 5.0.0-preview.7.20364.11 - MIT - - -(c) 2008 VeriSign, Inc. -(c) Microsoft Corporation. -Copyright (c) Andrew Arnott -Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. -Copyright (c) 2011, Google Inc. -Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2018 Alexander Chermyanin -Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) .NET Foundation Contributors -Copyright (c) The Internet Society (2003). -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - --------------------------------------------------------- --------------------------------------------------------- diff --git a/doBuild.ps1 b/doBuild.ps1 index a23afa510..ee7d99785 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -75,7 +75,6 @@ function DoBuild # Place build results $assemblyNames = @( 'PowerShellGet' - 'Microsoft.Extensions.Logging.Abstractions' 'MoreLinq' 'NuGet.Commands' 'NuGet.Common' diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 9452ccff4..ccba80588 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -14,7 +14,6 @@ - From db2a6bd62d3f821ab8a10b2a042a3da5e35daacd Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 15 Nov 2021 09:33:46 -0800 Subject: [PATCH 102/276] Use path separator to split PSModulePath env var (#541) Co-authored-by: Paul Higinbotham --- src/code/Utils.cs | 1324 ++++++++++++++++++++++----------------------- 1 file changed, 662 insertions(+), 662 deletions(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index c861e6a17..307d5569a 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,662 +1,662 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Runtime.InteropServices; -using NuGet.Versioning; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - internal static class Utils - { - #region String fields - - public static readonly string[] EmptyStrArray = Array.Empty(); - - #endregion - - #region String methods - - public static string TrimQuotes(string name) - { - return name.Trim('\'', '"'); - } - - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) - { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } - } - - if (!quotesNeeded) - { - return name; - } - - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i < list.Count; i++) - { - strArray[i] = list[i] as string; - } - - return strArray; - } - - public static string[] ProcessNameWildcards( - string[] pkgNames, - out string[] errorMsgs, - out bool isContainWildcard) - { - List namesWithSupportedWildcards = new List(); - List errorMsgsList = new List(); - - if (pkgNames == null) - { - isContainWildcard = true; - errorMsgs = errorMsgsList.ToArray(); - return new string[] {"*"}; - } - - isContainWildcard = false; - foreach (string name in pkgNames) - { - if (WildcardPattern.ContainsWildcardCharacters(name)) - { - if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) - { - isContainWildcard = true; - errorMsgs = new string[] {}; - return new string[] {"*"}; - } - - if (name.Contains("?") || name.Contains("[")) - { - errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); - continue; - } - - isContainWildcard = true; - namesWithSupportedWildcards.Add(name); - } - else - { - namesWithSupportedWildcards.Add(name); - } - } - - errorMsgs = errorMsgsList.ToArray(); - return namesWithSupportedWildcards.ToArray(); - } - - #endregion - - #region Version methods - - public static string GetNormalizedVersionString( - string versionString, - string prerelease) - { - // versionString may be like 1.2.0.0 or 1.2.0 - // prerelease may be null or "alpha1" - // possible passed in examples: - // versionString: "1.2.0" prerelease: "alpha1" - // versionString: "1.2.0" prerelease: "" <- doubtful though - // versionString: "1.2.0.0" prerelease: "alpha1" - // versionString: "1.2.0.0" prerelease: "" - - if (String.IsNullOrEmpty(prerelease)) - { - return versionString; - } - - int numVersionDigits = versionString.Split('.').Count(); - - if (numVersionDigits == 3) - { - // versionString: "1.2.0" prerelease: "alpha1" - return versionString + "-" + prerelease; - } - - else if (numVersionDigits == 4) - { - // versionString: "1.2.0.0" prerelease: "alpha1" - return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; - } - - return versionString; - } - - public static bool TryParseVersionOrVersionRange( - string version, - out VersionRange versionRange) - { - versionRange = null; - if (version == null) { return false; } - - if (version.Trim().Equals("*")) - { - versionRange = VersionRange.All; - return true; - } - - // parse as NuGetVersion - if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) - { - versionRange = new VersionRange( - minVersion: nugetVersion, - includeMinVersion: true, - maxVersion: nugetVersion, - includeMaxVersion: true, - floatRange: null, - originalString: version); - return true; - } - - // parse as Version range - return VersionRange.TryParse(version, out versionRange); - } - - public static bool GetVersionForInstallPath( - string installedPkgPath, - bool isModule, - PSCmdlet cmdletPassedIn, - out NuGetVersion pkgNuGetVersion) - { - // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file - // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. - // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current - // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. - - // for Modules, installedPkgPath will look like this: - // ./PowerShell/Modules/test_module/3.0.0 - // for Scripts, installedPkgPath will look like this: - // ./PowerShell/Scripts/test_script.ps1 - string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); - - string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); - if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - cmdletPassedIn.WriteVerbose(String.Format( - "The {0} file found at location: {1} cannot be parsed due to {2}", - isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", - packageInfoXMLFilePath, - errorMsg)); - pkgNuGetVersion = null; - return false; - } - - string version = psGetInfo.Version.ToString(); - string prereleaseLabel = psGetInfo.PrereleaseLabel; - - if (!NuGetVersion.TryParse( - value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), - version: out pkgNuGetVersion)) - { - cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); - return false; - } - - return true; - } - - #endregion - - #region Url methods - - public static bool TryCreateValidUrl( - string uriString, - PSCmdlet cmdletPassedIn, - out Uri uriResult, - out ErrorRecord errorRecord - ) - { - errorRecord = null; - if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) - { - return true; - } - - Exception ex; - try - { - // This is needed for a relative path urlstring. Does not throw error for an absolute path - var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; - if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) - { - return true; - } - - ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); - } - catch (Exception e) - { - ex = e; - } - - errorRecord = new ErrorRecord( - new PSArgumentException( - $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", - ex), - "InvalidUri", - ErrorCategory.InvalidArgument, - cmdletPassedIn); - - return false; - } - - #endregion - - #region Path methods - - public static string[] GetSubDirectories(string dirPath) - { - try - { - return Directory.GetDirectories(dirPath); - } - catch - { - return EmptyStrArray; - } - } - - public static string[] GetDirectoryFiles(string dirPath) - { - try - { - return Directory.GetFiles(dirPath); - } - catch - { - return EmptyStrArray; - } - } - - public static string GetInstalledPackageName(string pkgPath) - { - if (string.IsNullOrEmpty(pkgPath)) - { - return string.Empty; - } - - if (File.Exists(pkgPath)) - { - // ex: ./PowerShell/Scripts/TestScript.ps1 - return System.IO.Path.GetFileNameWithoutExtension(pkgPath); - } - else - { - // expecting the full version module path - // ex: ./PowerShell/Modules/TestModule/1.0.0 - return new DirectoryInfo(pkgPath).Parent.Name; - } - } - - public static List GetAllResourcePaths( - PSCmdlet psCmdlet, - ScopeType? scope = null) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - List resourcePaths = new List(); - - // Path search order is PSModulePath paths first, then default paths. - if (scope is null) - { - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - resourcePaths.AddRange(psModulePath.Split(';').ToList()); - } - - if (scope is null || scope.Value is ScopeType.CurrentUser) - { - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); - } - - if (scope is null || scope.Value is ScopeType.AllUsers) - { - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); - } - - // resourcePaths should now contain, eg: - // ./PowerShell/Scripts - // ./PowerShell/Modules - // add all module directories or script files - List pathsToSearch = new List(); - foreach (string path in resourcePaths) - { - psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); - - if (path.EndsWith("Scripts")) - { - try - { - pathsToSearch.AddRange(GetDirectoryFiles(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); - } - } - else - { - try - { - pathsToSearch.AddRange(GetSubDirectories(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); - } - } - } - - // resourcePaths should now contain eg: - // ./PowerShell/Scripts/Test-Script.ps1 - // ./PowerShell/Modules/TestModule - // need to use .ToList() to cast the IEnumerable to type List - pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); - - return pathsToSearch; - } - - // Find all potential installation paths given a scope - public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType scope) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - // The default user scope is CurrentUser - var installationPaths = new List(); - if (scope == ScopeType.AllUsers) - { - installationPaths.Add(System.IO.Path.Combine(programFilesPath, "Modules")); - installationPaths.Add(System.IO.Path.Combine(programFilesPath, "Scripts")); - } - else - { - installationPaths.Add(System.IO.Path.Combine(myDocumentsPath, "Modules")); - installationPaths.Add(System.IO.Path.Combine(myDocumentsPath, "Scripts")); - } - - installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); - - return installationPaths; - } - - private readonly static Version PSVersion6 = new Version(6, 0); - private static void GetStandardPlatformPaths( - PSCmdlet psCmdlet, - out string myDocumentsPath, - out string programFilesPath) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; - myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and macOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); - programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); - } - } - - #endregion - - #region Manifest methods - - public static bool TryParseModuleManifest( - string moduleFileInfo, - PSCmdlet cmdletPassedIn, - out Hashtable parsedMetadataHashtable) - { - parsedMetadataHashtable = new Hashtable(); - bool successfullyParsed = false; - - // A script will already have the metadata parsed into the parsedMetadatahash, - // a module will still need the module manifest to be parsed. - if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) - { - // Parse the module manifest - var ast = Parser.ParseFile( - moduleFileInfo, - out Token[] tokens, - out ParseError[] errors); - - if (errors.Length > 0) - { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - return successfullyParsed; - } - else - { - var data = ast.Find(a => a is HashtableAst, false); - if (data != null) - { - parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); - successfullyParsed = true; - } - else - { - var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - } - } - } - - return successfullyParsed; - } - - #endregion - - #region Misc methods - - public static void WriteVerboseOnCmdlet( - PSCmdlet cmdlet, - string message) - { - try - { - cmdlet.InvokeCommand.InvokeScript( - script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { message }); - } - catch { } - } - - #endregion - - #region Directory and File - - /// - /// Deletes a directory and its contents. - /// Attempts to restore the directory and contents if deletion fails. - /// - public static void DeleteDirectoryWithRestore(string dirPath) - { - string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - - try - { - // Create temporary directory for restore operation if needed. - CopyDirContents(dirPath, tempDirPath, overwrite: true); - - try - { - DeleteDirectory(dirPath); - } - catch (Exception ex) - { - // Delete failed. Attempt to restore the saved directory content. - try - { - RestoreDirContents(tempDirPath, dirPath); - } - catch (Exception exx) - { - throw new PSInvalidOperationException( - $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", - ex); - } - - throw new PSInvalidOperationException( - $"Cannot remove package path {dirPath}. The previous package contents have been restored.", - ex); - } - } - finally - { - if (Directory.Exists(tempDirPath)) - { - DeleteDirectory(tempDirPath); - } - } - } - - /// - /// Deletes a directory and its contents - /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell - /// on OneDrive with 'access denied' error. - /// Later versions of .NET, with PowerShellCore, do not have this bug. - /// - public static void DeleteDirectory(string dirPath) - { - foreach (var dirFilePath in Directory.GetFiles(dirPath)) - { - File.Delete(dirFilePath); - } - - foreach (var dirSubPath in Directory.GetDirectories(dirPath)) - { - DeleteDirectory(dirSubPath); - } - - Directory.Delete(dirPath); - } - - /// - /// Moves files from source to destination locations. - /// This is a workaround for .NET File.Move(), which fails over different file volumes. - /// - public static void MoveFiles( - string sourceFilePath, - string destFilePath, - bool overwrite = true) - { - File.Copy(sourceFilePath, destFilePath, overwrite); - File.Delete(sourceFilePath); - } - - /// - /// Moves the directory, including contents, from source to destination locations. - /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. - /// - public static void MoveDirectory( - string sourceDirPath, - string destDirPath, - bool overwrite = true) - { - CopyDirContents(sourceDirPath, destDirPath, overwrite); - DeleteDirectory(sourceDirPath); - } - - private static void CopyDirContents( - string sourceDirPath, - string destDirPath, - bool overwrite) - { - if (Directory.Exists(destDirPath)) - { - if (!overwrite) - { - throw new PSInvalidOperationException( - $"Cannot move directory because destination directory already exists: '{destDirPath}'"); - } - - DeleteDirectory(destDirPath); - } - - Directory.CreateDirectory(destDirPath); - - foreach (var filePath in Directory.GetFiles(sourceDirPath)) - { - var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); - File.Copy(filePath, destFilePath); - } - - foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) - { - var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); - CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); - } - } - - private static void RestoreDirContents( - string sourceDirPath, - string destDirPath) - { - if (!Directory.Exists(destDirPath)) - { - Directory.CreateDirectory(destDirPath); - } - - foreach (string filePath in Directory.GetFiles(sourceDirPath)) - { - string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); - if (!File.Exists(destFilePath)) - { - File.Copy(filePath, destFilePath); - } - } - - foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) - { - string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); - RestoreDirContents(srcSubDirPath, destSubDirPath); - } - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Runtime.InteropServices; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + internal static class Utils + { + #region String fields + + public static readonly string[] EmptyStrArray = Array.Empty(); + + #endregion + + #region String methods + + public static string TrimQuotes(string name) + { + return name.Trim('\'', '"'); + } + + public static string QuoteName(string name) + { + bool quotesNeeded = false; + foreach (var c in name) + { + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } + } + + if (!quotesNeeded) + { + return name; + } + + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) + { + strArray[i] = list[i] as string; + } + + return strArray; + } + + public static string[] ProcessNameWildcards( + string[] pkgNames, + out string[] errorMsgs, + out bool isContainWildcard) + { + List namesWithSupportedWildcards = new List(); + List errorMsgsList = new List(); + + if (pkgNames == null) + { + isContainWildcard = true; + errorMsgs = errorMsgsList.ToArray(); + return new string[] {"*"}; + } + + isContainWildcard = false; + foreach (string name in pkgNames) + { + if (WildcardPattern.ContainsWildcardCharacters(name)) + { + if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) + { + isContainWildcard = true; + errorMsgs = new string[] {}; + return new string[] {"*"}; + } + + if (name.Contains("?") || name.Contains("[")) + { + errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); + continue; + } + + isContainWildcard = true; + namesWithSupportedWildcards.Add(name); + } + else + { + namesWithSupportedWildcards.Add(name); + } + } + + errorMsgs = errorMsgsList.ToArray(); + return namesWithSupportedWildcards.ToArray(); + } + + #endregion + + #region Version methods + + public static string GetNormalizedVersionString( + string versionString, + string prerelease) + { + // versionString may be like 1.2.0.0 or 1.2.0 + // prerelease may be null or "alpha1" + // possible passed in examples: + // versionString: "1.2.0" prerelease: "alpha1" + // versionString: "1.2.0" prerelease: "" <- doubtful though + // versionString: "1.2.0.0" prerelease: "alpha1" + // versionString: "1.2.0.0" prerelease: "" + + if (String.IsNullOrEmpty(prerelease)) + { + return versionString; + } + + int numVersionDigits = versionString.Split('.').Count(); + + if (numVersionDigits == 3) + { + // versionString: "1.2.0" prerelease: "alpha1" + return versionString + "-" + prerelease; + } + + else if (numVersionDigits == 4) + { + // versionString: "1.2.0.0" prerelease: "alpha1" + return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; + } + + return versionString; + } + + public static bool TryParseVersionOrVersionRange( + string version, + out VersionRange versionRange) + { + versionRange = null; + if (version == null) { return false; } + + if (version.Trim().Equals("*")) + { + versionRange = VersionRange.All; + return true; + } + + // parse as NuGetVersion + if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) + { + versionRange = new VersionRange( + minVersion: nugetVersion, + includeMinVersion: true, + maxVersion: nugetVersion, + includeMaxVersion: true, + floatRange: null, + originalString: version); + return true; + } + + // parse as Version range + return VersionRange.TryParse(version, out versionRange); + } + + public static bool GetVersionForInstallPath( + string installedPkgPath, + bool isModule, + PSCmdlet cmdletPassedIn, + out NuGetVersion pkgNuGetVersion) + { + // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file + // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. + // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current + // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. + + // for Modules, installedPkgPath will look like this: + // ./PowerShell/Modules/test_module/3.0.0 + // for Scripts, installedPkgPath will look like this: + // ./PowerShell/Scripts/test_script.ps1 + string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); + + string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); + if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + cmdletPassedIn.WriteVerbose(String.Format( + "The {0} file found at location: {1} cannot be parsed due to {2}", + isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", + packageInfoXMLFilePath, + errorMsg)); + pkgNuGetVersion = null; + return false; + } + + string version = psGetInfo.Version.ToString(); + string prereleaseLabel = psGetInfo.PrereleaseLabel; + + if (!NuGetVersion.TryParse( + value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), + version: out pkgNuGetVersion)) + { + cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); + return false; + } + + return true; + } + + #endregion + + #region Url methods + + public static bool TryCreateValidUrl( + string uriString, + PSCmdlet cmdletPassedIn, + out Uri uriResult, + out ErrorRecord errorRecord + ) + { + errorRecord = null; + if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) + { + return true; + } + + Exception ex; + try + { + // This is needed for a relative path urlstring. Does not throw error for an absolute path + var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; + if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) + { + return true; + } + + ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); + } + catch (Exception e) + { + ex = e; + } + + errorRecord = new ErrorRecord( + new PSArgumentException( + $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", + ex), + "InvalidUri", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; + } + + #endregion + + #region Path methods + + public static string[] GetSubDirectories(string dirPath) + { + try + { + return Directory.GetDirectories(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string[] GetDirectoryFiles(string dirPath) + { + try + { + return Directory.GetFiles(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string GetInstalledPackageName(string pkgPath) + { + if (string.IsNullOrEmpty(pkgPath)) + { + return string.Empty; + } + + if (File.Exists(pkgPath)) + { + // ex: ./PowerShell/Scripts/TestScript.ps1 + return Path.GetFileNameWithoutExtension(pkgPath); + } + else + { + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; + } + } + + public static List GetAllResourcePaths( + PSCmdlet psCmdlet, + ScopeType? scope = null) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + + List resourcePaths = new List(); + + // Path search order is PSModulePath paths first, then default paths. + if (scope is null) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + resourcePaths.AddRange(psModulePath.Split(Path.PathSeparator).ToList()); + } + + if (scope is null || scope.Value is ScopeType.CurrentUser) + { + resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + } + + if (scope is null || scope.Value is ScopeType.AllUsers) + { + resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + + // resourcePaths should now contain, eg: + // ./PowerShell/Scripts + // ./PowerShell/Modules + // add all module directories or script files + List pathsToSearch = new List(); + foreach (string path in resourcePaths) + { + psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); + + if (path.EndsWith("Scripts")) + { + try + { + pathsToSearch.AddRange(GetDirectoryFiles(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); + } + } + else + { + try + { + pathsToSearch.AddRange(GetSubDirectories(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); + } + } + } + + // resourcePaths should now contain eg: + // ./PowerShell/Scripts/Test-Script.ps1 + // ./PowerShell/Modules/TestModule + // need to use .ToList() to cast the IEnumerable to type List + pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); + + return pathsToSearch; + } + + // Find all potential installation paths given a scope + public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType scope) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + + // The default user scope is CurrentUser + var installationPaths = new List(); + if (scope == ScopeType.AllUsers) + { + installationPaths.Add(Path.Combine(programFilesPath, "Modules")); + installationPaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + else + { + installationPaths.Add(Path.Combine(myDocumentsPath, "Modules")); + installationPaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + } + + installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); + + return installationPaths; + } + + private readonly static Version PSVersion6 = new Version(6, 0); + private static void GetStandardPlatformPaths( + PSCmdlet psCmdlet, + out string myDocumentsPath, + out string programFilesPath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; + myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and macOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); + programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); + } + } + + #endregion + + #region Manifest methods + + public static bool TryParseModuleManifest( + string moduleFileInfo, + PSCmdlet cmdletPassedIn, + out Hashtable parsedMetadataHashtable) + { + parsedMetadataHashtable = new Hashtable(); + bool successfullyParsed = false; + + // A script will already have the metadata parsed into the parsedMetadatahash, + // a module will still need the module manifest to be parsed. + if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) + { + // Parse the module manifest + var ast = Parser.ParseFile( + moduleFileInfo, + out Token[] tokens, + out ParseError[] errors); + + if (errors.Length > 0) + { + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + return successfullyParsed; + } + else + { + var data = ast.Find(a => a is HashtableAst, false); + if (data != null) + { + parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); + successfullyParsed = true; + } + else + { + var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + } + } + } + + return successfullyParsed; + } + + #endregion + + #region Misc methods + + public static void WriteVerboseOnCmdlet( + PSCmdlet cmdlet, + string message) + { + try + { + cmdlet.InvokeCommand.InvokeScript( + script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { message }); + } + catch { } + } + + #endregion + + #region Directory and File + + /// + /// Deletes a directory and its contents. + /// Attempts to restore the directory and contents if deletion fails. + /// + public static void DeleteDirectoryWithRestore(string dirPath) + { + string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + + try + { + // Create temporary directory for restore operation if needed. + CopyDirContents(dirPath, tempDirPath, overwrite: true); + + try + { + DeleteDirectory(dirPath); + } + catch (Exception ex) + { + // Delete failed. Attempt to restore the saved directory content. + try + { + RestoreDirContents(tempDirPath, dirPath); + } + catch (Exception exx) + { + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", + ex); + } + + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. The previous package contents have been restored.", + ex); + } + } + finally + { + if (Directory.Exists(tempDirPath)) + { + DeleteDirectory(tempDirPath); + } + } + } + + /// + /// Deletes a directory and its contents + /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell + /// on OneDrive with 'access denied' error. + /// Later versions of .NET, with PowerShellCore, do not have this bug. + /// + public static void DeleteDirectory(string dirPath) + { + foreach (var dirFilePath in Directory.GetFiles(dirPath)) + { + File.Delete(dirFilePath); + } + + foreach (var dirSubPath in Directory.GetDirectories(dirPath)) + { + DeleteDirectory(dirSubPath); + } + + Directory.Delete(dirPath); + } + + /// + /// Moves files from source to destination locations. + /// This is a workaround for .NET File.Move(), which fails over different file volumes. + /// + public static void MoveFiles( + string sourceFilePath, + string destFilePath, + bool overwrite = true) + { + File.Copy(sourceFilePath, destFilePath, overwrite); + File.Delete(sourceFilePath); + } + + /// + /// Moves the directory, including contents, from source to destination locations. + /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. + /// + public static void MoveDirectory( + string sourceDirPath, + string destDirPath, + bool overwrite = true) + { + CopyDirContents(sourceDirPath, destDirPath, overwrite); + DeleteDirectory(sourceDirPath); + } + + private static void CopyDirContents( + string sourceDirPath, + string destDirPath, + bool overwrite) + { + if (Directory.Exists(destDirPath)) + { + if (!overwrite) + { + throw new PSInvalidOperationException( + $"Cannot move directory because destination directory already exists: '{destDirPath}'"); + } + + DeleteDirectory(destDirPath); + } + + Directory.CreateDirectory(destDirPath); + + foreach (var filePath in Directory.GetFiles(sourceDirPath)) + { + var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + File.Copy(filePath, destFilePath); + } + + foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); + } + } + + private static void RestoreDirContents( + string sourceDirPath, + string destDirPath) + { + if (!Directory.Exists(destDirPath)) + { + Directory.CreateDirectory(destDirPath); + } + + foreach (string filePath in Directory.GetFiles(sourceDirPath)) + { + string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + if (!File.Exists(destFilePath)) + { + File.Copy(filePath, destFilePath); + } + } + + foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + RestoreDirContents(srcSubDirPath, destSubDirPath); + } + } + + #endregion + } +} From b987ebd6ff683ae9c275ff81c48eb5c6191cf2e7 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 17 Nov 2021 16:23:38 -0800 Subject: [PATCH 103/276] More code clean up for next release (#548) --- src/code/FindHelper.cs | 3 +- src/code/PSResourceInfo.cs | 88 +++++++++++----------------------- src/code/RepositorySettings.cs | 51 +++++++++++--------- src/code/Utils.cs | 22 ++++----- 4 files changed, 69 insertions(+), 95 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 143590345..d126df242 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -247,7 +247,8 @@ private IEnumerable SearchFromRepository( resourceSearch = repository.GetResourceAsync().GetAwaiter().GetResult(); resourceMetadata = repository.GetResourceAsync().GetAwaiter().GetResult(); } - catch (Exception e){ + catch (Exception e) + { Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "Error retrieving resource from repository: " + e.Message); } diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index 5d681825c..483662a1a 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -1,17 +1,16 @@ -using System.Text.RegularExpressions; -using System.Linq; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using NuGet.Versioning; +using NuGet.Protocol.Core.Types; using System; using System.Collections; using System.Collections.Generic; -using Dbg = System.Diagnostics.Debug; using System.Globalization; +using System.Linq; using System.Management.Automation; -using NuGet.Packaging; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; + +using Dbg = System.Diagnostics.Debug; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -20,9 +19,6 @@ namespace Microsoft.PowerShell.PowerShellGet.UtilClasses [Flags] public enum ResourceType { - // 00001 -> M - // 00100 -> C - // 00101 -> M, C None = 0x0, Module = 0x1, Script = 0x2, @@ -204,18 +200,18 @@ public sealed class PSCommandResourceInfo { // this object will represent a Command or DSCResource // included by the PSResourceInfo property - #region Properties + public string Name { get; } public PSResourceInfo ParentResource { get; } + #endregion #region Constructor /// /// Constructor - /// /// /// Name of the command or DSC resource /// the parent module resource the command or dsc resource belongs to @@ -325,6 +321,7 @@ private PSResourceInfo( #endregion #region Private fields + private static readonly char[] Delimeter = {' ', ','}; #endregion @@ -498,7 +495,6 @@ private static Version GetVersionInfo( return GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); } - public static bool TryConvert( IPackageSearchMetadata metadataToParse, out PSResourceInfo psGetInfo, @@ -620,38 +616,11 @@ private static T GetProperty( } } - private static string GetPrereleaseLabel(Version version) - { - string versionAsString = version.ToString(); - - if (!versionAsString.Contains("-")) - { - // no prerelease label present - return String.Empty; - } - - string[] prereleaseParsed = versionAsString.Split('-'); - if (prereleaseParsed.Length <= 1) - { - return String.Empty; - } - - string prereleaseString = prereleaseParsed[1]; - Regex prereleasePattern = new Regex("^[a-zA-Z0-9]+$"); - if (!prereleasePattern.IsMatch(prereleaseString)) - { - return String.Empty; - } - - return prereleaseString; - } - private static Dependency[] GetDependencies(ArrayList dependencyInfos) { List dependenciesFound = new List(); if (dependencyInfos == null) { return dependenciesFound.ToArray(); } - foreach(PSObject dependencyObj in dependencyInfos) { // The dependency object can be a string or a hashtable @@ -734,14 +703,12 @@ private static Dependency[] GetDependencies(ArrayList dependencyInfos) else if (dependencyObj.Properties["Name"] != null) { string name = dependencyObj.Properties["Name"].Value.ToString(); - - string version = string.Empty; VersionRange versionRange = VersionRange.All; - if (dependencyObj.Properties["VersionRange"] != null) { - version = dependencyObj.Properties["VersionRange"].Value.ToString(); - VersionRange.TryParse(version, out versionRange); + VersionRange.TryParse( + dependencyObj.Properties["VersionRange"].Value.ToString(), + out versionRange); } dependenciesFound.Add(new Dependency(name, versionRange)); @@ -756,7 +723,6 @@ private static string ConcatenateVersionWithPrerelease(string version, string pr return Utils.GetNormalizedVersionString(version, prerelease); } - #region Parse Metadata private static methods private static string ParseMetadataAuthor(IPackageSearchMetadata pkg) @@ -782,10 +748,11 @@ private static Dependency[] ParseMetadataDependencies(IPackageSearchMetadata pkg depVersionRange = pkgDependencyItem.VersionRange; } - Dependency currentDependency = new Dependency(pkgDependencyItem.Id, depVersionRange); - dependencies.Add(currentDependency); + dependencies.Add( + new Dependency(pkgDependencyItem.Id, depVersionRange)); } } + return dependencies.ToArray(); } @@ -828,13 +795,12 @@ private static Uri ParseMetadataProjectUri(IPackageSearchMetadata pkg) private static DateTime? ParseMetadataPublishedDate(IPackageSearchMetadata pkg) { - DateTime? publishDate = null; - DateTimeOffset? pkgPublishedDate = pkg.Published; - if (pkgPublishedDate.HasValue) + if (pkg.Published.HasValue) { - publishDate = pkgPublishedDate.Value.DateTime; + return pkg.Published.Value.DateTime; } - return publishDate; + + return null; } private static string[] ParseMetadataTags(IPackageSearchMetadata pkg) @@ -842,11 +808,12 @@ private static string[] ParseMetadataTags(IPackageSearchMetadata pkg) return pkg.Tags.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); } - private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, - string repoName, - ResourceType? pkgType, - out ArrayList commandNames, - out ArrayList dscResourceNames) + private static ResourceType ParseMetadataType( + IPackageSearchMetadata pkg, + string repoName, + ResourceType? pkgType, + out ArrayList commandNames, + out ArrayList dscResourceNames) { // possible type combinations: // M, C @@ -875,7 +842,7 @@ private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, // if Name contains wildcard, currently Script and Module tags should be set properly, but need to account for Command and DscResource types too // if Name does not contain wildcard, GetMetadataAsync() was used, PSGallery only is searched (and pkg will successfully be found // and returned from there) before PSGalleryScripts can be searched - foreach(string tag in tags) + foreach (string tag in tags) { if(String.Equals(tag, "PSScript", StringComparison.InvariantCultureIgnoreCase)) { @@ -883,11 +850,13 @@ private static ResourceType ParseMetadataType(IPackageSearchMetadata pkg, currentPkgType &= ~ResourceType.Module; currentPkgType |= ResourceType.Script; } + if (tag.StartsWith("PSCommand_", StringComparison.InvariantCultureIgnoreCase)) { currentPkgType |= ResourceType.Command; commandNames.Add(tag.Split('_')[1]); } + if (tag.StartsWith("PSDscResource_", StringComparison.InvariantCultureIgnoreCase)) { currentPkgType |= ResourceType.DscResource; @@ -904,6 +873,7 @@ private static Version ParseMetadataVersion(IPackageSearchMetadata pkg) { return pkg.Identity.Version.Version; } + return null; } @@ -999,7 +969,7 @@ public static void WritePSGetResourceInfo( { if (psObjectGetInfo.BaseObject is PSResourceInfo psGetInfo) { - if (! psGetInfo.TryWrite(filePath, out string errorMsg)) + if (!psGetInfo.TryWrite(filePath, out string errorMsg)) { throw new PSInvalidOperationException(errorMsg); } diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 511c9d651..a51ab4416 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -7,17 +7,15 @@ using System.IO; using System.Linq; using System.Management.Automation; +using System.Xml; using System.Xml.Linq; -using Dbg = System.Diagnostics.Debug; - namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { /// /// The class contains basic information of a repository path settings as well as methods to - /// perform CRUD operations on the repository store file. + /// perform Create/Read/Update/Delete operations on the repository store file. /// - internal static class RepositorySettings { #region Members @@ -52,8 +50,7 @@ public static void CheckRepositoryStore() } XDocument newRepoXML = new XDocument( - new XElement("configuration") - ); + new XElement("configuration")); newRepoXML.Save(FullRepositoryPath); } catch (Exception e) @@ -69,7 +66,7 @@ public static void CheckRepositoryStore() // Open file (which should exist now), if cannot/is corrupted then throw error try { - XDocument.Load(FullRepositoryPath); + LoadXDocument(FullRepositoryPath); } catch (Exception e) { @@ -84,13 +81,10 @@ public static void CheckRepositoryStore() /// public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriority, bool repoTrusted) { - Dbg.Assert(!string.IsNullOrEmpty(repoName), "Repository name cannot be null or empty"); - Dbg.Assert(!string.IsNullOrEmpty(repoURL.ToString()), "Repository URL cannot be null or empty"); - try { // Open file - XDocument doc = XDocument.Load(FullRepositoryPath); + XDocument doc = LoadXDocument(FullRepositoryPath); if (FindRepositoryElement(doc, repoName) != null) { throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); @@ -128,13 +122,11 @@ public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriorit /// public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted) { - Dbg.Assert(!string.IsNullOrEmpty(repoName), "Repository name cannot be null or empty"); - PSRepositoryInfo updatedRepo; try { // Open file - XDocument doc = XDocument.Load(FullRepositoryPath); + XDocument doc = LoadXDocument(FullRepositoryPath); XElement node = FindRepositoryElement(doc, repoName); if (node == null) { @@ -196,18 +188,11 @@ public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPrio public static void Remove(string[] repoNames, out string[] errorList) { List tempErrorList = new List(); - - // Check to see if information we're trying to remove from the repository is valid - if (repoNames == null || repoNames.Length == 0) - { - throw new ArgumentException("Repository name cannot be null or empty"); - } - XDocument doc; try { // Open file - doc = XDocument.Load(FullRepositoryPath); + doc = LoadXDocument(FullRepositoryPath); } catch (Exception e) { @@ -244,7 +229,7 @@ public static List Read(string[] repoNames, out string[] error try { // Open file - doc = XDocument.Load(FullRepositoryPath); + doc = LoadXDocument(FullRepositoryPath); } catch (Exception e) { @@ -323,6 +308,26 @@ private static XElement FindRepositoryElement(XDocument doc, string name) StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } + private static readonly XmlReaderSettings XDocReaderSettings = new XmlReaderSettings() + { + DtdProcessing = DtdProcessing.Prohibit, // Disallow any DTD elements + XmlResolver = null, // Do not resolve external links + CheckCharacters = true, + IgnoreComments = true, + IgnoreProcessingInstructions = true, + IgnoreWhitespace = true, + MaxCharactersFromEntities = 1024, + MaxCharactersInDocument = 512 * 1024 * 1024, // 512M characters = 1GB + ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.None, + ValidationType = ValidationType.None + }; + + private static XDocument LoadXDocument(string filePath) + { + using var xmlReader = XmlReader.Create(filePath, XDocReaderSettings); + return XDocument.Load(xmlReader); + } + #endregion } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 307d5569a..6d6496fdb 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using NuGet.Versioning; using System; using System.Collections; using System.Collections.Generic; @@ -9,7 +10,6 @@ using System.Management.Automation; using System.Management.Automation.Language; using System.Runtime.InteropServices; -using NuGet.Versioning; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -138,7 +138,6 @@ public static string GetNormalizedVersionString( // versionString: "1.2.0" prerelease: "alpha1" return versionString + "-" + prerelease; } - else if (numVersionDigits == 4) { // versionString: "1.2.0.0" prerelease: "alpha1" @@ -229,8 +228,7 @@ public static bool TryCreateValidUrl( string uriString, PSCmdlet cmdletPassedIn, out Uri uriResult, - out ErrorRecord errorRecord - ) + out ErrorRecord errorRecord) { errorRecord = null; if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) @@ -241,7 +239,7 @@ out ErrorRecord errorRecord Exception ex; try { - // This is needed for a relative path urlstring. Does not throw error for an absolute path + // This is needed for a relative path urlstring. Does not throw error for an absolute path. var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) { @@ -306,12 +304,10 @@ public static string GetInstalledPackageName(string pkgPath) // ex: ./PowerShell/Scripts/TestScript.ps1 return Path.GetFileNameWithoutExtension(pkgPath); } - else - { - // expecting the full version module path - // ex: ./PowerShell/Modules/TestModule/1.0.0 - return new DirectoryInfo(pkgPath).Parent.Name; - } + + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; } public static List GetAllResourcePaths( @@ -388,7 +384,9 @@ public static List GetAllResourcePaths( } // Find all potential installation paths given a scope - public static List GetAllInstallationPaths(PSCmdlet psCmdlet, ScopeType scope) + public static List GetAllInstallationPaths( + PSCmdlet psCmdlet, + ScopeType scope) { GetStandardPlatformPaths( psCmdlet, From 7f73be8f167d420631859173086a83bfa561e2e9 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 29 Nov 2021 09:29:19 -0800 Subject: [PATCH 104/276] Add -SkipDependencyCheck to cmdlets. (#550) * Add -SkipDependencyCheck to install/save/update cmdlets * Change -Force to -SkipDependencyCheck * Fix tests --- src/code/InstallHelper.cs | 13 ++++++++--- src/code/InstallPSResource.cs | 9 +++++++- src/code/SavePSResource.cs | 10 ++++++++- src/code/UninstallPSResource.cs | 36 +++++++++++++++++------------- src/code/UpdatePSResource.cs | 10 ++++++++- test/InstallPSResource.Tests.ps1 | 21 ++++++++++++----- test/SavePSResource.Tests.ps1 | 7 ++++++ test/UninstallPSResource.Tests.ps1 | 29 ++++++++++++------------ 8 files changed, 93 insertions(+), 42 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index a08011eff..c68ce4529 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -79,6 +79,7 @@ public void InstallPackages( string specifiedPath, bool asNupkg, bool includeXML, + bool skipDependencyCheck, List pathsToInstallPkg) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + @@ -123,7 +124,12 @@ public void InstallPackages( } // Go through the repositories and see which is the first repository to have the pkg version available - ProcessRepositories(names, repository, _trustRepository, _credential); + ProcessRepositories( + packageNames: names, + repository: repository, + trustRepository: _trustRepository, + credential: _credential, + skipDependencyCheck: skipDependencyCheck); } #endregion @@ -135,7 +141,8 @@ private void ProcessRepositories( string[] packageNames, string[] repository, bool trustRepository, - PSCredential credential) + PSCredential credential, + bool skipDependencyCheck) { var listOfRepositories = RepositorySettings.Read(repository, out string[] _); List pckgNamesToInstall = packageNames.ToList(); @@ -185,7 +192,7 @@ private void ProcessRepositories( tag: null, repository: new string[] { repoName }, credential: credential, - includeDependencies: true); + includeDependencies: !skipDependencyCheck); if (!pkgsFromRepoToInstall.Any()) { diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index d08c42efd..71a529901 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -15,7 +15,6 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// The Install-PSResource cmdlet installs a resource. /// It returns nothing. /// - [Cmdlet(VerbsLifecycle.Install, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] public sealed class InstallPSResource : PSCmdlet @@ -106,6 +105,13 @@ class InstallPSResource : PSCmdlet [ValidateNotNullOrEmpty] public PSResourceInfo InputObject { get; set; } + /// + /// Skips the check for resource dependencies, so that only found resources are installed, + /// and not any resources the found resource depends on. + /// + [Parameter] + public SwitchParameter SkipDependencyCheck { get; set; } + #endregion #region Members @@ -250,6 +256,7 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[ specifiedPath: null, asNupkg: false, includeXML: true, + skipDependencyCheck: SkipDependencyCheck, pathsToInstallPkg: _pathsToInstallPkg); } diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 64e9e98bc..d2b31d9c0 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -123,6 +123,13 @@ public string Path [ValidateNotNullOrEmpty] public PSResourceInfo InputObject { get; set; } + /// + /// Skips the check for resource dependencies, so that only found resources are saved, + /// and not any resources the found resource depends on. + /// + [Parameter] + public SwitchParameter SkipDependencyCheck { get; set; } + #endregion #region Method overrides @@ -243,7 +250,8 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p noClobber: false, specifiedPath: _path, asNupkg: false, - includeXML: false, + includeXML: false, + skipDependencyCheck: SkipDependencyCheck, pathsToInstallPkg: new List { _path } ); } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 4c2be49d9..05aa4e886 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -43,10 +43,10 @@ public sealed class UninstallPSResource : PSCmdlet public PSResourceInfo InputObject { get; set; } /// + /// Skips check to see if other resources are dependent on the resource being uninstalled. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter Force { get; set; } + [Parameter] + public SwitchParameter SkipDependencyCheck { get; set; } #endregion @@ -212,9 +212,9 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; - // if -Force is not specified and the pkg is a dependency for another package, + // if -SkipDependencyCheck is not specified and the pkg is a dependency for another package, // an error will be written and we return false - if (!Force && CheckIfDependency(pkgName, out errRecord)) + if (!SkipDependencyCheck && CheckIfDependency(pkgName, out errRecord)) { return false; } @@ -301,9 +301,8 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorReco return successfullyUninstalledPkg; } - private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) + private bool CheckIfDependency(string pkgName, out ErrorRecord errorRecord) { - errRecord = null; // this is a primitive implementation // TODO: implement a dependencies database for querying dependency info // cannot uninstall a module if another module is dependent on it @@ -317,18 +316,21 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) // RequiredModules is collection of PSModuleInfo objects that need to be iterated through to see if any of them are the pkg we're trying to uninstall // If we anything from the final call gets returned, there is a dependency on this pkg. IEnumerable pkgsWithRequiredModules = new List(); + errorRecord = null; try { pkgsWithRequiredModules = results.Where( - p => ((ReadOnlyCollection)p.Properties["RequiredModules"].Value).Where( + pkg => ((ReadOnlyCollection)pkg.Properties["RequiredModules"].Value).Where( rm => rm.Name.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)).Any()); } catch (Exception e) { - var exMessage = String.Format("Error checking if resource is a dependency: {0}. If you would still like to uninstall, rerun the command with -Force", e.Message); - var ex = new ArgumentException(exMessage); - var DependencyCheckError = new ErrorRecord(ex, "DependencyCheckError", ErrorCategory.OperationStopped, null); - errRecord = DependencyCheckError; + errorRecord = new ErrorRecord( + new PSInvalidOperationException( + $"Error checking if resource is a dependency: {e.Message}."), + "UninstallPSResourceDependencyCheckError", + ErrorCategory.InvalidOperation, + null); } if (pkgsWithRequiredModules.Any()) @@ -336,10 +338,12 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) var uniquePkgNames = pkgsWithRequiredModules.Select(p => p.Properties["Name"].Value).Distinct().ToArray(); var strUniquePkgNames = string.Join(",", uniquePkgNames); - var exMessage = String.Format("Cannot uninstall '{0}', the following package(s) take a dependency on this package: {1}. If you would still like to uninstall, rerun the command with -Force", pkgName, strUniquePkgNames); - var ex = new ArgumentException(exMessage); - var PackageIsaDependency = new ErrorRecord(ex, "PackageIsaDependency", ErrorCategory.OperationStopped, null); - errRecord = PackageIsaDependency; + errorRecord = new ErrorRecord( + new PSInvalidOperationException( + $"Cannot uninstall '{pkgName}'. The following package(s) take a dependency on this package: {strUniquePkgNames}. If you would still like to uninstall, rerun the command with -SkipDependencyCheck"), + "UninstallPSResourcePackageIsaDependency", + ErrorCategory.InvalidOperation, + null); return true; } diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 86b811888..ba4bec2b6 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -97,6 +97,13 @@ public sealed class UpdatePSResource : PSCmdlet [Parameter] public SwitchParameter Force { get; set; } + /// + /// Skips the check for resource dependencies, so that only found resources are updated, + /// and not any resources the found resource depends on. + /// + [Parameter] + public SwitchParameter SkipDependencyCheck { get; set; } + #endregion #region Override Methods @@ -166,6 +173,7 @@ protected override void ProcessRecord() specifiedPath: null, asNupkg: false, includeXML: true, + skipDependencyCheck: SkipDependencyCheck, pathsToInstallPkg: _pathsToInstallPkg); } @@ -253,7 +261,7 @@ private string[] ProcessPackageNames( tag: null, repository: Repository, credential: Credential, - includeDependencies: false)) + includeDependencies: !SkipDependencyCheck)) { if (!repositoryPackages.ContainsKey(foundResource.Name)) { diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 45d12d99f..5f9298991 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -17,7 +17,7 @@ Describe 'Test Install-PSResource for Module' { AfterEach { Uninstall-PSResource "TestModule", "TestModule99", "myTestModule", "myTestModule2", "testModulePrerelease", "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule","ClobberTestModule1", - "ClobberTestModule2" -Force -ErrorAction SilentlyContinue + "ClobberTestModule2" -SkipDependencyCheck -ErrorAction SilentlyContinue } AfterAll { @@ -103,14 +103,14 @@ Describe 'Test Install-PSResource for Module' { } It "Install resource when given Name, Version '*', should install the latest version" { - $pkg = Install-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName + Install-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" $pkg.Version | Should -Be "1.3.0" } It "Install resource with latest (including prerelease) version given Prerelease parameter" { - $pkg = Install-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName + Install-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName $pkg = Get-Module "TestModulePrerelease" -ListAvailable $pkg.Name | Should -Be "TestModulePrerelease" $pkg.Version | Should -Be "0.0.1" @@ -118,7 +118,7 @@ Describe 'Test Install-PSResource for Module' { } It "Install a module with a dependency" { - $pkg = Install-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName + Install-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName $pkg = Get-Module "PSGetTestModule" -ListAvailable $pkg.Name | Should -Be "PSGetTestModule" $pkg.Version | Should -Be "2.0.2" @@ -129,6 +129,17 @@ Describe 'Test Install-PSResource for Module' { $pkg.Version | Should -Be "1.0.0" } + It "Install a module with a dependency and skip installing the dependency" { + Install-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -SkipDependencyCheck + $pkg = Get-Module "PSGetTestModule" -ListAvailable + $pkg.Name | Should -Be "PSGetTestModule" + $pkg.Version | Should -Be "2.0.2" + $pkg.PrivateData.PSData.Prerelease | Should -Be "-alpha1" + + $pkg = Get-Module "PSGetTestDependency1" -ListAvailable + $pkg | Should -BeNullOrEmpty + } + It "Install resource via InputObject by piping from Find-PSresource" { Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Install-PSResource $pkg = Get-Module "TestModule" -ListAvailable @@ -309,7 +320,7 @@ Describe 'Test Install-PSResource for interactive and root user scenarios' { } AfterEach { - Uninstall-PSResource "TestModule", "testModuleWithlicense" -Force -ErrorAction SilentlyContinue + Uninstall-PSResource "TestModule", "testModuleWithlicense" -SkipDependencyCheck -ErrorAction SilentlyContinue } AfterAll { diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 910597f7e..59b1f7d43 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -129,6 +129,13 @@ Describe 'Test Save-PSResource for PSResources' { (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 } + It "Save a module with a dependency and skip saving the dependency" { + Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir -SkipDependencyCheck + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } + $pkgDirs.Count | Should -Be 1 + (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 + } + It "Save resource via InputObject by piping from Find-PSresource" { Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index c5b23a9c7..94acd9947 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -11,7 +11,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $testModuleName = "test_module" $testScriptName = "test_script" Get-NewPSResourceRepositoryFile - $res = Uninstall-PSResource -name ContosoServer -Version "*" + Uninstall-PSResource -name ContosoServer -Version "*" } BeforeEach{ $null = Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue @@ -21,7 +21,7 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall a specific module by name" { - $res = Uninstall-PSResource -name ContosoServer + Uninstall-PSResource -name ContosoServer Get-Module ContosoServer -ListAvailable | Should -Be $null } @@ -38,20 +38,20 @@ Describe 'Test Uninstall-PSResource for Modules' { It "Uninstall a list of modules by name" { $null = Install-PSResource BaseTestPackage -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - $res = Uninstall-PSResource -Name BaseTestPackage, ContosoServer + Uninstall-PSResource -Name BaseTestPackage, ContosoServer Get-Module ContosoServer, BaseTestPackage -ListAvailable | Should -be $null } It "Uninstall a specific script by name" { $null = Install-PSResource Test-RPC -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - $pkg = Uninstall-PSResource -name Test-RPC + Uninstall-PSResource -name Test-RPC } It "Uninstall a list of scripts by name" { $null = Install-PSResource adsql, airoute -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - $pkg = Uninstall-PSResource -Name adsql, airoute + Uninstall-PSResource -Name adsql, airoute } It "Uninstall a module when given name and specifying all versions" { @@ -59,7 +59,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - $res = Uninstall-PSResource -Name ContosoServer -version "*" + Uninstall-PSResource -Name ContosoServer -version "*" $pkgs = Get-Module ContosoServer -ListAvailable $pkgs.Version | Should -Not -Contain "1.0.0" $pkgs.Version | Should -Not -Contain "1.5.0" @@ -72,7 +72,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - $res = Uninstall-PSResource -Name ContosoServer + Uninstall-PSResource -Name ContosoServer $pkgs = Get-Module ContosoServer -ListAvailable $pkgs.Version | Should -Not -Contain "1.0.0" $pkgs.Version | Should -Not -Contain "1.5.0" @@ -85,7 +85,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - $res = Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" + Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" $pkgs = Get-Module ContosoServer -ListAvailable $pkgs.Version | Should -Not -Contain "1.0.0" } @@ -106,7 +106,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - $res = Uninstall-PSResource -Name ContosoServer -Version $Version + Uninstall-PSResource -Name ContosoServer -Version $Version $pkgs = Get-Module ContosoServer -ListAvailable $pkgs.Version | Should -Not -Contain $Version } @@ -169,8 +169,7 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall module using -WhatIf, should not uninstall the module" { - $res = Uninstall-PSResource -Name "ContosoServer" -WhatIf - + Uninstall-PSResource -Name "ContosoServer" -WhatIf $pkg = Get-Module ContosoServer -ListAvailable $pkg.Version | Should -Be "2.5" } @@ -183,16 +182,16 @@ Describe 'Test Uninstall-PSResource for Modules' { $pkg = Get-Module "RequiredModule1" -ListAvailable $pkg | Should -Not -Be $null - $ev | Should -Be "Cannot uninstall 'RequiredModule1', the following package(s) take a dependency on this package: test_module. If you would still like to uninstall, rerun the command with -Force" + $ev.FullyQualifiedErrorId | Should -BeExactly 'UninstallPSResourcePackageIsaDependency,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource' } - It "Uninstall module that is a dependency for another module using -Force" { + It "Uninstall module that is a dependency for another module using -SkipDependencyCheck" { $null = Install-PSResource "test_module" -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - $res = Uninstall-PSResource -Name "RequiredModule1" -Force + Uninstall-PSResource -Name "RequiredModule1" -SkipDependencyCheck $pkg = Get-Module "RequiredModule1" -ListAvailable - $pkg | Should -Be $null + $pkg | Should -BeNullOrEmpty } It "Uninstall PSResourceInfo object piped in" { From 1d216e1b7d6fb7309b3382097bebe5b88eb3c6d7 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 30 Nov 2021 17:04:08 -0500 Subject: [PATCH 105/276] Implement Progress Bar for Install (#552) Add progress bar for install --- src/code/InstallHelper.cs | 84 +++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index c68ce4529..c92ca4f56 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -145,7 +145,7 @@ private void ProcessRepositories( bool skipDependencyCheck) { var listOfRepositories = RepositorySettings.Read(repository, out string[] _); - List pckgNamesToInstall = packageNames.ToList(); + List pkgNamesToInstall = packageNames.ToList(); var yesToAll = false; var noToAll = false; @@ -153,7 +153,7 @@ private void ProcessRepositories( foreach (var repo in listOfRepositories) { // If no more packages to install, then return - if (!pckgNamesToInstall.Any()) return; + if (!pkgNamesToInstall.Any()) return; string repoName = repo.Name; _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); @@ -185,7 +185,7 @@ private void ProcessRepositories( // Finds parent packages and dependencies IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( - name: pckgNamesToInstall.ToArray(), + name: pkgNamesToInstall.ToArray(), type: ResourceType.None, version: _versionRange != null ? _versionRange.OriginalString : null, prerelease: _prerelease, @@ -225,14 +225,14 @@ private void ProcessRepositories( List pkgsInstalled = InstallPackage( pkgsFromRepoToInstall, - repoName, + pkgNamesToInstall, repo.Url.AbsoluteUri, credential, isLocalRepo); foreach (string name in pkgsInstalled) { - pckgNamesToInstall.Remove(name); + pkgNamesToInstall.Remove(name); } } } @@ -286,15 +286,26 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable InstallPackage( - IEnumerable pkgsToInstall, - string repoName, + IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) + List pkgNamesToInstall, // those requested by the user to be installed string repoUrl, PSCredential credential, bool isLocalRepo) { List pkgsSuccessfullyInstalled = new List(); - foreach (PSResourceInfo pkgInfo in pkgsToInstall) + int totalPkgs = pkgsToInstall.Count(); + + // counters for tracking dependent package and current package out of total + int totalPkgsCount = 0; + int dependentPkgCount = 1; + // by default this is 1, because if a parent package was already installed and only the dependent package + // needs to be installed we don't want a default value of 0 which throws a division error. + // if parent package isn't already installed we'll set this value properly in the below if condition anyways + int currentPkgNumOfDependentPkgs = 1; + + foreach (PSResourceInfo pkg in pkgsToInstall) { + totalPkgsCount++; var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try { @@ -307,24 +318,47 @@ private List InstallPackage( // TODO: are there Linux accommodations we need to consider here? dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; - _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkgInfo.Name)); + _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkg.Name)); + + int activityId = 0; + string activity = ""; + string statusDescription = ""; + + if (pkgNamesToInstall.ToList().Contains(pkg.Name, StringComparer.InvariantCultureIgnoreCase)) + { + // Installing parent package (one whose name was passed in to install) + activityId = 0; + activity = string.Format("Installing {0}...", pkg.Name); + statusDescription = string.Format("{0}% Complete:", Math.Round(((double) totalPkgsCount/totalPkgs) * 100), 2); + currentPkgNumOfDependentPkgs = pkg.Dependencies.Count(); + dependentPkgCount = 1; + } + else + { + // Installing dependent package + activityId = 1; + activity = string.Format("Installing dependent package {0}...", pkg.Name); + statusDescription = string.Format("{0}% Complete:", Math.Round(((double) dependentPkgCount/currentPkgNumOfDependentPkgs) * 100), 2); + dependentPkgCount++; + } - // TODO: add progress bar here - + var progressRecord = new ProgressRecord(activityId, activity, statusDescription); + _cmdletPassedIn.WriteProgress(progressRecord); + // Create PackageIdentity in order to download - string createFullVersion = pkgInfo.Version.ToString(); - if (pkgInfo.IsPrerelease) + string createFullVersion = pkg.Version.ToString(); + if (pkg.IsPrerelease) { - createFullVersion = pkgInfo.Version.ToString() + "-" + pkgInfo.PrereleaseLabel; + createFullVersion = pkg.Version.ToString() + "-" + pkg.PrereleaseLabel; } if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) { _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", - pkgInfo.Name, pkgInfo.Version.ToString())); + pkg.Name, pkg.Version.ToString())); continue; } - var pkgIdentity = new PackageIdentity(pkgInfo.Name, pkgVersion); + var pkgIdentity = new PackageIdentity(pkg.Name, pkgVersion); var cacheContext = new SourceCacheContext(); if (isLocalRepo) @@ -419,8 +453,8 @@ private List InstallPackage( string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); string moduleManifestVersion = string.Empty; - var scriptPath = Path.Combine(tempDirNameVersion, pkgInfo.Name + ".ps1"); - var modulePath = Path.Combine(tempDirNameVersion, pkgInfo.Name + ".psd1"); + var scriptPath = Path.Combine(tempDirNameVersion, pkg.Name + ".ps1"); + var modulePath = Path.Combine(tempDirNameVersion, pkg.Name + ".psd1"); // Check if the package is a module or a script var isModule = File.Exists(modulePath); @@ -446,13 +480,13 @@ private List InstallPackage( moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; // Accept License verification - if (!_savePkg && !CallAcceptLicense(pkgInfo, moduleManifest, tempInstallPath, newVersion)) + if (!_savePkg && !CallAcceptLicense(pkg, moduleManifest, tempInstallPath, newVersion)) { continue; } // If NoClobber is specified, ensure command clobbering does not happen - if (_noClobber && !DetectClobber(pkgInfo.Name, parsedMetadataHashtable)) + if (_noClobber && !DetectClobber(pkg.Name, parsedMetadataHashtable)) { continue; } @@ -478,11 +512,11 @@ private List InstallPackage( if (_includeXML) { - CreateMetadataXMLFile(tempDirNameVersion, installPath, pkgInfo, isModule); + CreateMetadataXMLFile(tempDirNameVersion, installPath, pkg, isModule); } MoveFilesIntoInstallPath( - pkgInfo, + pkg, isModule, isLocalRepo, tempDirNameVersion, @@ -492,15 +526,15 @@ private List InstallPackage( moduleManifestVersion, scriptPath); - _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkgInfo.Name, installPath)); - pkgsSuccessfullyInstalled.Add(pkgInfo.Name); + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkg.Name, installPath)); + pkgsSuccessfullyInstalled.Add(pkg.Name); } catch (Exception e) { _cmdletPassedIn.WriteError( new ErrorRecord( new PSInvalidOperationException( - message: $"Unable to successfully install package '{pkgInfo.Name}': '{e.Message}'", + message: $"Unable to successfully install package '{pkg.Name}': '{e.Message}'", innerException: e), "InstallPackageFailed", ErrorCategory.InvalidOperation, From 26866ac154a7879994c1caa31c307468aefb8685 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 30 Nov 2021 15:15:43 -0800 Subject: [PATCH 106/276] Bug fix for Publish-PSResource deleting a temp dir that contains a readonly file (#543) --- src/code/PublishPSResource.cs | 1 + src/code/Utils.cs | 1325 +++++++++++++++--------------- test/PublishPSResource.Tests.ps1 | 15 + 3 files changed, 681 insertions(+), 660 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 8f29930a0..1797eccd8 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -408,6 +408,7 @@ protected override void ProcessRecord() finally { WriteVerbose(string.Format("Deleting temporary directory '{0}'", outputDir)); + Utils.DeleteDirectory(outputDir); } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 6d6496fdb..2b5e5b9aa 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,660 +1,665 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using NuGet.Versioning; -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Runtime.InteropServices; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - internal static class Utils - { - #region String fields - - public static readonly string[] EmptyStrArray = Array.Empty(); - - #endregion - - #region String methods - - public static string TrimQuotes(string name) - { - return name.Trim('\'', '"'); - } - - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) - { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } - } - - if (!quotesNeeded) - { - return name; - } - - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i < list.Count; i++) - { - strArray[i] = list[i] as string; - } - - return strArray; - } - - public static string[] ProcessNameWildcards( - string[] pkgNames, - out string[] errorMsgs, - out bool isContainWildcard) - { - List namesWithSupportedWildcards = new List(); - List errorMsgsList = new List(); - - if (pkgNames == null) - { - isContainWildcard = true; - errorMsgs = errorMsgsList.ToArray(); - return new string[] {"*"}; - } - - isContainWildcard = false; - foreach (string name in pkgNames) - { - if (WildcardPattern.ContainsWildcardCharacters(name)) - { - if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) - { - isContainWildcard = true; - errorMsgs = new string[] {}; - return new string[] {"*"}; - } - - if (name.Contains("?") || name.Contains("[")) - { - errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); - continue; - } - - isContainWildcard = true; - namesWithSupportedWildcards.Add(name); - } - else - { - namesWithSupportedWildcards.Add(name); - } - } - - errorMsgs = errorMsgsList.ToArray(); - return namesWithSupportedWildcards.ToArray(); - } - - #endregion - - #region Version methods - - public static string GetNormalizedVersionString( - string versionString, - string prerelease) - { - // versionString may be like 1.2.0.0 or 1.2.0 - // prerelease may be null or "alpha1" - // possible passed in examples: - // versionString: "1.2.0" prerelease: "alpha1" - // versionString: "1.2.0" prerelease: "" <- doubtful though - // versionString: "1.2.0.0" prerelease: "alpha1" - // versionString: "1.2.0.0" prerelease: "" - - if (String.IsNullOrEmpty(prerelease)) - { - return versionString; - } - - int numVersionDigits = versionString.Split('.').Count(); - - if (numVersionDigits == 3) - { - // versionString: "1.2.0" prerelease: "alpha1" - return versionString + "-" + prerelease; - } - else if (numVersionDigits == 4) - { - // versionString: "1.2.0.0" prerelease: "alpha1" - return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; - } - - return versionString; - } - - public static bool TryParseVersionOrVersionRange( - string version, - out VersionRange versionRange) - { - versionRange = null; - if (version == null) { return false; } - - if (version.Trim().Equals("*")) - { - versionRange = VersionRange.All; - return true; - } - - // parse as NuGetVersion - if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) - { - versionRange = new VersionRange( - minVersion: nugetVersion, - includeMinVersion: true, - maxVersion: nugetVersion, - includeMaxVersion: true, - floatRange: null, - originalString: version); - return true; - } - - // parse as Version range - return VersionRange.TryParse(version, out versionRange); - } - - public static bool GetVersionForInstallPath( - string installedPkgPath, - bool isModule, - PSCmdlet cmdletPassedIn, - out NuGetVersion pkgNuGetVersion) - { - // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file - // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. - // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current - // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. - - // for Modules, installedPkgPath will look like this: - // ./PowerShell/Modules/test_module/3.0.0 - // for Scripts, installedPkgPath will look like this: - // ./PowerShell/Scripts/test_script.ps1 - string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); - - string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); - if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - cmdletPassedIn.WriteVerbose(String.Format( - "The {0} file found at location: {1} cannot be parsed due to {2}", - isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", - packageInfoXMLFilePath, - errorMsg)); - pkgNuGetVersion = null; - return false; - } - - string version = psGetInfo.Version.ToString(); - string prereleaseLabel = psGetInfo.PrereleaseLabel; - - if (!NuGetVersion.TryParse( - value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), - version: out pkgNuGetVersion)) - { - cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); - return false; - } - - return true; - } - - #endregion - - #region Url methods - - public static bool TryCreateValidUrl( - string uriString, - PSCmdlet cmdletPassedIn, - out Uri uriResult, - out ErrorRecord errorRecord) - { - errorRecord = null; - if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) - { - return true; - } - - Exception ex; - try - { - // This is needed for a relative path urlstring. Does not throw error for an absolute path. - var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; - if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) - { - return true; - } - - ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); - } - catch (Exception e) - { - ex = e; - } - - errorRecord = new ErrorRecord( - new PSArgumentException( - $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", - ex), - "InvalidUri", - ErrorCategory.InvalidArgument, - cmdletPassedIn); - - return false; - } - - #endregion - - #region Path methods - - public static string[] GetSubDirectories(string dirPath) - { - try - { - return Directory.GetDirectories(dirPath); - } - catch - { - return EmptyStrArray; - } - } - - public static string[] GetDirectoryFiles(string dirPath) - { - try - { - return Directory.GetFiles(dirPath); - } - catch - { - return EmptyStrArray; - } - } - - public static string GetInstalledPackageName(string pkgPath) - { - if (string.IsNullOrEmpty(pkgPath)) - { - return string.Empty; - } - - if (File.Exists(pkgPath)) - { - // ex: ./PowerShell/Scripts/TestScript.ps1 - return Path.GetFileNameWithoutExtension(pkgPath); - } - - // expecting the full version module path - // ex: ./PowerShell/Modules/TestModule/1.0.0 - return new DirectoryInfo(pkgPath).Parent.Name; - } - - public static List GetAllResourcePaths( - PSCmdlet psCmdlet, - ScopeType? scope = null) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - List resourcePaths = new List(); - - // Path search order is PSModulePath paths first, then default paths. - if (scope is null) - { - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - resourcePaths.AddRange(psModulePath.Split(Path.PathSeparator).ToList()); - } - - if (scope is null || scope.Value is ScopeType.CurrentUser) - { - resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); - } - - if (scope is null || scope.Value is ScopeType.AllUsers) - { - resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); - } - - // resourcePaths should now contain, eg: - // ./PowerShell/Scripts - // ./PowerShell/Modules - // add all module directories or script files - List pathsToSearch = new List(); - foreach (string path in resourcePaths) - { - psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); - - if (path.EndsWith("Scripts")) - { - try - { - pathsToSearch.AddRange(GetDirectoryFiles(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); - } - } - else - { - try - { - pathsToSearch.AddRange(GetSubDirectories(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); - } - } - } - - // resourcePaths should now contain eg: - // ./PowerShell/Scripts/Test-Script.ps1 - // ./PowerShell/Modules/TestModule - // need to use .ToList() to cast the IEnumerable to type List - pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); - - return pathsToSearch; - } - - // Find all potential installation paths given a scope - public static List GetAllInstallationPaths( - PSCmdlet psCmdlet, - ScopeType scope) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - // The default user scope is CurrentUser - var installationPaths = new List(); - if (scope == ScopeType.AllUsers) - { - installationPaths.Add(Path.Combine(programFilesPath, "Modules")); - installationPaths.Add(Path.Combine(programFilesPath, "Scripts")); - } - else - { - installationPaths.Add(Path.Combine(myDocumentsPath, "Modules")); - installationPaths.Add(Path.Combine(myDocumentsPath, "Scripts")); - } - - installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); - - return installationPaths; - } - - private readonly static Version PSVersion6 = new Version(6, 0); - private static void GetStandardPlatformPaths( - PSCmdlet psCmdlet, - out string myDocumentsPath, - out string programFilesPath) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; - myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and macOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); - programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); - } - } - - #endregion - - #region Manifest methods - - public static bool TryParseModuleManifest( - string moduleFileInfo, - PSCmdlet cmdletPassedIn, - out Hashtable parsedMetadataHashtable) - { - parsedMetadataHashtable = new Hashtable(); - bool successfullyParsed = false; - - // A script will already have the metadata parsed into the parsedMetadatahash, - // a module will still need the module manifest to be parsed. - if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) - { - // Parse the module manifest - var ast = Parser.ParseFile( - moduleFileInfo, - out Token[] tokens, - out ParseError[] errors); - - if (errors.Length > 0) - { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - return successfullyParsed; - } - else - { - var data = ast.Find(a => a is HashtableAst, false); - if (data != null) - { - parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); - successfullyParsed = true; - } - else - { - var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - } - } - } - - return successfullyParsed; - } - - #endregion - - #region Misc methods - - public static void WriteVerboseOnCmdlet( - PSCmdlet cmdlet, - string message) - { - try - { - cmdlet.InvokeCommand.InvokeScript( - script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { message }); - } - catch { } - } - - #endregion - - #region Directory and File - - /// - /// Deletes a directory and its contents. - /// Attempts to restore the directory and contents if deletion fails. - /// - public static void DeleteDirectoryWithRestore(string dirPath) - { - string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - - try - { - // Create temporary directory for restore operation if needed. - CopyDirContents(dirPath, tempDirPath, overwrite: true); - - try - { - DeleteDirectory(dirPath); - } - catch (Exception ex) - { - // Delete failed. Attempt to restore the saved directory content. - try - { - RestoreDirContents(tempDirPath, dirPath); - } - catch (Exception exx) - { - throw new PSInvalidOperationException( - $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", - ex); - } - - throw new PSInvalidOperationException( - $"Cannot remove package path {dirPath}. The previous package contents have been restored.", - ex); - } - } - finally - { - if (Directory.Exists(tempDirPath)) - { - DeleteDirectory(tempDirPath); - } - } - } - - /// - /// Deletes a directory and its contents - /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell - /// on OneDrive with 'access denied' error. - /// Later versions of .NET, with PowerShellCore, do not have this bug. - /// - public static void DeleteDirectory(string dirPath) - { - foreach (var dirFilePath in Directory.GetFiles(dirPath)) - { - File.Delete(dirFilePath); - } - - foreach (var dirSubPath in Directory.GetDirectories(dirPath)) - { - DeleteDirectory(dirSubPath); - } - - Directory.Delete(dirPath); - } - - /// - /// Moves files from source to destination locations. - /// This is a workaround for .NET File.Move(), which fails over different file volumes. - /// - public static void MoveFiles( - string sourceFilePath, - string destFilePath, - bool overwrite = true) - { - File.Copy(sourceFilePath, destFilePath, overwrite); - File.Delete(sourceFilePath); - } - - /// - /// Moves the directory, including contents, from source to destination locations. - /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. - /// - public static void MoveDirectory( - string sourceDirPath, - string destDirPath, - bool overwrite = true) - { - CopyDirContents(sourceDirPath, destDirPath, overwrite); - DeleteDirectory(sourceDirPath); - } - - private static void CopyDirContents( - string sourceDirPath, - string destDirPath, - bool overwrite) - { - if (Directory.Exists(destDirPath)) - { - if (!overwrite) - { - throw new PSInvalidOperationException( - $"Cannot move directory because destination directory already exists: '{destDirPath}'"); - } - - DeleteDirectory(destDirPath); - } - - Directory.CreateDirectory(destDirPath); - - foreach (var filePath in Directory.GetFiles(sourceDirPath)) - { - var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); - File.Copy(filePath, destFilePath); - } - - foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) - { - var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); - CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); - } - } - - private static void RestoreDirContents( - string sourceDirPath, - string destDirPath) - { - if (!Directory.Exists(destDirPath)) - { - Directory.CreateDirectory(destDirPath); - } - - foreach (string filePath in Directory.GetFiles(sourceDirPath)) - { - string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); - if (!File.Exists(destFilePath)) - { - File.Copy(filePath, destFilePath); - } - } - - foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) - { - string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); - RestoreDirContents(srcSubDirPath, destSubDirPath); - } - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using NuGet.Versioning; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Runtime.InteropServices; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + internal static class Utils + { + #region String fields + + public static readonly string[] EmptyStrArray = Array.Empty(); + + #endregion + + #region String methods + + public static string TrimQuotes(string name) + { + return name.Trim('\'', '"'); + } + + public static string QuoteName(string name) + { + bool quotesNeeded = false; + foreach (var c in name) + { + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } + } + + if (!quotesNeeded) + { + return name; + } + + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) + { + strArray[i] = list[i] as string; + } + + return strArray; + } + + public static string[] ProcessNameWildcards( + string[] pkgNames, + out string[] errorMsgs, + out bool isContainWildcard) + { + List namesWithSupportedWildcards = new List(); + List errorMsgsList = new List(); + + if (pkgNames == null) + { + isContainWildcard = true; + errorMsgs = errorMsgsList.ToArray(); + return new string[] {"*"}; + } + + isContainWildcard = false; + foreach (string name in pkgNames) + { + if (WildcardPattern.ContainsWildcardCharacters(name)) + { + if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) + { + isContainWildcard = true; + errorMsgs = new string[] {}; + return new string[] {"*"}; + } + + if (name.Contains("?") || name.Contains("[")) + { + errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); + continue; + } + + isContainWildcard = true; + namesWithSupportedWildcards.Add(name); + } + else + { + namesWithSupportedWildcards.Add(name); + } + } + + errorMsgs = errorMsgsList.ToArray(); + return namesWithSupportedWildcards.ToArray(); + } + + #endregion + + #region Version methods + + public static string GetNormalizedVersionString( + string versionString, + string prerelease) + { + // versionString may be like 1.2.0.0 or 1.2.0 + // prerelease may be null or "alpha1" + // possible passed in examples: + // versionString: "1.2.0" prerelease: "alpha1" + // versionString: "1.2.0" prerelease: "" <- doubtful though + // versionString: "1.2.0.0" prerelease: "alpha1" + // versionString: "1.2.0.0" prerelease: "" + + if (String.IsNullOrEmpty(prerelease)) + { + return versionString; + } + + int numVersionDigits = versionString.Split('.').Count(); + + if (numVersionDigits == 3) + { + // versionString: "1.2.0" prerelease: "alpha1" + return versionString + "-" + prerelease; + } + else if (numVersionDigits == 4) + { + // versionString: "1.2.0.0" prerelease: "alpha1" + return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; + } + + return versionString; + } + + public static bool TryParseVersionOrVersionRange( + string version, + out VersionRange versionRange) + { + versionRange = null; + if (version == null) { return false; } + + if (version.Trim().Equals("*")) + { + versionRange = VersionRange.All; + return true; + } + + // parse as NuGetVersion + if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) + { + versionRange = new VersionRange( + minVersion: nugetVersion, + includeMinVersion: true, + maxVersion: nugetVersion, + includeMaxVersion: true, + floatRange: null, + originalString: version); + return true; + } + + // parse as Version range + return VersionRange.TryParse(version, out versionRange); + } + + public static bool GetVersionForInstallPath( + string installedPkgPath, + bool isModule, + PSCmdlet cmdletPassedIn, + out NuGetVersion pkgNuGetVersion) + { + // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file + // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. + // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current + // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. + + // for Modules, installedPkgPath will look like this: + // ./PowerShell/Modules/test_module/3.0.0 + // for Scripts, installedPkgPath will look like this: + // ./PowerShell/Scripts/test_script.ps1 + string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); + + string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); + if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + cmdletPassedIn.WriteVerbose(String.Format( + "The {0} file found at location: {1} cannot be parsed due to {2}", + isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", + packageInfoXMLFilePath, + errorMsg)); + pkgNuGetVersion = null; + return false; + } + + string version = psGetInfo.Version.ToString(); + string prereleaseLabel = psGetInfo.PrereleaseLabel; + + if (!NuGetVersion.TryParse( + value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), + version: out pkgNuGetVersion)) + { + cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); + return false; + } + + return true; + } + + #endregion + + #region Url methods + + public static bool TryCreateValidUrl( + string uriString, + PSCmdlet cmdletPassedIn, + out Uri uriResult, + out ErrorRecord errorRecord) + { + errorRecord = null; + if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) + { + return true; + } + + Exception ex; + try + { + // This is needed for a relative path urlstring. Does not throw error for an absolute path. + var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; + if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) + { + return true; + } + + ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); + } + catch (Exception e) + { + ex = e; + } + + errorRecord = new ErrorRecord( + new PSArgumentException( + $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", + ex), + "InvalidUri", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; + } + + #endregion + + #region Path methods + + public static string[] GetSubDirectories(string dirPath) + { + try + { + return Directory.GetDirectories(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string[] GetDirectoryFiles(string dirPath) + { + try + { + return Directory.GetFiles(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string GetInstalledPackageName(string pkgPath) + { + if (string.IsNullOrEmpty(pkgPath)) + { + return string.Empty; + } + + if (File.Exists(pkgPath)) + { + // ex: ./PowerShell/Scripts/TestScript.ps1 + return Path.GetFileNameWithoutExtension(pkgPath); + } + + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; + } + + public static List GetAllResourcePaths( + PSCmdlet psCmdlet, + ScopeType? scope = null) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + + List resourcePaths = new List(); + + // Path search order is PSModulePath paths first, then default paths. + if (scope is null) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + resourcePaths.AddRange(psModulePath.Split(Path.PathSeparator).ToList()); + } + + if (scope is null || scope.Value is ScopeType.CurrentUser) + { + resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + } + + if (scope is null || scope.Value is ScopeType.AllUsers) + { + resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + + // resourcePaths should now contain, eg: + // ./PowerShell/Scripts + // ./PowerShell/Modules + // add all module directories or script files + List pathsToSearch = new List(); + foreach (string path in resourcePaths) + { + psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); + + if (path.EndsWith("Scripts")) + { + try + { + pathsToSearch.AddRange(GetDirectoryFiles(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); + } + } + else + { + try + { + pathsToSearch.AddRange(GetSubDirectories(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); + } + } + } + + // resourcePaths should now contain eg: + // ./PowerShell/Scripts/Test-Script.ps1 + // ./PowerShell/Modules/TestModule + // need to use .ToList() to cast the IEnumerable to type List + pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); + + return pathsToSearch; + } + + // Find all potential installation paths given a scope + public static List GetAllInstallationPaths( + PSCmdlet psCmdlet, + ScopeType scope) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + + // The default user scope is CurrentUser + var installationPaths = new List(); + if (scope == ScopeType.AllUsers) + { + installationPaths.Add(Path.Combine(programFilesPath, "Modules")); + installationPaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + else + { + installationPaths.Add(Path.Combine(myDocumentsPath, "Modules")); + installationPaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + } + + installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); + + return installationPaths; + } + + private readonly static Version PSVersion6 = new Version(6, 0); + private static void GetStandardPlatformPaths( + PSCmdlet psCmdlet, + out string myDocumentsPath, + out string programFilesPath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; + myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and macOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); + programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); + } + } + + #endregion + + #region Manifest methods + + public static bool TryParseModuleManifest( + string moduleFileInfo, + PSCmdlet cmdletPassedIn, + out Hashtable parsedMetadataHashtable) + { + parsedMetadataHashtable = new Hashtable(); + bool successfullyParsed = false; + + // A script will already have the metadata parsed into the parsedMetadatahash, + // a module will still need the module manifest to be parsed. + if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) + { + // Parse the module manifest + var ast = Parser.ParseFile( + moduleFileInfo, + out Token[] tokens, + out ParseError[] errors); + + if (errors.Length > 0) + { + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + return successfullyParsed; + } + else + { + var data = ast.Find(a => a is HashtableAst, false); + if (data != null) + { + parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); + successfullyParsed = true; + } + else + { + var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + } + } + } + + return successfullyParsed; + } + + #endregion + + #region Misc methods + + public static void WriteVerboseOnCmdlet( + PSCmdlet cmdlet, + string message) + { + try + { + cmdlet.InvokeCommand.InvokeScript( + script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { message }); + } + catch { } + } + + #endregion + + #region Directory and File + + /// + /// Deletes a directory and its contents. + /// Attempts to restore the directory and contents if deletion fails. + /// + public static void DeleteDirectoryWithRestore(string dirPath) + { + string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + + try + { + // Create temporary directory for restore operation if needed. + CopyDirContents(dirPath, tempDirPath, overwrite: true); + + try + { + DeleteDirectory(dirPath); + } + catch (Exception ex) + { + // Delete failed. Attempt to restore the saved directory content. + try + { + RestoreDirContents(tempDirPath, dirPath); + } + catch (Exception exx) + { + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", + ex); + } + + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. The previous package contents have been restored.", + ex); + } + } + finally + { + if (Directory.Exists(tempDirPath)) + { + DeleteDirectory(tempDirPath); + } + } + } + + /// + /// Deletes a directory and its contents + /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell + /// on OneDrive with 'access denied' error. + /// Later versions of .NET, with PowerShellCore, do not have this bug. + /// + public static void DeleteDirectory(string dirPath) + { + foreach (var dirFilePath in Directory.GetFiles(dirPath)) + { + if (File.GetAttributes(dirFilePath).HasFlag(FileAttributes.ReadOnly)) + { + File.SetAttributes(dirFilePath, (File.GetAttributes(dirFilePath) & ~FileAttributes.ReadOnly)); + } + + File.Delete(dirFilePath); + } + + foreach (var dirSubPath in Directory.GetDirectories(dirPath)) + { + DeleteDirectory(dirSubPath); + } + + Directory.Delete(dirPath); + } + + /// + /// Moves files from source to destination locations. + /// This is a workaround for .NET File.Move(), which fails over different file volumes. + /// + public static void MoveFiles( + string sourceFilePath, + string destFilePath, + bool overwrite = true) + { + File.Copy(sourceFilePath, destFilePath, overwrite); + File.Delete(sourceFilePath); + } + + /// + /// Moves the directory, including contents, from source to destination locations. + /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. + /// + public static void MoveDirectory( + string sourceDirPath, + string destDirPath, + bool overwrite = true) + { + CopyDirContents(sourceDirPath, destDirPath, overwrite); + DeleteDirectory(sourceDirPath); + } + + private static void CopyDirContents( + string sourceDirPath, + string destDirPath, + bool overwrite) + { + if (Directory.Exists(destDirPath)) + { + if (!overwrite) + { + throw new PSInvalidOperationException( + $"Cannot move directory because destination directory already exists: '{destDirPath}'"); + } + + DeleteDirectory(destDirPath); + } + + Directory.CreateDirectory(destDirPath); + + foreach (var filePath in Directory.GetFiles(sourceDirPath)) + { + var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + File.Copy(filePath, destFilePath); + } + + foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); + } + } + + private static void RestoreDirContents( + string sourceDirPath, + string destDirPath) + { + if (!Directory.Exists(destDirPath)) + { + Directory.CreateDirectory(destDirPath); + } + + foreach (string filePath in Directory.GetFiles(sourceDirPath)) + { + string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + if (!File.Exists(destFilePath)) + { + File.Copy(filePath, destFilePath); + } + } + + foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + RestoreDirContents(srcSubDirPath, destSubDirPath); + } + } + + #endregion + } +} diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 2a4feb5b2..d5a96b45b 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -278,4 +278,19 @@ Describe "Test Publish-PSResource" { $expectedPath = Join-Path -Path $tmpPath -ChildPath "$script:PublishModuleName.$version.nupkg" (Get-ChildItem $tmpPath).FullName | Should -Be $expectedPath } + + It "Publish a module and clean up properly when file in module is readonly" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + # Create a readonly file that will throw access denied error if deletion is attempted + $file = Join-Path -Path $script:PublishModuleBase -ChildPath "inaccessiblefile.txt" + New-Item $file -Itemtype file -Force + Set-ItemProperty -Path $file -Name IsReadOnly -Value $true + + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } } From 01aaf34e33354b4501e2d59fd93b4ad38e82b769 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 30 Nov 2021 15:56:14 -0800 Subject: [PATCH 107/276] Add -PassThru to Install-PSResource, Save-PSResource, and Update-PSResource (#540) --- src/code/InstallHelper.cs | 27 +- src/code/InstallPSResource.cs | 33 +- src/code/SavePSResource.cs | 534 +++++++++++---------- src/code/UpdatePSResource.cs | 658 +++++++++++++------------- test/GetInstalledPSResource.Tests.ps1 | 2 +- test/InstallPSResource.Tests.ps1 | 6 + test/SavePSResource.Tests.ps1 | 5 + test/UpdatePSResource.Tests.ps1 | 10 +- 8 files changed, 671 insertions(+), 604 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index c92ca4f56..fba72465e 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -64,7 +64,7 @@ public InstallHelper(bool savePkg, PSCmdlet cmdletPassedIn) _cmdletPassedIn = cmdletPassedIn; } - public void InstallPackages( + public List InstallPackages( string[] names, VersionRange versionRange, bool prerelease, @@ -83,7 +83,7 @@ public void InstallPackages( List pathsToInstallPkg) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}';", + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'", string.Join(",", names), versionRange != null ? versionRange.OriginalString : string.Empty, prerelease.ToString(), @@ -124,7 +124,7 @@ public void InstallPackages( } // Go through the repositories and see which is the first repository to have the pkg version available - ProcessRepositories( + return ProcessRepositories( packageNames: names, repository: repository, trustRepository: _trustRepository, @@ -137,7 +137,7 @@ public void InstallPackages( #region Private methods // This method calls iterates through repositories (by priority order) to search for the pkgs to install - private void ProcessRepositories( + private List ProcessRepositories( string[] packageNames, string[] repository, bool trustRepository, @@ -150,10 +150,11 @@ private void ProcessRepositories( var noToAll = false; var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); + List allPkgsInstalled = new List(); foreach (var repo in listOfRepositories) { // If no more packages to install, then return - if (!pkgNamesToInstall.Any()) return; + if (!pkgNamesToInstall.Any()) return allPkgsInstalled; string repoName = repo.Name; _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); @@ -223,18 +224,22 @@ private void ProcessRepositories( continue; } - List pkgsInstalled = InstallPackage( + List pkgsInstalled = InstallPackage( pkgsFromRepoToInstall, pkgNamesToInstall, repo.Url.AbsoluteUri, credential, isLocalRepo); - foreach (string name in pkgsInstalled) + foreach (PSResourceInfo pkg in pkgsInstalled) { - pkgNamesToInstall.Remove(name); + pkgNamesToInstall.Remove(pkg.Name); } + + allPkgsInstalled.AddRange(pkgsInstalled); } + + return allPkgsInstalled; } // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install @@ -285,14 +290,14 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable InstallPackage( + private List InstallPackage( IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) List pkgNamesToInstall, // those requested by the user to be installed string repoUrl, PSCredential credential, bool isLocalRepo) { - List pkgsSuccessfullyInstalled = new List(); + List pkgsSuccessfullyInstalled = new List(); int totalPkgs = pkgsToInstall.Count(); // counters for tracking dependent package and current package out of total @@ -527,7 +532,7 @@ private List InstallPackage( scriptPath); _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkg.Name, installPath)); - pkgsSuccessfullyInstalled.Add(pkg.Name); + pkgsSuccessfullyInstalled.Add(pkg); } catch (Exception e) { diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 71a529901..bdbbbdc5f 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -98,13 +98,6 @@ class InstallPSResource : PSCmdlet [Parameter(ParameterSetName = NameParameterSet)] public SwitchParameter NoClobber { get; set; } - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] - [ValidateNotNullOrEmpty] - public PSResourceInfo InputObject { get; set; } - /// /// Skips the check for resource dependencies, so that only found resources are installed, /// and not any resources the found resource depends on. @@ -112,6 +105,20 @@ class InstallPSResource : PSCmdlet [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } + /// + /// Passes the resource installed to the console. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter PassThru { get; set; } + + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public PSResourceInfo InputObject { get; set; } + #endregion #region Members @@ -241,7 +248,7 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[ return; } - _installHelper.InstallPackages( + var installedPkgs = _installHelper.InstallPackages( names: pkgNames, versionRange: _versionRange, prerelease: pkgPrerelease, @@ -257,7 +264,15 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[ asNupkg: false, includeXML: true, skipDependencyCheck: SkipDependencyCheck, - pathsToInstallPkg: _pathsToInstallPkg); + pathsToInstallPkg: _pathsToInstallPkg); + + if (PassThru) + { + foreach (PSResourceInfo pkg in installedPkgs) + { + WriteObject(pkg); + } + } } #endregion diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index d2b31d9c0..0c79420d2 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -1,260 +1,274 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using NuGet.Versioning; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; - -using Dbg = System.Diagnostics.Debug; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Save-PSResource cmdlet saves a resource to a machine. - /// It returns nothing. - /// - [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] - public sealed class SavePSResource : PSCmdlet - { - #region Members - - private const string NameParameterSet = "NameParameterSet"; - private const string InputObjectParameterSet = "InputObjectParameterSet"; - VersionRange _versionRange; - InstallHelper _installHelper; - - #endregion - - #region Parameters - - /// - /// Specifies the exact names of resources to save from a repository. - /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] - [ValidateNotNullOrEmpty] - public string[] Name { get; set; } - - /// - /// Specifies the version or version range of the package to be saved - /// - [Parameter(ParameterSetName = NameParameterSet)] - [ValidateNotNullOrEmpty] - public string Version { get; set; } - - /// - /// Specifies to allow saveing of prerelease versions - /// - [Parameter(ParameterSetName = NameParameterSet)] - public SwitchParameter Prerelease { get; set; } - - /// - /// Specifies the specific repositories to search within. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string[] Repository { get; set; } - - /// - /// Specifies a user account that has rights to save a resource from a specific repository. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public PSCredential Credential { get; set; } - - /* - /// - /// Saves as a .nupkg - /// - [Parameter()] - public SwitchParameter AsNupkg { get; set; } - - /// - /// Saves the metadata XML file with the resource - /// - [Parameter()] - public SwitchParameter IncludeXML { get; set; } - */ - - /// - /// The destination where the resource is to be installed. Works for all resource types. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - [ValidateNotNullOrEmpty] - public string Path - { - get - { return _path; } - - set - { - string resolvedPath = string.Empty; - if (!string.IsNullOrEmpty(value)) - { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } - - // Path where resource is saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _path = resolvedPath; - } - } - } - private string _path; - - /// - /// Suppresses being prompted for untrusted sources. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] - public SwitchParameter TrustRepository { get; set; } - - /// - /// Used for pipeline input. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] - [ValidateNotNullOrEmpty] - public PSResourceInfo InputObject { get; set; } - - /// - /// Skips the check for resource dependencies, so that only found resources are saved, - /// and not any resources the found resource depends on. - /// - [Parameter] - public SwitchParameter SkipDependencyCheck { get; set; } - - #endregion - - #region Method overrides - - protected override void BeginProcessing() - { - // Create a repository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly - RepositorySettings.CheckRepositoryStore(); - - // If the user does not specify a path to save to, use the user's current working directory - if (string.IsNullOrWhiteSpace(_path)) - { - _path = SessionState.Path.CurrentLocation.Path; - } - - _installHelper = new InstallHelper(savePkg: true, cmdletPassedIn: this); - } - - protected override void ProcessRecord() - { - switch (ParameterSetName) - { - case NameParameterSet: - // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. - // an exact version will be formatted into a version range. - if (Version == null) - { - _versionRange = VersionRange.All; - } - else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) - { - var exMessage = "Argument for -Version parameter is not in the proper format."; - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - ProcessSaveHelper( - pkgNames: Name, - pkgPrerelease: Prerelease, - pkgRepository: Repository); - break; - - case InputObjectParameterSet: - string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); - if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) - { - var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); - var ex = new ArgumentException(exMessage); - var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(IncorrectVersionFormat); - } - - ProcessSaveHelper( - pkgNames: new string[] { InputObject.Name }, - pkgPrerelease: InputObject.IsPrerelease, - pkgRepository: new string[] { InputObject.Repository }); - - break; - - default: - Dbg.Assert(false, "Invalid parameter set"); - break; - } - } - - #endregion - - #region Private methods - - private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) - { - var namesToSave = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); - if (nameContainsWildcard) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), - "NameContainsWildcard", - ErrorCategory.InvalidArgument, - this)); - return; - } - - foreach (string error in errorMsgs) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); - } - - // 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 namesToSave - if (namesToSave.Length == 0) - { - return; - } - - if (!ShouldProcess(string.Format("Resources to save: '{0}'", namesToSave))) - { - WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", namesToSave)); - return; - } - - _installHelper.InstallPackages( - names: namesToSave, - versionRange: _versionRange, - prerelease: pkgPrerelease, - repository: pkgRepository, - acceptLicense: true, - quiet: true, - reinstall: true, - force: false, - trustRepository: TrustRepository, - credential: Credential, - noClobber: false, - specifiedPath: _path, - asNupkg: false, - includeXML: false, - skipDependencyCheck: SkipDependencyCheck, - pathsToInstallPkg: new List { _path } ); - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Management.Automation; + +using Dbg = System.Diagnostics.Debug; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Save-PSResource cmdlet saves a resource to a machine. + /// It returns nothing. + /// + [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] + public sealed class SavePSResource : PSCmdlet + { + #region Members + + private const string NameParameterSet = "NameParameterSet"; + private const string InputObjectParameterSet = "InputObjectParameterSet"; + VersionRange _versionRange; + InstallHelper _installHelper; + + #endregion + + #region Parameters + + /// + /// Specifies the exact names of resources to save from a repository. + /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set; } + + /// + /// Specifies the version or version range of the package to be saved + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// Specifies to allow saveing of prerelease versions + /// + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies the specific repositories to search within. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies a user account that has rights to save a resource from a specific repository. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public PSCredential Credential { get; set; } + + /* + /// + /// Saves as a .nupkg + /// + [Parameter()] + public SwitchParameter AsNupkg { get; set; } + + /// + /// Saves the metadata XML file with the resource + /// + [Parameter()] + public SwitchParameter IncludeXML { get; set; } + */ + + /// + /// The destination where the resource is to be installed. Works for all resource types. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public string Path + { + get + { return _path; } + + set + { + string resolvedPath = string.Empty; + if (!string.IsNullOrEmpty(value)) + { + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + } + + // Path where resource is saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _path = resolvedPath; + } + } + } + private string _path; + + /// + /// Suppresses being prompted for untrusted sources. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Passes the resource saved to the console. + /// + [Parameter()] + public SwitchParameter PassThru { get; set; } + + /// + /// Used for pipeline input. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = InputObjectParameterSet)] + [ValidateNotNullOrEmpty] + public PSResourceInfo InputObject { get; set; } + + /// + /// Skips the check for resource dependencies, so that only found resources are saved, + /// and not any resources the found resource depends on. + /// + [Parameter] + public SwitchParameter SkipDependencyCheck { get; set; } + + #endregion + + #region Method overrides + + protected override void BeginProcessing() + { + // Create a repository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + + // If the user does not specify a path to save to, use the user's current working directory + if (string.IsNullOrWhiteSpace(_path)) + { + _path = SessionState.Path.CurrentLocation.Path; + } + + _installHelper = new InstallHelper(savePkg: true, cmdletPassedIn: this); + } + + protected override void ProcessRecord() + { + switch (ParameterSetName) + { + case NameParameterSet: + // validate that if a -Version param is passed in that it can be parsed into a NuGet version range. + // an exact version will be formatted into a version range. + if (Version == null) + { + _versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + { + var exMessage = "Argument for -Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + ProcessSaveHelper( + pkgNames: Name, + pkgPrerelease: Prerelease, + pkgRepository: Repository); + break; + + case InputObjectParameterSet: + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) + { + var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + ProcessSaveHelper( + pkgNames: new string[] { InputObject.Name }, + pkgPrerelease: InputObject.IsPrerelease, + pkgRepository: new string[] { InputObject.Repository }); + + break; + + default: + Dbg.Assert(false, "Invalid parameter set"); + break; + } + } + + #endregion + + #region Private methods + + private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) + { + var namesToSave = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Name with wildcards is not supported for Save-PSResource cmdlet"), + "NameContainsWildcard", + ErrorCategory.InvalidArgument, + this)); + return; + } + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // 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 namesToSave + if (namesToSave.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("Resources to save: '{0}'", namesToSave))) + { + WriteVerbose(string.Format("Save operation cancelled by user for resources: {0}", namesToSave)); + return; + } + + var installedPkgs = _installHelper.InstallPackages( + names: namesToSave, + versionRange: _versionRange, + prerelease: pkgPrerelease, + repository: pkgRepository, + acceptLicense: true, + quiet: true, + reinstall: true, + force: false, + trustRepository: TrustRepository, + credential: Credential, + noClobber: false, + specifiedPath: _path, + asNupkg: false, + includeXML: false, + skipDependencyCheck: SkipDependencyCheck, + pathsToInstallPkg: new List { _path } ); + + if (PassThru) + { + foreach (PSResourceInfo pkg in installedPkgs) + { + WriteObject(pkg); + } + } + } + + #endregion + } +} diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index ba4bec2b6..6303905ca 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -1,322 +1,336 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using NuGet.Versioning; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Management.Automation; -using System.Threading; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. - /// It updates an already installed package based on the -Name parameter argument. - /// It does not return an object. Other parameters allow the package to be updated to be further filtered. - /// - [Cmdlet(VerbsData.Update, - "PSResource", - SupportsShouldProcess = true)] - public sealed class UpdatePSResource : PSCmdlet - { - #region Members - private List _pathsToInstallPkg; - private CancellationTokenSource _cancellationTokenSource; - private FindHelper _findHelper; - private InstallHelper _installHelper; - - #endregion - - #region Parameters - - /// - /// Specifies name of a resource or resources to update. - /// Accepts wildcard characters. - /// - [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - [ValidateNotNullOrEmpty] - public string[] Name { get; set ; } = new string[] {"*"}; - - /// - /// Specifies the version the resource is to be updated to. - /// - [Parameter] - [ValidateNotNullOrEmpty] - public string Version { get; set; } - - /// - /// When specified, allows updating to a prerelease version. - /// - [Parameter] - public SwitchParameter Prerelease { get; set; } - - /// - /// Specifies one or more repository names to update packages from. - /// If not specified, search will include all currently registered repositories in order of highest priority. - /// - [Parameter] - [ArgumentCompleter(typeof(RepositoryNameCompleter))] - [ValidateNotNullOrEmpty] - public string[] Repository { get; set; } - - /// - /// Specifies the scope of the resource to update. - /// - [Parameter] - public ScopeType Scope { get; set; } - - /// - /// When specified, suppresses prompting for untrusted sources. - /// - [Parameter] - public SwitchParameter TrustRepository { get; set; } - - /// - /// Specifies optional credentials to be used when accessing a private repository. - /// - [Parameter] - public PSCredential Credential { get; set; } - - /// - /// Suppresses progress information. - /// - [Parameter] - public SwitchParameter Quiet { get; set; } - - /// - /// For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. - /// - [Parameter] - public SwitchParameter AcceptLicense { get; set; } - - /// - /// When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. - /// - [Parameter] - public SwitchParameter Force { get; set; } - - /// - /// Skips the check for resource dependencies, so that only found resources are updated, - /// and not any resources the found resource depends on. - /// - [Parameter] - public SwitchParameter SkipDependencyCheck { get; set; } - - #endregion - - #region Override Methods - - protected override void BeginProcessing() - { - // Create a repository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly - RepositorySettings.CheckRepositoryStore(); - - _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); - - _cancellationTokenSource = new CancellationTokenSource(); - _findHelper = new FindHelper( - cancellationToken: _cancellationTokenSource.Token, - cmdletPassedIn: this); - - _installHelper = new InstallHelper( - savePkg: false, - cmdletPassedIn: this); - } - - protected override void ProcessRecord() - { - VersionRange versionRange; - - // handle case where Version == null - if (Version == null) { - versionRange = VersionRange.All; - } - else if (!Utils.TryParseVersionOrVersionRange(Version, out versionRange)) - { - // Only returns false if the range was incorrectly formatted and couldn't be parsed. - WriteError(new ErrorRecord( - new PSInvalidOperationException("Cannot parse Version parameter provided into VersionRange"), - "ErrorParsingVersionParamIntoVersionRange", - ErrorCategory.InvalidArgument, - this)); - return; - } - - var namesToUpdate = ProcessPackageNames(Name, versionRange); - - if (namesToUpdate.Length == 0) - { - return; - } - - if (!ShouldProcess(string.Format("package to update: '{0}'", String.Join(", ", Name)))) - { - WriteVerbose(string.Format("Update is cancelled by user for: {0}", String.Join(", ", Name))); - return; - } - - _installHelper.InstallPackages( - names: namesToUpdate, - versionRange: versionRange, - prerelease: Prerelease, - repository: Repository, - acceptLicense: AcceptLicense, - quiet: Quiet, - reinstall: true, - force: Force, - trustRepository: TrustRepository, - credential: Credential, - noClobber: false, - specifiedPath: null, - asNupkg: false, - includeXML: true, - skipDependencyCheck: SkipDependencyCheck, - pathsToInstallPkg: _pathsToInstallPkg); - } - - protected override void StopProcessing() - { - _cancellationTokenSource?.Cancel(); - } - - protected override void EndProcessing() - { - _cancellationTokenSource.Dispose(); - _cancellationTokenSource = null; - } - - #endregion - - #region Private Methods - - /// - /// This method performs a number of functions on the list of resource package names to update. - /// - Processes the name list for wild card characters. - /// - Writes errors for names with unsupported wild characters. - /// - Finds installed packages that match the names list. - /// - Finds repository packages that match the names list and update version. - /// - Compares installed packages and repository search results with name list. - /// - Returns a final list of packages for reinstall, that meet update criteria. - /// - private string[] ProcessPackageNames( - string[] namesToProcess, - VersionRange versionRange) - { - namesToProcess = Utils.ProcessNameWildcards( - pkgNames: namesToProcess, - errorMsgs: out string[] errorMsgs, - isContainWildcard: out bool _); - - foreach (string error in errorMsgs) - { - WriteError(new ErrorRecord( - new PSInvalidOperationException(error), - "ErrorFilteringNamesForUnsupportedWildcards", - ErrorCategory.InvalidArgument, - this)); - } - - // This catches the case where namesToProcess wasn't passed in as null or empty, - // but after filtering out unsupported wildcard names there are no elements left in namesToProcess. - if (namesToProcess.Length == 0) - { - return Utils.EmptyStrArray; - } - - if (String.Equals(namesToProcess[0], "*", StringComparison.InvariantCultureIgnoreCase)) - { - WriteVerbose("Package names were detected to be (or contain an element equal to): '*', so all packages will be updated"); - } - - // Get all installed packages selected for updating. - GetHelper getHelper = new GetHelper(cmdletPassedIn: this); - var installedPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (var installedPackage in getHelper.GetPackagesFromPath( - name: namesToProcess, - versionRange: VersionRange.All, - pathsToSearch: Utils.GetAllResourcePaths(this, Scope))) - { - if (!installedPackages.ContainsKey(installedPackage.Name)) - { - installedPackages.Add(installedPackage.Name, installedPackage); - } - } - - if (installedPackages.Count is 0) - { - WriteWarning($"No installed packages were found with name '{string.Join(",", namesToProcess)}' in scope '{Scope}'. First install package using 'Install-PSResource'."); - return Utils.EmptyStrArray; - } - - // Find all packages selected for updating in provided repositories. - var repositoryPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (var foundResource in _findHelper.FindByResourceName( - name: installedPackages.Keys.ToArray(), - type: ResourceType.None, - version: Version, - prerelease: Prerelease, - tag: null, - repository: Repository, - credential: Credential, - includeDependencies: !SkipDependencyCheck)) - { - if (!repositoryPackages.ContainsKey(foundResource.Name)) - { - repositoryPackages.Add(foundResource.Name, foundResource); - } - } - - // Check if named package is installed or can be found in the repositories. - foreach (var nameToProcess in namesToProcess) - { - if (!WildcardPattern.ContainsWildcardCharacters(nameToProcess)) - { - if (!installedPackages.ContainsKey(nameToProcess)) - { - WriteWarning( - $"Package '{nameToProcess}' not installed in scope '{Scope}'. First install package using 'Install-PSResource'."); - } - else if (!repositoryPackages.ContainsKey(nameToProcess)) - { - WriteWarning( - $"Installed package '{nameToProcess}':'{Version}' was not found in repositories and cannot be updated."); - } - } - } - - // Create list of packages to update. - List namesToUpdate = new List(); - foreach (PSResourceInfo repositoryPackage in repositoryPackages.Values) - { - if (!installedPackages.TryGetValue(repositoryPackage.Name, out PSResourceInfo installedPackage)) - { - continue; - } - - // If the current package is out of range, install it with the correct version. - if (!NuGetVersion.TryParse(installedPackage.Version.ToString(), out NuGetVersion installedVersion)) - { - WriteWarning($"Cannot parse nuget version in installed package '{installedPackage.Name}'. Cannot update package."); - continue; - } - - if ((versionRange == VersionRange.All && repositoryPackage.Version > installedPackage.Version) || - !versionRange.Satisfies(installedVersion)) - { - namesToUpdate.Add(repositoryPackage.Name); - } - else - { - WriteVerbose($"Installed package {repositoryPackage.Name} is up to date."); - } - } - - return namesToUpdate.ToArray(); - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; +using System.Threading; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. + /// It updates an already installed package based on the -Name parameter argument. + /// It does not return an object. Other parameters allow the package to be updated to be further filtered. + /// + [Cmdlet(VerbsData.Update, + "PSResource", + SupportsShouldProcess = true)] + public sealed class UpdatePSResource : PSCmdlet + { + #region Members + private List _pathsToInstallPkg; + private CancellationTokenSource _cancellationTokenSource; + private FindHelper _findHelper; + private InstallHelper _installHelper; + + #endregion + + #region Parameters + + /// + /// Specifies name of a resource or resources to update. + /// Accepts wildcard characters. + /// + [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [ValidateNotNullOrEmpty] + public string[] Name { get; set ; } = new string[] {"*"}; + + /// + /// Specifies the version the resource is to be updated to. + /// + [Parameter] + [ValidateNotNullOrEmpty] + public string Version { get; set; } + + /// + /// When specified, allows updating to a prerelease version. + /// + [Parameter] + public SwitchParameter Prerelease { get; set; } + + /// + /// Specifies one or more repository names to update packages from. + /// If not specified, search will include all currently registered repositories in order of highest priority. + /// + [Parameter] + [ArgumentCompleter(typeof(RepositoryNameCompleter))] + [ValidateNotNullOrEmpty] + public string[] Repository { get; set; } + + /// + /// Specifies the scope of the resource to update. + /// + [Parameter] + public ScopeType Scope { get; set; } + + /// + /// When specified, suppresses prompting for untrusted sources. + /// + [Parameter] + public SwitchParameter TrustRepository { get; set; } + + /// + /// Specifies optional credentials to be used when accessing a private repository. + /// + [Parameter] + public PSCredential Credential { get; set; } + + /// + /// Suppresses progress information. + /// + [Parameter] + public SwitchParameter Quiet { get; set; } + + /// + /// For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + /// + [Parameter] + public SwitchParameter AcceptLicense { get; set; } + + /// + /// When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + /// + [Parameter] + public SwitchParameter Force { get; set; } + + /// + /// Passes the resource updated to the console. + /// + [Parameter()] + public SwitchParameter PassThru { get; set; } + + /// + /// Skips the check for resource dependencies, so that only found resources are updated, + /// and not any resources the found resource depends on. + /// + [Parameter] + public SwitchParameter SkipDependencyCheck { get; set; } + + #endregion + + #region Override Methods + + protected override void BeginProcessing() + { + // Create a repository story (the PSResourceRepository.xml file) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); + + _cancellationTokenSource = new CancellationTokenSource(); + _findHelper = new FindHelper( + cancellationToken: _cancellationTokenSource.Token, + cmdletPassedIn: this); + + _installHelper = new InstallHelper( + savePkg: false, + cmdletPassedIn: this); + } + + protected override void ProcessRecord() + { + VersionRange versionRange; + + // handle case where Version == null + if (Version == null) { + versionRange = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(Version, out versionRange)) + { + // Only returns false if the range was incorrectly formatted and couldn't be parsed. + WriteError(new ErrorRecord( + new PSInvalidOperationException("Cannot parse Version parameter provided into VersionRange"), + "ErrorParsingVersionParamIntoVersionRange", + ErrorCategory.InvalidArgument, + this)); + return; + } + + var namesToUpdate = ProcessPackageNames(Name, versionRange); + + if (namesToUpdate.Length == 0) + { + return; + } + + if (!ShouldProcess(string.Format("package to update: '{0}'", String.Join(", ", Name)))) + { + WriteVerbose(string.Format("Update is cancelled by user for: {0}", String.Join(", ", Name))); + return; + } + + var installedPkgs = _installHelper.InstallPackages( + names: namesToUpdate, + versionRange: versionRange, + prerelease: Prerelease, + repository: Repository, + acceptLicense: AcceptLicense, + quiet: Quiet, + reinstall: true, + force: Force, + trustRepository: TrustRepository, + credential: Credential, + noClobber: false, + specifiedPath: null, + asNupkg: false, + includeXML: true, + skipDependencyCheck: SkipDependencyCheck, + pathsToInstallPkg: _pathsToInstallPkg); + + if (PassThru) + { + foreach (PSResourceInfo pkg in installedPkgs) + { + WriteObject(pkg); + } + } + } + + protected override void StopProcessing() + { + _cancellationTokenSource?.Cancel(); + } + + protected override void EndProcessing() + { + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = null; + } + + #endregion + + #region Private Methods + + /// + /// This method performs a number of functions on the list of resource package names to update. + /// - Processes the name list for wild card characters. + /// - Writes errors for names with unsupported wild characters. + /// - Finds installed packages that match the names list. + /// - Finds repository packages that match the names list and update version. + /// - Compares installed packages and repository search results with name list. + /// - Returns a final list of packages for reinstall, that meet update criteria. + /// + private string[] ProcessPackageNames( + string[] namesToProcess, + VersionRange versionRange) + { + namesToProcess = Utils.ProcessNameWildcards( + pkgNames: namesToProcess, + errorMsgs: out string[] errorMsgs, + isContainWildcard: out bool _); + + foreach (string error in errorMsgs) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(error), + "ErrorFilteringNamesForUnsupportedWildcards", + ErrorCategory.InvalidArgument, + this)); + } + + // This catches the case where namesToProcess wasn't passed in as null or empty, + // but after filtering out unsupported wildcard names there are no elements left in namesToProcess. + if (namesToProcess.Length == 0) + { + return Utils.EmptyStrArray; + } + + if (String.Equals(namesToProcess[0], "*", StringComparison.InvariantCultureIgnoreCase)) + { + WriteVerbose("Package names were detected to be (or contain an element equal to): '*', so all packages will be updated"); + } + + // Get all installed packages selected for updating. + GetHelper getHelper = new GetHelper(cmdletPassedIn: this); + var installedPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (var installedPackage in getHelper.GetPackagesFromPath( + name: namesToProcess, + versionRange: VersionRange.All, + pathsToSearch: Utils.GetAllResourcePaths(this, Scope))) + { + if (!installedPackages.ContainsKey(installedPackage.Name)) + { + installedPackages.Add(installedPackage.Name, installedPackage); + } + } + + if (installedPackages.Count is 0) + { + WriteWarning($"No installed packages were found with name '{string.Join(",", namesToProcess)}' in scope '{Scope}'. First install package using 'Install-PSResource'."); + return Utils.EmptyStrArray; + } + + // Find all packages selected for updating in provided repositories. + var repositoryPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (var foundResource in _findHelper.FindByResourceName( + name: installedPackages.Keys.ToArray(), + type: ResourceType.None, + version: Version, + prerelease: Prerelease, + tag: null, + repository: Repository, + credential: Credential, + includeDependencies: !SkipDependencyCheck)) + { + if (!repositoryPackages.ContainsKey(foundResource.Name)) + { + repositoryPackages.Add(foundResource.Name, foundResource); + } + } + + // Check if named package is installed or can be found in the repositories. + foreach (var nameToProcess in namesToProcess) + { + if (!WildcardPattern.ContainsWildcardCharacters(nameToProcess)) + { + if (!installedPackages.ContainsKey(nameToProcess)) + { + WriteWarning( + $"Package '{nameToProcess}' not installed in scope '{Scope}'. First install package using 'Install-PSResource'."); + } + else if (!repositoryPackages.ContainsKey(nameToProcess)) + { + WriteWarning( + $"Installed package '{nameToProcess}':'{Version}' was not found in repositories and cannot be updated."); + } + } + } + + // Create list of packages to update. + List namesToUpdate = new List(); + foreach (PSResourceInfo repositoryPackage in repositoryPackages.Values) + { + if (!installedPackages.TryGetValue(repositoryPackage.Name, out PSResourceInfo installedPackage)) + { + continue; + } + + // If the current package is out of range, install it with the correct version. + if (!NuGetVersion.TryParse(installedPackage.Version.ToString(), out NuGetVersion installedVersion)) + { + WriteWarning($"Cannot parse nuget version in installed package '{installedPackage.Name}'. Cannot update package."); + continue; + } + + if ((versionRange == VersionRange.All && repositoryPackage.Version > installedPackage.Version) || + !versionRange.Satisfies(installedVersion)) + { + namesToUpdate.Add(repositoryPackage.Name); + } + else + { + WriteVerbose($"Installed package {repositoryPackage.Name} is up to date."); + } + } + + return namesToUpdate.ToArray(); + } + + #endregion + } +} diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 523f83908..b7901be78 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -11,7 +11,7 @@ Describe 'Test Get-PSResource for Module' { $testScriptName = "test_script" Get-NewPSResourceRepositoryFile - Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository + Install-PSResource -Name ContosoServer -Repository $TestGalleryName -Verbose Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "2.0" Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "1.5" Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "1.0" diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 5f9298991..b0812c636 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -306,6 +306,12 @@ Describe 'Test Install-PSResource for Module' { $res.Name | Should -Be $testModuleName $res.Version | Should -Be "1.1.0.0" } + + It "Install module using -PassThru" { + $res = Install-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -PassThru + $res.Name | Should -Be "TestModule" + $res.Version | Should -Be "1.3.0.0" + } } <# Temporarily commented until -Tag is implemented for this Describe block diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 59b1f7d43..d18194b41 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -195,6 +195,11 @@ Describe 'Test Save-PSResource for PSResources' { (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } + It "Save module using -PassThru" { + $res = Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru + $res.Name | Should -Be "TestModule" + $res.Version | Should -Be "1.3.0.0" + } <# # Tests should not write to module directory It "Save specific module resource by name if no -Path param is specifed" { diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index ee6b7c0cc..29549d3db 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -344,4 +344,12 @@ Describe 'Test Update-PSResource' { $isPkgUpdated | Should -Be $false } -} \ No newline at end of file + + It "update resource installed given -Name and -PassThru parameters" { + Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + + $res = Update-PSResource -Name "TestModule" -Version "1.3.0.0" -Repository $TestGalleryName -PassThru + $res.Name | Should -Be "TestModule" + $res.Version | Should -Be "1.3.0.0" + } +} From d605294bd9c06491e3fc416df8f94abea31d772d Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 1 Dec 2021 13:00:59 -0800 Subject: [PATCH 108/276] Add -AsNupkg and -IncludeXML params and test (#538) --- src/code/InstallHelper.cs | 75 +++++++++++++++++++---------------- src/code/InstallPSResource.cs | 20 +++++----- src/code/SavePSResource.cs | 12 +++--- src/code/UpdatePSResource.cs | 6 +-- test/SavePSResource.Tests.ps1 | 24 +++++++++++ 5 files changed, 81 insertions(+), 56 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index fba72465e..8f5d45d8e 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -35,7 +35,6 @@ internal class InstallHelper : PSCmdlet private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; private CancellationToken _cancellationToken; - private readonly bool _savePkg; private readonly PSCmdlet _cmdletPassedIn; private List _pathsToInstallPkg; private VersionRange _versionRange; @@ -46,21 +45,20 @@ internal class InstallHelper : PSCmdlet private bool _force; private bool _trustRepository; private PSCredential _credential; - private string _specifiedPath; private bool _asNupkg; private bool _includeXML; private bool _noClobber; + private bool _savePkg; List _pathsToSearch; #endregion #region Public methods - public InstallHelper(bool savePkg, PSCmdlet cmdletPassedIn) + public InstallHelper(PSCmdlet cmdletPassedIn) { CancellationTokenSource source = new CancellationTokenSource(); _cancellationToken = source.Token; - _savePkg = savePkg; _cmdletPassedIn = cmdletPassedIn; } @@ -76,23 +74,26 @@ public List InstallPackages( bool trustRepository, bool noClobber, PSCredential credential, - string specifiedPath, bool asNupkg, bool includeXML, bool skipDependencyCheck, + bool savePkg, List pathsToInstallPkg) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'", + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXML '{10}'; SavePackage '{11}'", string.Join(",", names), - versionRange != null ? versionRange.OriginalString : string.Empty, + versionRange != null ? (versionRange.OriginalString != null ? versionRange.OriginalString : string.Empty) : string.Empty, prerelease.ToString(), repository != null ? string.Join(",", repository) : string.Empty, acceptLicense.ToString(), quiet.ToString(), reinstall.ToString(), trustRepository.ToString(), - noClobber.ToString())); + noClobber.ToString(), + asNupkg.ToString(), + includeXML.ToString(), + savePkg.ToString())); _versionRange = versionRange; _prerelease = prerelease; @@ -103,9 +104,9 @@ public List InstallPackages( _trustRepository = trustRepository || force; _noClobber = noClobber; _credential = credential; - _specifiedPath = specifiedPath; _asNupkg = asNupkg; _includeXML = includeXML; + _savePkg = savePkg; _pathsToInstallPkg = pathsToInstallPkg; // Create list of installation paths to search. @@ -379,15 +380,7 @@ private List InstallPackage( globalPackagesFolder: tempInstallPath, logger: NullLogger.Instance, token: _cancellationToken).GetAwaiter().GetResult(); - - if (_asNupkg) // this is Save functionality - { - DirectoryInfo nupkgPath = new DirectoryInfo(((System.IO.FileStream)result.PackageStream).Name); - File.Copy(nupkgPath.FullName, Path.Combine(tempInstallPath, pkgIdentity.Id + pkgIdentity.Version + ".nupkg")); - - continue; - } - + // Create the package extraction context PackageExtractionContext packageExtractionContext = new PackageExtractionContext( packageSaveMode: PackageSaveMode.Nupkg, @@ -444,10 +437,8 @@ private List InstallPackage( _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); - // Prompt if module requires license acceptance (need to read info license acceptance info from the module manifest) // pkgIdentity.Version.Version gets the version without metadata or release labels. string newVersion = pkgIdentity.Version.ToNormalizedString(); - string normalizedVersionNoPrereleaseLabel = newVersion; if (pkgIdentity.Version.IsPrerelease) { @@ -463,6 +454,35 @@ private List InstallPackage( // Check if the package is a module or a script var isModule = File.Exists(modulePath); + string installPath; + if (_savePkg) + { + // For save the installation path is what is passed in via -Path + installPath = _pathsToInstallPkg.FirstOrDefault(); + + // If saving as nupkg simply copy the nupkg and move onto next iteration of loop + // asNupkg functionality only applies to Save-PSResource + if (_asNupkg) + { + var nupkgFile = pkgIdentity.ToString().ToLower() + ".nupkg"; + File.Copy(Path.Combine(tempDirNameVersion, nupkgFile), Path.Combine(installPath, nupkgFile)); + + _cmdletPassedIn.WriteVerbose(string.Format("'{0}' moved into file path '{1}'", nupkgFile, installPath)); + pkgsSuccessfullyInstalled.Add(pkg); + + continue; + } + } + else + { + // PSModules: + /// ./Modules + /// ./Scripts + /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list + installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) + : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); + } + if (isModule) { var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); @@ -500,21 +520,6 @@ private List InstallPackage( // Delete the extra nupkg related files that are not needed and not part of the module/script DeleteExtraneousFiles(pkgIdentity, tempDirNameVersion); - string installPath; - if (_savePkg) - { - // For save the installation path is what is passed in via -Path - installPath = _pathsToInstallPkg.FirstOrDefault(); - } - else { - // PSModules: - /// ./Modules - /// ./Scripts - /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list - installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) - : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); - } - if (_includeXML) { CreateMetadataXMLFile(tempDirNameVersion, installPath, pkg, isModule); diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index bdbbbdc5f..f2fc2e8ca 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -143,7 +143,7 @@ protected override void BeginProcessing() _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, Scope); - _installHelper = new InstallHelper(savePkg: false, cmdletPassedIn: this); + _installHelper = new InstallHelper(cmdletPassedIn: this); } protected override void ProcessRecord() @@ -260,18 +260,18 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[ trustRepository: TrustRepository, noClobber: NoClobber, credential: Credential, - specifiedPath: null, asNupkg: false, includeXML: true, skipDependencyCheck: SkipDependencyCheck, - pathsToInstallPkg: _pathsToInstallPkg); - - if (PassThru) - { - foreach (PSResourceInfo pkg in installedPkgs) - { - WriteObject(pkg); - } + savePkg: false, + pathsToInstallPkg: _pathsToInstallPkg); + + if (PassThru) + { + foreach (PSResourceInfo pkg in installedPkgs) + { + WriteObject(pkg); + } } } diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 0c79420d2..e9c456cd7 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -67,9 +67,8 @@ public sealed class SavePSResource : PSCmdlet [Parameter(ParameterSetName = InputObjectParameterSet)] public PSCredential Credential { get; set; } - /* /// - /// Saves as a .nupkg + /// Saves the resource as a .nupkg /// [Parameter()] public SwitchParameter AsNupkg { get; set; } @@ -79,7 +78,6 @@ public sealed class SavePSResource : PSCmdlet /// [Parameter()] public SwitchParameter IncludeXML { get; set; } - */ /// /// The destination where the resource is to be installed. Works for all resource types. @@ -152,7 +150,7 @@ protected override void BeginProcessing() _path = SessionState.Path.CurrentLocation.Path; } - _installHelper = new InstallHelper(savePkg: true, cmdletPassedIn: this); + _installHelper = new InstallHelper(cmdletPassedIn: this); } protected override void ProcessRecord() @@ -254,10 +252,10 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p trustRepository: TrustRepository, credential: Credential, noClobber: false, - specifiedPath: _path, - asNupkg: false, - includeXML: false, + asNupkg: AsNupkg, + includeXML: IncludeXML, skipDependencyCheck: SkipDependencyCheck, + savePkg: true, pathsToInstallPkg: new List { _path } ); if (PassThru) diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 6303905ca..dc947e084 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -127,9 +127,7 @@ protected override void BeginProcessing() cancellationToken: _cancellationTokenSource.Token, cmdletPassedIn: this); - _installHelper = new InstallHelper( - savePkg: false, - cmdletPassedIn: this); + _installHelper = new InstallHelper(cmdletPassedIn: this); } protected override void ProcessRecord() @@ -176,10 +174,10 @@ protected override void ProcessRecord() trustRepository: TrustRepository, credential: Credential, noClobber: false, - specifiedPath: null, asNupkg: false, includeXML: true, skipDependencyCheck: SkipDependencyCheck, + savePkg: false, pathsToInstallPkg: _pathsToInstallPkg); if (PassThru) diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index d18194b41..b21f27d90 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -195,6 +195,30 @@ Describe 'Test Save-PSResource for PSResources' { (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } + It "Save module as a nupkg" { + Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + write-host $SaveDir + write-host + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testmodule.1.3.0.nupkg" + $pkgDir | Should -Not -BeNullOrEmpty + } + + It "Save script as a nupkg" { + Save-PSResource -Name "TestTestScript" -Version "1.3.1" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testtestscript.1.3.1.nupkg" + $pkgDir | Should -Not -BeNullOrEmpty + } + + It "Save module and include XML metadata file" { + Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -IncludeXML + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" + $xmlFile = Get-ChildItem -Path $pkgDirVersion.FullName | Where-Object Name -eq "PSGetModuleInfo.xml" + $xmlFile | Should -Not -BeNullOrEmpty + } + It "Save module using -PassThru" { $res = Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru $res.Name | Should -Be "TestModule" From d6bf64325c1447e1db0547dc2494d24819390368 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 1 Dec 2021 13:44:28 -0800 Subject: [PATCH 109/276] Remove DSCResources from PowerShellGet (#553) --- .ci/ci_auto.yml | 1 - .ci/ci_release.yml | 1 - DSC/DSC.psd1 | 63 -- .../MSFT_PSModule/MSFT_PSModule.psm1 | 625 ------------------ .../MSFT_PSModule/MSFT_PSModule.schema.mfl | 21 - .../MSFT_PSModule/MSFT_PSModule.schema.mof | 19 - .../en-US/MSFT_PSModule.strings.psd1 | 35 - .../MSFT_PSRepository/MSFT_PSRepository.psm1 | 273 -------- .../MSFT_PSRepository.schema.mfl | 15 - .../MSFT_PSRepository.schema.mof | 11 - .../en-US/MSFT_PSRepository.strings.psd1 | 22 - DSC/Examples/.gitattributes | 1 - DSC/Examples/README.md | 8 - .../1-PSModule_InstallModuleConfig.ps1 | 73 -- .../2-PSModule_InstallModuleTrustedConfig.ps1 | 76 --- ...Module_InstallModuleAllowClobberConfig.ps1 | 74 --- ...ule_InstallModuleSpecificVersionConfig.ps1 | 83 --- ..._InstallModuleWithinVersionRangeConfig.ps1 | 92 --- .../6-PSModule_UninstallModuleConfig.ps1 | 74 --- .../1-PSRepository_AddRepositoryConfig.ps1 | 76 --- .../2-PSRepository_RemoveRepositoryConfig.ps1 | 74 --- .../PowerShellGet.LocalizationHelper.psm1 | 254 ------- .../PowerShellGet.ResourceHelper.psm1 | 368 ----------- .../PowerShellGet.ResourceHelper.strings.psd1 | 29 - .../MSFT_PSModule.Integration.Tests.ps1 | 498 -------------- .../Integration/MSFT_PSModule.config.ps1 | 227 ------- .../MSFT_PSRepository.Integration.Tests.ps1 | 206 ------ .../Integration/MSFT_PSRepository.config.ps1 | 108 --- DSC/Tests/Unit/MSFT_PSModule.Tests.ps1 | 613 ----------------- DSC/Tests/Unit/MSFT_PSRepository.Tests.ps1 | 397 ----------- ...PowerShellGet.LocalizationHelper.Tests.ps1 | 206 ------ .../PowerShellGet.ResourceHelper.Tests.ps1 | 504 -------------- build.ps1 | 1 - doBuild.ps1 | 14 - 34 files changed, 5142 deletions(-) delete mode 100644 DSC/DSC.psd1 delete mode 100644 DSC/DscResources/MSFT_PSModule/MSFT_PSModule.psm1 delete mode 100644 DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mfl delete mode 100644 DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mof delete mode 100644 DSC/DscResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 delete mode 100644 DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.psm1 delete mode 100644 DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mfl delete mode 100644 DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mof delete mode 100644 DSC/DscResources/MSFT_PSRepository/en-US/MSFT_PSRepository.strings.psd1 delete mode 100644 DSC/Examples/.gitattributes delete mode 100644 DSC/Examples/README.md delete mode 100644 DSC/Examples/Resources/PSModule/1-PSModule_InstallModuleConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSModule/2-PSModule_InstallModuleTrustedConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSModule/3-PSModule_InstallModuleAllowClobberConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSModule/4-PSModule_InstallModuleSpecificVersionConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSModule/5-PSModule_InstallModuleWithinVersionRangeConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSModule/6-PSModule_UninstallModuleConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSRepository/1-PSRepository_AddRepositoryConfig.ps1 delete mode 100644 DSC/Examples/Resources/PSRepository/2-PSRepository_RemoveRepositoryConfig.ps1 delete mode 100644 DSC/Modules/PowerShellGet.LocalizationHelper/PowerShellGet.LocalizationHelper.psm1 delete mode 100644 DSC/Modules/PowerShellGet.ResourceHelper/PowerShellGet.ResourceHelper.psm1 delete mode 100644 DSC/Modules/PowerShellGet.ResourceHelper/en-US/PowerShellGet.ResourceHelper.strings.psd1 delete mode 100644 DSC/Tests/Integration/MSFT_PSModule.Integration.Tests.ps1 delete mode 100644 DSC/Tests/Integration/MSFT_PSModule.config.ps1 delete mode 100644 DSC/Tests/Integration/MSFT_PSRepository.Integration.Tests.ps1 delete mode 100644 DSC/Tests/Integration/MSFT_PSRepository.config.ps1 delete mode 100644 DSC/Tests/Unit/MSFT_PSModule.Tests.ps1 delete mode 100644 DSC/Tests/Unit/MSFT_PSRepository.Tests.ps1 delete mode 100644 DSC/Tests/Unit/PowerShellGet.LocalizationHelper.Tests.ps1 delete mode 100644 DSC/Tests/Unit/PowerShellGet.ResourceHelper.Tests.ps1 diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index ae0720d8c..8178c08e1 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -109,7 +109,6 @@ stages: } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSGet.Format.ps1xml") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index d9133e0cd..722528604 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -98,7 +98,6 @@ stages: } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSGet.Format.ps1xml") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "DscResources") -Dest $createdSignSrcPath -Recurse -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" diff --git a/DSC/DSC.psd1 b/DSC/DSC.psd1 deleted file mode 100644 index 9e56bc3b9..000000000 --- a/DSC/DSC.psd1 +++ /dev/null @@ -1,63 +0,0 @@ -<# - This is a dummy PowerShell manifest file so that the DscResource.Tests - test framework recognize the module folder as correct (expected) folder - and file structure. - THIS FILE IS NOT USE DURING DEPLOYMENT. -#> -@{ - # Version number of this module. - moduleVersion = '0.0.0.1' - - # ID used to uniquely identify this module - GUID = 'e102ebd2-bdc3-4d0f-bc93-4b8cc3eb7074' - - # Author of this module - Author = 'Microsoft Corporation' - - # Company or vendor of this module - CompanyName = 'Microsoft Corporation' - - # Copyright statement for this module - Copyright = '(c) 2019 Microsoft Corporation. All rights reserved.' - - # Description of the functionality provided by this module - Description = 'Module with DSC Resources for deployment of PowerShell modules.' - - # Minimum version of the Windows PowerShell engine required by this module - PowerShellVersion = '5.0' - - # Minimum version of the common language runtime (CLR) required by this module - CLRVersion = '4.0' - - # Functions to export from this module - FunctionsToExport = @() - - # Cmdlets to export from this module - CmdletsToExport = @() - - RequiredAssemblies = @() - - <# - Private data to pass to the module specified in RootModule/ModuleToProcess. - This may also contain a PSData hashtable with additional module metadata used by PowerShell. - #> - PrivateData = @{ - - PSData = @{ - - # Tags applied to this module. These help with module discovery in online galleries. - Tags = @('DesiredStateConfiguration', 'DSC', 'DSCResource') - - # A URL to the license for this module. - LicenseUri = 'https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE' - - # A URL to the main website for this project. - ProjectUri = 'https://github.com/PowerShell/PowerShellGet' - - # ReleaseNotes of this module - ReleaseNotes = '' - - } # End of PSData hashtable - - } # End of PrivateData hashtable -} diff --git a/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.psm1 b/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.psm1 deleted file mode 100644 index 2f58af1b3..000000000 --- a/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.psm1 +++ /dev/null @@ -1,625 +0,0 @@ -# -# Copyright (c) Microsoft Corporation. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# - -$resourceModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent - -# Import localization helper functions. -$helperName = 'PowerShellGet.LocalizationHelper' -$dscResourcesFolderFilePath = Join-Path -Path $resourceModuleRoot -ChildPath "Modules\$helperName\$helperName.psm1" -Import-Module -Name $dscResourcesFolderFilePath - -$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_PSModule' -ScriptRoot $PSScriptRoot - -# Import resource helper functions. -$helperName = 'PowerShellGet.ResourceHelper' -$dscResourcesFolderFilePath = Join-Path -Path $resourceModuleRoot -ChildPath "Modules\$helperName\$helperName.psm1" -Import-Module -Name $dscResourcesFolderFilePath -Force - -<# - .SYNOPSIS - This DSC resource provides a mechanism to download PowerShell modules from the PowerShell - Gallery and install it on your computer. - - Get-TargetResource returns the current state of the resource. - - .PARAMETER Name - Specifies the name of the PowerShell module to be installed or uninstalled. - - .PARAMETER Repository - Specifies the name of the module source repository where the module can be found. - - .PARAMETER Version - Provides the version of the module you want to install or uninstall. - - .PARAMETER NoClobber - Does not allow the installation of modules if other existing module on the computer have cmdlets - of the same name. - - .PARAMETER SkipPublisherCheck - Allows the installation of modules that have not been catalog signed. -#> -function Get-TargetResource { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-ForEachStatement', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $Repository = 'PSGallery', - - [Parameter()] - [System.String] - $Version, - - [Parameter()] - [System.Boolean] - $NoClobber, - - [Parameter()] - [System.Boolean] - $SkipPublisherCheck - ) - - $returnValue = @{ - Ensure = 'Absent' - Name = $Name - Repository = $Repository - Priority = $null - Description = $null - Guid = $null - ModuleBase = $null - ModuleType = $null - Author = $null - InstalledVersion = $null - Version = $Version - NoClobber = $NoClobber - SkipPublisherCheck = $SkipPublisherCheck - InstallationPolicy = $null - Trusted = $false - } - - Write-Verbose -Message ($localizedData.GetTargetResourceMessage -f $Name) - Write-Verbose("Name:") - - Write-Verbose("Name: $Name") - Write-Verbose("Repository: $Repository") - Write-Verbose("Version: $Version") - - $extractedArguments = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames ('Name', 'Repository', 'Version') - - # Get the module with the right version and repository properties. - $modules = Get-RightModule @extractedArguments -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - - # If the module is found, the count > 0 - if ($modules.Count -gt 0) { - Write-Verbose -Message ($localizedData.ModuleFound -f $Name) - - # Find a module with the latest version and return its properties. - $latestModule = $modules[0] - - foreach ($module in $modules) { - if ($module.Version -gt $latestModule.Version) { - $latestModule = $module - } - } - - # Check if the repository matches. - $repositoryName = Get-ModuleRepositoryName -Module $latestModule -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - - ##if ($repositoryName) { - ## $installationPolicy = Get-InstallationPolicy -RepositoryName $repositoryName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - ##} - - ##if ($installationPolicy) { - ## $installationPolicyReturnValue = 'Trusted' - ## $Trusted = $true - ##} - ##else { - ##$installationPolicyReturnValue = 'Untrusted' - ##$Trusted = $false - ##} - - Write-Verbose("returning value") - $returnValue.Ensure = 'Present' - $returnValue.Repository = $repositoryName - $returnValue.Description = $latestModule.Description - $returnValue.Guid = $latestModule.Guid - $returnValue.ModuleBase = $latestModule.ModuleBase - $returnValue.ModuleType = $latestModule.ModuleType - $returnValue.Author = $latestModule.Author - $returnValue.InstalledVersion = $latestModule.Version - $returnValue.InstallationPolicy = $installationPolicyReturnValue - $returnValue.Trusted = $trusted - } - else { - Write-Verbose -Message ($localizedData.ModuleNotFound -f $Name) - } - - return $returnValue -} - -<# - .SYNOPSIS - This DSC resource provides a mechanism to download PowerShell modules from the PowerShell - Gallery and install it on your computer. - - Test-TargetResource validates whether the resource is currently in the desired state. - - .PARAMETER Ensure - Determines whether the module to be installed or uninstalled. - - .PARAMETER Name - Specifies the name of the PowerShell module to be installed or uninstalled. - - .PARAMETER Repository - Specifies the name of the module source repository where the module can be found. - - .PARAMETER InstallationPolicy - Determines whether you trust the source repository where the module resides. - - .PARAMETER Trusted - Determines whether you trust the source repository where the module resides. - - .PARAMETER Version - Provides the version of the module you want to install or uninstall. - - .PARAMETER NoClobber - Does not allow the installation of modules if other existing module on the computer have cmdlets - of the same name. - - .PARAMETER SkipPublisherCheck - Allows the installation of modules that have not been catalog signed. -#> -function Test-TargetResource { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter()] - [ValidateSet('Present', 'Absent')] - [System.String] - $Ensure = 'Present', - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $Repository = 'PSGallery', - - [Parameter()] - [ValidateSet('Trusted', 'Untrusted')] - [System.String] - $InstallationPolicy = 'Untrusted', - - [Parameter()] - [System.Boolean] - $Trusted = $false, - - [Parameter()] - [System.String] - $Version, - - [Parameter()] - [System.Boolean] - $NoClobber, - - [Parameter()] - [System.Boolean] - $SkipPublisherCheck - ) - - Write-Verbose -Message ($localizedData.TestTargetResourceMessage -f $Name) - - $extractedArguments = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames ('Name', 'Repository', 'Version') - - $status = Get-TargetResource @extractedArguments - - # The ensure returned from Get-TargetResource is not equal to the desired $Ensure. - if ($status.Ensure -ieq $Ensure) { - Write-Verbose -Message ($localizedData.InDesiredState -f $Name) - return $true - } - else { - Write-Verbose -Message ($localizedData.NotInDesiredState -f $Name) - return $false - } -} - -<# - .SYNOPSIS - This DSC resource provides a mechanism to download PowerShell modules from the PowerShell - Gallery and install it on your computer. - - Set-TargetResource sets the resource to the desired state. "Make it so". - - .PARAMETER Ensure - Determines whether the module to be installed or uninstalled. - - .PARAMETER Name - Specifies the name of the PowerShell module to be installed or uninstalled. - - .PARAMETER Repository - Specifies the name of the module source repository where the module can be found. - - .PARAMETER InstallationPolicy - Determines whether you trust the source repository where the module resides. - - .PARAMETER Trusted - Determines whether you trust the source repository where the module resides. - - .PARAMETER Version - Provides the version of the module you want to install or uninstall. - - .PARAMETER NoClobber - Does not allow the installation of modules if other existing module on the computer have cmdlets - of the same name. - - .PARAMETER SkipPublisherCheck - Allows the installation of modules that have not been catalog signed. -#> -function Set-TargetResource { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-ForEachStatement', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-TryStatement', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-CatchClause', '')] - [CmdletBinding()] - param - ( - [Parameter()] - [ValidateSet('Present', 'Absent')] - [System.String] - $Ensure = 'Present', - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $Repository = 'PSGallery', - - [Parameter()] - [ValidateSet('Trusted', 'Untrusted')] - [System.String] - $InstallationPolicy = 'Untrusted', - - [Parameter()] - [System.Boolean] - $Trusted = $false, - - [Parameter()] - [System.String] - $Version, - - [Parameter()] - [System.Boolean] - $NoClobber, - - [Parameter()] - [System.Boolean] - $SkipPublisherCheck - ) - - # Validate the repository argument - if ($PSBoundParameters.ContainsKey('Repository')) { - #Test-ParameterValue -Value $Repository -Type 'PackageSource' -Verbose - } - - if ($Ensure -ieq 'Present') { - # Version check - $extractedArguments = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames ('Version') - - # $null = Test-VersionParameter @extractedArguments - - $trusted = $null - $moduleFound = $null - - try { - $extractedArguments = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames ('Name', 'Repository', 'Version') - - Write-Verbose -Message ($localizedData.StartFindModule -f $Name) - Write-verbose ("Name is: $name") - Write-verbose ("Repository is: $repository") - Write-verbose ("Version is: $Version") - - $modules = Find-PSResource @extractedArguments -ErrorVariable ev -ErrorAction SilentlyContinue - - Write-verbose ("modules is: $modules") - $moduleFound = $modules[0] - } - catch { - $errorMessage = $script:localizedData.ModuleNotFoundInRepository -f $Name - New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ - } - - - foreach ($m in $modules) { - # Check for the installation policy. - #$trusted = Get-InstallationPolicy -RepositoryName $m.Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - - # Stop the loop if found a trusted repository. - #if ($trusted) { - # $moduleFound = $m - # break; - #} - } - - try { - # The repository is trusted, so we install it. - #if ($trusted) { - # Write-Verbose -Message ($localizedData.StartInstallModule -f $Name, $moduleFound.Version.toString(), $moduleFound.Repository) - - # Extract the installation options. - ## $extractedSwitches = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters -ArgumentNames ('Force', 'AllowClobber', 'SkipPublisherCheck') - - ## $moduleFound | Install-Module @extractedSwitches 2>&1 | out-string | Write-Verbose - Install-PSResource -name $moduleFound.Name -Repository $moduleFound.Repository -version $moduleFound.Version -TrustRepository:$true -NoClobber:$NoClobber -Verbose #$SkipPublisherCheck, - - ##} - # The repository is untrusted but user's installation policy is trusted, so we install it with a warning. - ##elseif ($InstallationPolicy -ieq $true) { - ## Write-Warning -Message ($localizedData.InstallationPolicyWarning -f $Name, $modules[0].Repository, $InstallationPolicy) - - # Extract installation options (Force implied by InstallationPolicy). - ## $extractedSwitches = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters -ArgumentNames ('AllowClobber', 'SkipPublisherCheck') - - # If all the repositories are untrusted, we choose the first one. - ## $modules[0] | Install-Module @extractedSwitches -Force 2>&1 | out-string | Write-Verbose - ## } - # Both user and repository is untrusted - ##else { - ## $errorMessage = $script:localizedData.InstallationPolicyFailed -f $InstallationPolicy, 'Untrusted' - ## New-InvalidOperationException -Message $errorMessage - ##} - - Write-Verbose -Message ($localizedData.InstalledSuccess -f $Name) - } - catch { - $errorMessage = $script:localizedData.FailToInstall -f $Name - New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ - } - } - # Ensure=Absent - else { - - $extractedArguments = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames ('Name', 'Repository', 'Version') - - # Get the module with the right version and repository properties. - $modules = Get-RightModule @extractedArguments - - if (-not $modules) { - $errorMessage = $script:localizedData.ModuleWithRightPropertyNotFound -f $Name - New-InvalidOperationException -Message $errorMessage - } - - foreach ($module in $modules) { - # Get the path where the module is installed. - $path = $module.ModuleBase - - Write-Verbose -Message ($localizedData.StartUnInstallModule -f $Name) - - try { - <# - There is no Uninstall-Module cmdlet for Windows PowerShell 4.0, - so we will remove the ModuleBase folder as an uninstall operation. - #> - Microsoft.PowerShell.Management\Remove-Item -Path $path -Force -Recurse - - Write-Verbose -Message ($localizedData.UnInstalledSuccess -f $module.Name) - } - catch { - $errorMessage = $script:localizedData.FailToUninstall -f $module.Name - New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ - } - } # foreach - } # Ensure=Absent -} - -<# - .SYNOPSIS - This is a helper function. It returns the modules that meet the specified versions and the repository requirements. - - .PARAMETER Name - Specifies the name of the PowerShell module. - - .PARAMETER Version - Provides the version of the module you want to install or uninstall. - - .PARAMETER Repository - Specifies the name of the module source repository where the module can be found. -#> -function Get-RightModule { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-ForEachStatement', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Name, - - [Parameter()] - [System.String] - $Version, - - [Parameter()] - [System.String] - $Repository - ) - - Write-Verbose -Message ($localizedData.StartGetModule -f $($Name)) - - $modules = Microsoft.PowerShell.Core\Get-Module -Name $Name -ListAvailable -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - - if (-not $modules) { - return $null - } - - <# - As Get-Module does not take RequiredVersion, MinimumVersion, MaximumVersion, or Repository, - below we need to check whether the modules are containing the right version and repository - location. - #> - - $extractedArguments = New-SplatParameterHashTable -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames ('Version') - $returnVal = @() - - foreach ($m in $modules) { - $versionMatch = $false - $installedVersion = $m.Version - - # Case 1 - a user provides none of RequiredVersion, MinimumVersion, MaximumVersion - if ($extractedArguments.Count -eq 0) { - $versionMatch = $true - } - - ########### COME BACK HERE - # Case 2 - a user provides RequiredVersion - elseif ($extractedArguments.ContainsKey('Version')) { - # Check if it matches with the installed version - $versionMatch = ($installedVersion -eq [System.Version] $RequiredVersion) - } - <# - else { - - # Case 3 - a user provides MinimumVersion - if ($extractedArguments.ContainsKey('MinimumVersion')) { - $versionMatch = ($installedVersion -ge [System.Version] $extractedArguments['MinimumVersion']) - } - - # Case 4 - a user provides MaximumVersion - if ($extractedArguments.ContainsKey('MaximumVersion')) { - $isLessThanMax = ($installedVersion -le [System.Version] $extractedArguments['MaximumVersion']) - - if ($extractedArguments.ContainsKey('MinimumVersion')) { - $versionMatch = $versionMatch -and $isLessThanMax - } - else { - $versionMatch = $isLessThanMax - } - } - - # Case 5 - Both MinimumVersion and MaximumVersion are provided. It's covered by the above. - # Do not return $false yet to allow the foreach to continue - if (-not $versionMatch) { - Write-Verbose -Message ($localizedData.VersionMismatch -f $Name, $installedVersion) - $versionMatch = $false - } - } - #> - - # Case 6 - Version matches but need to check if the module is from the right repository. - if ($versionMatch) { - # A user does not provide Repository, we are good - if (-not $PSBoundParameters.ContainsKey('Repository')) { - Write-Verbose -Message ($localizedData.ModuleFound -f "$Name $installedVersion") - $returnVal += $m - } - else { - # Check if the Repository matches - $sourceName = Get-ModuleRepositoryName -Module $m - - if ($Repository -ieq $sourceName) { - Write-Verbose -Message ($localizedData.ModuleFound -f "$Name $installedVersion") - $returnVal += $m - } - else { - Write-Verbose -Message ($localizedData.RepositoryMismatch -f $($Name), $($sourceName)) - } - } - } - } # foreach - - return $returnVal -} - -<# - .SYNOPSIS - This is a helper function that returns the module's repository name. - - .PARAMETER Module - Specifies the name of the PowerShell module. -#> -function Get-ModuleRepositoryName { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.Object] - $Module - ) - - <# - RepositorySourceLocation property is supported in PS V5 only. To work with the earlier - PowerShell version, we need to do a different way. PSGetModuleInfo.xml exists for any - PowerShell modules downloaded through PSModule provider. - #> - $psGetModuleInfoFileName = 'PSGetModuleInfo.xml' - $psGetModuleInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $Module.ModuleBase -ChildPath $psGetModuleInfoFileName - - Write-Verbose -Message ($localizedData.FoundModulePath -f $psGetModuleInfoPath) - - if (Microsoft.PowerShell.Management\Test-path -Path $psGetModuleInfoPath) { - $psGetModuleInfo = Microsoft.PowerShell.Utility\Import-Clixml -Path $psGetModuleInfoPath - - return $psGetModuleInfo.Repository - } -} diff --git a/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mfl b/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mfl deleted file mode 100644 index db8de1e01..000000000 --- a/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mfl +++ /dev/null @@ -1,21 +0,0 @@ -#pragma namespace("\\\\.\\root\\default") -instance of __namespace{ name="MS_409";}; -#pragma namespace("\\\\.\\root\\default\\MS_409") - -[AMENDMENT, LOCALE("MS_409")] -class MSFT_PSModule : OMI_BaseResource -{ - [Key,Description("Name of the module\n") : Amended] String Name; - [Description("Whether the module is to be installed or uninstalled.\nPresent {default} \nAbsent \n") : Amended] String Ensure; - [Description("The name of the module source where the module can be found.\n") : Amended] String Repository; - [Description("Whether the package is trusted or untrusted.\nTrusted {default} \nUntrusted \n") : Amended] String InstallationPolicy; - [Description("The version of the module.\n") : Amended] String Version; - [Description("Does not allow installation when existing cmdlets of the same name exist.\n" : Amended] Boolean NoClobber; - [Description("Allows installation when module is not signed.\n" : Amended] Boolean SkipPublisherCheck; - [Description("The brief description of the module.\n") : Amended] string Description; - [Description("The version of the module that is installed.\n") : Amended] String InstalledVersion; - [Description("The identifier of the module.\n") : Amended] String Guid; - [Description("The base location where the module is installed.\n") : Amended] String ModuleBase; - [Description("The type of the module.\n") : Amended] String ModuleType; - [Description("The author of the module.\n") : Amended] String Author; -}; diff --git a/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mof b/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mof deleted file mode 100644 index 400185899..000000000 --- a/DSC/DscResources/MSFT_PSModule/MSFT_PSModule.schema.mof +++ /dev/null @@ -1,19 +0,0 @@ - -[ClassVersion("1.0.0.0"),FriendlyName("PSModule")] -class MSFT_PSModule : OMI_BaseResource -{ - [Key] String Name; - [Write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] String Ensure; - [Write] String Repository; - [Write,ValueMap{"Trusted", "Untrusted"},Values{"Trusted", "Untrusted"}] String InstallationPolicy; - [Write] Boolean Trusted; - [Write] String Version; - [Write] Boolean NoClobber; - [Write] Boolean SkipPublisherCheck; - [Read] string Description; - [Read] String InstalledVersion; - [Read] String Guid; - [Read] String ModuleBase; - [Read] String ModuleType; - [Read] String Author; -}; diff --git a/DSC/DscResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 b/DSC/DscResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 deleted file mode 100644 index e1a37ac0f..000000000 --- a/DSC/DscResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) Microsoft Corporation. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# culture = "en-US" -ConvertFrom-StringData -StringData @' - FailToUninstall = Failed to uninstall the module '{0}'. - FailToInstall = Failed to install the module '{0}'. - InDesiredState = Resource '{0}' is in the desired state. - NotInDesiredState = Resource '{0}' is not in the desired state. - ModuleFound = Module '{0}' is found on the node. - ModuleNotFound = Module '{0}' is not found on the node. - ModuleWithRightPropertyNotFound = Module '{0}' with the right version or other properties not found in the node. - ModuleNotFoundInRepository = Module '{0}' with the right version or other properties not found in the repository. - StartGetModule = Begin invoking Get-Module '{0}'. - StartFindModule = Begin invoking Find-PSResource '{0}'. - StartInstallModule = Begin invoking Install-PSResource '{0}' version '{1}' from '{2}' repository. - StartUnInstallModule = Begin invoking Remove-Item to remove the module '{0}' from the file system. - InstalledSuccess = Successfully installed the module '{0}' - UnInstalledSuccess = Successfully uninstalled the module '{0}' - VersionMismatch = The installed module '{0}' has the version: '{1}' - RepositoryMismatch = The installed module '{0}' is from the '{1}' repository. - FoundModulePath = Found the module path: '{0}'. - InstallationPolicyWarning = The module '{0}' was installed from the untrusted repository' {1}'. The InstallationPolicy is set to '{2}' to override the repository installation policy. If you trust the repository, set the repository installation policy to 'Trusted', that will also remove this warning. - InstallationPolicyFailed = The current installation policy do not allow installation from this repository. Your current installation policy is '{0}' and the repository installation policy is '{1}'. If you trust the repository, either change the repository installation policy, or set the parameter InstallationPolicy to 'Trusted' to override the repository installation policy. - GetTargetResourceMessage = Getting the current state of the module '{0}'. - TestTargetResourceMessage = Determining if the module '{0}' is in the desired state. -'@ diff --git a/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.psm1 b/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.psm1 deleted file mode 100644 index 30c0dfe44..000000000 --- a/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.psm1 +++ /dev/null @@ -1,273 +0,0 @@ -$resourceModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent - -# Import localization helper functions. -$helperName = 'PowerShellGet.LocalizationHelper' -$dscResourcesFolderFilePath = Join-Path -Path $resourceModuleRoot -ChildPath "Modules\$helperName\$helperName.psm1" -Import-Module -Name $dscResourcesFolderFilePath - -$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_PSRepository' -ScriptRoot $PSScriptRoot - -# Import resource helper functions. -$helperName = 'PowerShellGet.ResourceHelper' -$dscResourcesFolderFilePath = Join-Path -Path $resourceModuleRoot -ChildPath "Modules\$helperName\$helperName.psm1" -Import-Module -Name $dscResourcesFolderFilePath - -<# - .SYNOPSIS - Returns the current state of the repository. - - .PARAMETER Name - Specifies the name of the repository to manage. -#> -function Get-TargetResource { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [Parameter(Mandatory = $true)] - [System.String] - $Name - ) - - $returnValue = @{ - Ensure = 'Absent' - Name = $Name - URL = $null - Priority = $null - #InstallationPolicy = $null - #Trusted = $false - Registered = $false - } - - Write-Verbose -Message ($localizedData.GetTargetResourceMessage -f $Name) - - $repository = Get-PSResourceRepository -Name $Name -ErrorAction 'SilentlyContinue' - - if ($repository) { - $returnValue.Ensure = 'Present' - $returnValue.SourceLocation = $repository.SourceLocation - $returnValue.ScriptSourceLocation = $repository.ScriptSourceLocation - $returnValue.PublishLocation = $repository.PublishLocation - $returnValue.ScriptPublishLocation = $repository.ScriptPublishLocation - $returnValue.InstallationPolicy = $repository.InstallationPolicy - $returnValue.PackageManagementProvider = $repository.PackageManagementProvider - $returnValue.Trusted = $repository.Trusted - $returnValue.Registered = $repository.Registered - } - else { - Write-Verbose -Message ($localizedData.RepositoryNotFound -f $Name) - } - - return $returnValue -} - -<# - .SYNOPSIS - Determines if the repository is in the desired state. - - .PARAMETER Ensure - If the repository should be present or absent on the server - being configured. Default values is 'Present'. - - .PARAMETER Name - Specifies the name of the repository to manage. - - .PARAMETER SourceLocation - Specifies the URI for discovering and installing modules from - this repository. A URI can be a NuGet server feed, HTTP, HTTPS, - FTP or file location. - - .PARAMETER ScriptSourceLocation - Specifies the URI for the script source location. - - .PARAMETER PublishLocation - Specifies the URI of the publish location. For example, for - NuGet-based repositories, the publish location is similar - to http://someNuGetUrl.com/api/v2/Packages. - - .PARAMETER ScriptPublishLocation - Specifies the URI for the script publish location. - - .PARAMETER InstallationPolicy - Specifies the installation policy. Valid values are 'Trusted' - or 'Untrusted'. The default value is 'Untrusted'. - - .PARAMETER PackageManagementProvider - Specifies a OneGet package provider. Default value is 'NuGet'. -#> -function Test-TargetResource { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [Parameter()] - [ValidateSet('Present', 'Absent')] - [System.String] - $Ensure = 'Present', - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $URL, - - [Parameter()] - [System.String] - $Priority, - - [Parameter()] - [ValidateSet('Trusted', 'Untrusted')] - [System.String] - $InstallationPolicy = 'Untrusted' - ) - - Write-Verbose -Message ($localizedData.TestTargetResourceMessage -f $Name) - - $returnValue = $false - - $getTargetResourceResult = Get-TargetResource -Name $Name - - if ($Ensure -eq $getTargetResourceResult.Ensure) { - if ($getTargetResourceResult.Ensure -eq 'Present' ) { - $returnValue = Test-DscParameterState ` - -CurrentValues $getTargetResourceResult ` - -DesiredValues $PSBoundParameters ` - -ValuesToCheck @( - 'URL' - 'Priority' - #'InstallationPolicy' - ) - } - else { - $returnValue = $true - } - } - - if ($returnValue) { - Write-Verbose -Message ($localizedData.InDesiredState -f $Name) - } - else { - Write-Verbose -Message ($localizedData.NotInDesiredState -f $Name) - } - - return $returnValue -} - -<# - .SYNOPSIS - Creates, removes or updates the repository. - - .PARAMETER Ensure - If the repository should be present or absent on the server - being configured. Default values is 'Present'. - - .PARAMETER Name - Specifies the name of the repository to manage. - - .PARAMETER SourceLocation - Specifies the URI for discovering and installing modules from - this repository. A URI can be a NuGet server feed, HTTP, HTTPS, - FTP or file location. - - .PARAMETER ScriptSourceLocation - Specifies the URI for the script source location. - - .PARAMETER PublishLocation - Specifies the URI of the publish location. For example, for - NuGet-based repositories, the publish location is similar - to http://someNuGetUrl.com/api/v2/Packages. - - .PARAMETER ScriptPublishLocation - Specifies the URI for the script publish location. - - .PARAMETER InstallationPolicy - Specifies the installation policy. Valid values are 'Trusted' - or 'Untrusted'. The default value is 'Untrusted'. - - .PARAMETER PackageManagementProvider - Specifies a OneGet package provider. Default value is 'NuGet'. -#> -function Set-TargetResource { - <# - These suppressions are added because this repository have other Visual Studio Code workspace - settings than those in DscResource.Tests DSC test framework. - Only those suppression that contradict this repository guideline is added here. - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-FunctionBlockBraces', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-IfStatement', '')] - [CmdletBinding()] - param - ( - [Parameter()] - [ValidateSet('Present', 'Absent')] - [System.String] - $Ensure = 'Present', - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $URL, - - [Parameter()] - [ValidateSet('Trusted', 'Untrusted')] - [System.String] - $InstallationPolicy = 'Untrusted' - ) - - $getTargetResourceResult = Get-TargetResource -Name $Name - - Write-Verbose("Name: $Name") - Write-Verbose("URL: $URL") - # Determine if the repository should be present or absent. - if ($Ensure -eq 'Present') { - $repositoryParameters = New-SplatParameterHashTable ` - -FunctionBoundParameters $PSBoundParameters ` - -ArgumentNames @( - 'Name' - 'URL' - #'InstallationPolicy' - ) - - # Determine if the repository is already present. - if ($getTargetResourceResult.Ensure -eq 'Present') { - Write-Verbose -Message ($localizedData.RepositoryExist -f $Name) - - # Repository exist, update the properties. - Set-PSResourceRepository @repositoryParameters -ErrorAction 'Stop' - } - else { - Write-Verbose -Message ($localizedData.RepositoryDoesNotExist -f $Name) - - # Repository did not exist, create the repository. - Register-PSResourceRepository @repositoryParameters -ErrorAction 'Stop' - } - } - else { - if ($getTargetResourceResult.Ensure -eq 'Present') { - Write-Verbose -Message ($localizedData.RemoveExistingRepository -f $Name) - - # Repository did exist, remove the repository. - Unregister-PSResourceRepository -Name $Name -ErrorAction 'Stop' - } - } -} diff --git a/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mfl b/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mfl deleted file mode 100644 index 20d1871cc..000000000 --- a/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mfl +++ /dev/null @@ -1,15 +0,0 @@ -#pragma namespace("\\\\.\\root\\default") -instance of __namespace{ name="MS_409";}; -#pragma namespace("\\\\.\\root\\default\\MS_409") - -[AMENDMENT, LOCALE("MS_409")] -class MSFT_PSModule : OMI_BaseResource -{ - [Key, Description("Specifies the name of the repository to manage.") : Amended] String Name; - [Description("If the repository should be present or absent on the server being configured. Default values is 'Present'.") : Amended] String Ensure; - [Description("Specifies the URI for discovering and installing modules from this repository. A URI can be a NuGet server feed, HTTP, HTTPS, FTP or file location.") : Amended] String URL; - [Description("Specifies the priority for the repository.") : Amended] String Priority; - [Description("Specifies the installation policy. Valid values are 'Trusted' or 'Untrusted'. The default value is 'Untrusted'.") : Amended] String InstallationPolicy; - [Description("Specifies if the repository is trusted.") : Amended] Boolean Trusted; - [Description("Specifies if the repository is registered.") : Amended] Boolean Registered; -}; diff --git a/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mof b/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mof deleted file mode 100644 index 46dcb7f49..000000000 --- a/DSC/DscResources/MSFT_PSRepository/MSFT_PSRepository.schema.mof +++ /dev/null @@ -1,11 +0,0 @@ -[ClassVersion("1.0.0.0"),FriendlyName("PSRepository")] -class MSFT_PSRepository : OMI_BaseResource -{ - [Key] String Name; - [Write, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; - [Write] String URL; - [Write] String Priority; - [Write, ValueMap{"Trusted","Untrusted"}, Values{"Trusted","Untrusted"}] String InstallationPolicy; - [Read] Boolean Trusted; - [Read] Boolean Registered; -}; diff --git a/DSC/DscResources/MSFT_PSRepository/en-US/MSFT_PSRepository.strings.psd1 b/DSC/DscResources/MSFT_PSRepository/en-US/MSFT_PSRepository.strings.psd1 deleted file mode 100644 index 81c7c7555..000000000 --- a/DSC/DscResources/MSFT_PSRepository/en-US/MSFT_PSRepository.strings.psd1 +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) Microsoft Corporation. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# culture = "en-US" -ConvertFrom-StringData -StringData @' - GetTargetResourceMessage = Return the current state of the repository '{0}'. - RepositoryNotFound = The repository '{0}' was not found. - TestTargetResourceMessage = Determining if the repository '{0}' is in the desired state. - InDesiredState = Repository '{0}' is in the desired state. - NotInDesiredState = Repository '{0}' is not in the desired state. - RepositoryExist = Updating the properties of the repository '{0}'. - RepositoryDoesNotExist = Creating the repository '{0}'. - RemoveExistingRepository = Removing the repository '{0}'. -'@ diff --git a/DSC/Examples/.gitattributes b/DSC/Examples/.gitattributes deleted file mode 100644 index 92be83e26..000000000 --- a/DSC/Examples/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text eol=crlf diff --git a/DSC/Examples/README.md b/DSC/Examples/README.md deleted file mode 100644 index a027a5494..000000000 --- a/DSC/Examples/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Examples - -## Resource examples - -These are the links to the examples for each individual resource. - -- [PSModule](Resources/PSModule) -- [PSRepository](Resources/PSRepository) diff --git a/DSC/Examples/Resources/PSModule/1-PSModule_InstallModuleConfig.ps1 b/DSC/Examples/Resources/PSModule/1-PSModule_InstallModuleConfig.ps1 deleted file mode 100644 index e8583e891..000000000 --- a/DSC/Examples/Resources/PSModule/1-PSModule_InstallModuleConfig.ps1 +++ /dev/null @@ -1,73 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID 45d8677b-817f-4b2a-8d47-a802c4f758b1 -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module. - - .DESCRIPTION - Configuration that installs a module. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER ModuleName - The name of the module to be downloaded and installed. - - .EXAMPLE - PSModule_InstallModuleConfig -ModuleName 'PSLogging' - - Compiles a configuration that downloads and installs the module 'PSLogging'. - - .EXAMPLE - $configurationParameters = @{ - ModuleName = 'PSLogging' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSModule_InstallModuleConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'PSLogging'. - - Replace the and with correct values. -#> -configuration PSModule_InstallModuleConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSModule 'InstallModule' - { - Name = $ModuleName - } - } -} diff --git a/DSC/Examples/Resources/PSModule/2-PSModule_InstallModuleTrustedConfig.ps1 b/DSC/Examples/Resources/PSModule/2-PSModule_InstallModuleTrustedConfig.ps1 deleted file mode 100644 index 84b6635c4..000000000 --- a/DSC/Examples/Resources/PSModule/2-PSModule_InstallModuleTrustedConfig.ps1 +++ /dev/null @@ -1,76 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID d16da19d-439a-4730-8e02-6928d6a8ed28 -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module, and overrides the - current trust level for the package source. - - .DESCRIPTION - Configuration that installs a module, and overrides the - current trust level for the package source. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER ModuleName - The name of the module to be downloaded and installed. - - .EXAMPLE - PSModule_InstallModuleTrustedConfig -ModuleName 'PSLogging' - - Compiles a configuration that downloads and installs the module 'PSLogging'. - - .EXAMPLE - $configurationParameters = @{ - ModuleName = 'PSLogging' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSModule_InstallModuleTrustedConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'PSLogging'. - - Replace the and with correct values. -#> -configuration PSModule_InstallModuleTrustedConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSModule 'InstallModuleAsTrusted' - { - Name = $ModuleName - InstallationPolicy = 'Trusted' - } - } -} diff --git a/DSC/Examples/Resources/PSModule/3-PSModule_InstallModuleAllowClobberConfig.ps1 b/DSC/Examples/Resources/PSModule/3-PSModule_InstallModuleAllowClobberConfig.ps1 deleted file mode 100644 index 335216206..000000000 --- a/DSC/Examples/Resources/PSModule/3-PSModule_InstallModuleAllowClobberConfig.ps1 +++ /dev/null @@ -1,74 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID 47eb256b-9c81-437d-9148-890bc94f15ed -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module and allows clobber. - - .DESCRIPTION - Configuration that installs a module and allows clobber. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER ModuleName - The name of the module to be downloaded and installed. - - .EXAMPLE - PSModule_InstallModuleAllowClobberConfig -ModuleName 'SqlServer' - - Compiles a configuration that downloads and installs the module 'SqlServer'. - - .EXAMPLE - $configurationParameters = @{ - ModuleName = 'SqlServer' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSModule_InstallModuleAllowClobberConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'SqlServer'. - - Replace the and with correct values. -#> -configuration PSModule_InstallModuleAllowClobberConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSModule 'InstallModuleAndAllowClobber' - { - Name = $ModuleName - NoClobber = $false - } - } -} diff --git a/DSC/Examples/Resources/PSModule/4-PSModule_InstallModuleSpecificVersionConfig.ps1 b/DSC/Examples/Resources/PSModule/4-PSModule_InstallModuleSpecificVersionConfig.ps1 deleted file mode 100644 index 5f6b8cb2f..000000000 --- a/DSC/Examples/Resources/PSModule/4-PSModule_InstallModuleSpecificVersionConfig.ps1 +++ /dev/null @@ -1,83 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID cbed3f85-50cf-49ca-bde4-1b3ef0e33687 -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module with a specific version. - - .DESCRIPTION - Configuration that installs a module with a specific version. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER ModuleName - The name of the module to be downloaded and installed. - - .PARAMETER Version - The version of the module to download and install. - - .EXAMPLE - PSModule_InstallModuleSpecificVersionConfig -ModuleName 'SqlServer' -RequiredVersion '21.1.18068' - - Compiles a configuration that downloads and installs the module 'SqlServer'. - - .EXAMPLE - $configurationParameters = @{ - ModuleName = 'SqlServer' - RequiredVersion = '21.1.18068' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSModule_InstallModuleSpecificVersionConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'SqlServer'. - - Replace the and with correct values. -#> -configuration PSModule_InstallModuleSpecificVersionConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Version - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSModule 'InstallModuleAndAllowClobber' - { - Name = $ModuleName - Version = $Version - } - } -} diff --git a/DSC/Examples/Resources/PSModule/5-PSModule_InstallModuleWithinVersionRangeConfig.ps1 b/DSC/Examples/Resources/PSModule/5-PSModule_InstallModuleWithinVersionRangeConfig.ps1 deleted file mode 100644 index 3264218d6..000000000 --- a/DSC/Examples/Resources/PSModule/5-PSModule_InstallModuleWithinVersionRangeConfig.ps1 +++ /dev/null @@ -1,92 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID b3a8515b-9164-4fc5-9df0-e883f6420a83 -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module withing a specific version range. - - .DESCRIPTION - Configuration that installs a module withing a specific version range. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER ModuleName - The name of the module to be downloaded and installed. - - .PARAMETER MinimumVersion - The minimum version of the module to download and install. - - .PARAMETER MaximumVersion - The maximum version of the module to download and install. - - .EXAMPLE - PSModule_InstallModuleWithinVersionRangeConfig -ModuleName 'SqlServer' -MinimumVersion '21.0.17199' -MaximumVersion '21.1.18068' - - Compiles a configuration that downloads and installs the module 'SqlServer'. - - .EXAMPLE - $configurationParameters = @{ - ModuleName = 'SqlServer' - MinimumVersion = '21.0.17199' - MaximumVersion = '21.1.18068' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSModule_InstallModuleWithinVersionRangeConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'SqlServer'. - - Replace the and with correct values. -#> -configuration PSModule_InstallModuleWithinVersionRangeConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $MinimumVersion, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $MaximumVersion - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSModule 'InstallModuleAndAllowClobber' - { - Name = $ModuleName - Version = "[$MinimumVersion, $MaximumVersion]" - } - } -} diff --git a/DSC/Examples/Resources/PSModule/6-PSModule_UninstallModuleConfig.ps1 b/DSC/Examples/Resources/PSModule/6-PSModule_UninstallModuleConfig.ps1 deleted file mode 100644 index b255a121d..000000000 --- a/DSC/Examples/Resources/PSModule/6-PSModule_UninstallModuleConfig.ps1 +++ /dev/null @@ -1,74 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID 83a844ed-4e23-427d-94c9-72bdcae0e1bb -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that uninstalls an installed module. - - .DESCRIPTION - Configuration that uninstalls an installed module. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER ModuleName - The name of the module to be uninstalled. - - .EXAMPLE - PSModule_UninstallModuleConfig -ModuleName 'PSLogging' - - Compiles a configuration that downloads and installs the module 'PSLogging'. - - .EXAMPLE - $configurationParameters = @{ - ModuleName = 'PSLogging' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSModule_UninstallModuleConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'PSLogging'. - - Replace the and with correct values. -#> -configuration PSModule_UninstallModuleConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSModule 'InstallModule' - { - Ensure = 'Absent' - Name = $ModuleName - } - } -} diff --git a/DSC/Examples/Resources/PSRepository/1-PSRepository_AddRepositoryConfig.ps1 b/DSC/Examples/Resources/PSRepository/1-PSRepository_AddRepositoryConfig.ps1 deleted file mode 100644 index 26beff701..000000000 --- a/DSC/Examples/Resources/PSRepository/1-PSRepository_AddRepositoryConfig.ps1 +++ /dev/null @@ -1,76 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID a1f8ee59-31b6-49be-9175-f7a49b5e03f1 -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module. - - .DESCRIPTION - Configuration that installs a module. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER RepositoryName - The name of the repository that will be added. - - .EXAMPLE - PSRepository_AddRepositoryConfig -RepositoryName 'PSTestGallery' - - Compiles a configuration that downloads and installs the module 'PSLogging'. - - .EXAMPLE - $configurationParameters = @{ - RepositoryName = 'PSTestGallery' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSRepository_AddRepositoryConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'PSLogging'. - - Replace the and with correct values. -#> -configuration PSRepository_AddRepositoryConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $RepositoryName - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSRepository 'AddRepository' - { - Name = $RepositoryName - URL = 'https://www.poshtestgallery.com/api/v2' - Priority = 1 - Trusted = 'True' - } - } -} diff --git a/DSC/Examples/Resources/PSRepository/2-PSRepository_RemoveRepositoryConfig.ps1 b/DSC/Examples/Resources/PSRepository/2-PSRepository_RemoveRepositoryConfig.ps1 deleted file mode 100644 index 3dc9abfd2..000000000 --- a/DSC/Examples/Resources/PSRepository/2-PSRepository_RemoveRepositoryConfig.ps1 +++ /dev/null @@ -1,74 +0,0 @@ -<#PSScriptInfo -.VERSION 1.0.0 -.GUID c9a8b46f-12a6-46e1-8c6b-946ac9995aad -.AUTHOR Microsoft Corporation -.COMPANYNAME Microsoft Corporation -.COPYRIGHT -.TAGS DSCConfiguration -.LICENSEURI https://github.com/PowerShell/PowerShellGet/blob/master/LICENSE -.PROJECTURI https://github.com/PowerShell/PowerShellGet -.ICONURI -.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES -.RELEASENOTES First version. -.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core -#> - -#Requires -module PowerShellGet - -<# - .SYNOPSIS - Configuration that installs a module. - - .DESCRIPTION - Configuration that installs a module. - - .PARAMETER NodeName - The names of one or more nodes to compile a configuration for. - Defaults to 'localhost'. - - .PARAMETER RepositoryName - The name of the repository that will be added. - - .EXAMPLE - PSRepository_RemoveRepositoryConfig -RepositoryName 'PSTestGallery' - - Compiles a configuration that downloads and installs the module 'PSLogging'. - - .EXAMPLE - $configurationParameters = @{ - RepositoryName = 'PSTestGallery' - } - Start-AzureRmAutomationDscCompilationJob -ResourceGroupName '' -AutomationAccountName '' -ConfigurationName 'PSRepository_RemoveRepositoryConfig' -Parameters $configurationParameters - - Compiles a configuration in Azure Automation that downloads and installs - the module 'PSLogging'. - - Replace the and with correct values. -#> -configuration PSRepository_RemoveRepositoryConfig -{ - param - ( - [Parameter()] - [System.String[]] - $NodeName = 'localhost', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $RepositoryName - ) - - Import-DscResource -ModuleName 'PowerShellGet' - - Node $nodeName - { - PSRepository 'AddRepository' - { - Ensure = 'Absent' - Name = $RepositoryName - } - } -} diff --git a/DSC/Modules/PowerShellGet.LocalizationHelper/PowerShellGet.LocalizationHelper.psm1 b/DSC/Modules/PowerShellGet.LocalizationHelper/PowerShellGet.LocalizationHelper.psm1 deleted file mode 100644 index 9f6b61253..000000000 --- a/DSC/Modules/PowerShellGet.LocalizationHelper/PowerShellGet.LocalizationHelper.psm1 +++ /dev/null @@ -1,254 +0,0 @@ -<# - .SYNOPSIS - Creates and throws an invalid argument exception. - - .PARAMETER Message - The message explaining why this error is being thrown. - - .PARAMETER ArgumentName - The name of the invalid argument that is causing this error to be thrown. -#> -function New-InvalidArgumentException { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Message, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ArgumentName - ) - - $argumentException = New-Object -TypeName 'ArgumentException' ` - -ArgumentList @($Message, $ArgumentName) - - $newObjectParameters = @{ - TypeName = 'System.Management.Automation.ErrorRecord' - ArgumentList = @($argumentException, $ArgumentName, 'InvalidArgument', $null) - } - - $errorRecord = New-Object @newObjectParameters - - throw $errorRecord -} - -<# - .SYNOPSIS - Creates and throws an invalid operation exception. - - .PARAMETER Message - The message explaining why this error is being thrown. - - .PARAMETER ErrorRecord - The error record containing the exception that is causing this terminating error. -#> -function New-InvalidOperationException { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Message, - - [Parameter()] - [ValidateNotNull()] - [System.Management.Automation.ErrorRecord] - $ErrorRecord - ) - - if ($null -eq $ErrorRecord) { - $invalidOperationException = New-Object -TypeName 'InvalidOperationException' ` - -ArgumentList @($Message) - } - else { - $invalidOperationException = New-Object -TypeName 'InvalidOperationException' ` - -ArgumentList @($Message, $ErrorRecord.Exception) - } - - $newObjectParameters = @{ - TypeName = 'System.Management.Automation.ErrorRecord' - ArgumentList = @( - $invalidOperationException.ToString(), - 'MachineStateIncorrect', - 'InvalidOperation', - $null - ) - } - - $errorRecordToThrow = New-Object @newObjectParameters - - throw $errorRecordToThrow -} - -<# - .SYNOPSIS - Creates and throws an object not found exception. - - .PARAMETER Message - The message explaining why this error is being thrown. - - .PARAMETER ErrorRecord - The error record containing the exception that is causing this terminating error. -#> -function New-ObjectNotFoundException { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Message, - - [Parameter()] - [ValidateNotNull()] - [System.Management.Automation.ErrorRecord] - $ErrorRecord - ) - - if ($null -eq $ErrorRecord) { - $exception = New-Object -TypeName 'System.Exception' ` - -ArgumentList @($Message) - } - else { - $exception = New-Object -TypeName 'System.Exception' ` - -ArgumentList @($Message, $ErrorRecord.Exception) - } - - $newObjectParameters = @{ - TypeName = 'System.Management.Automation.ErrorRecord' - ArgumentList = @( - $exception.ToString(), - 'MachineStateIncorrect', - 'ObjectNotFound', - $null - ) - } - - $errorRecordToThrow = New-Object @newObjectParameters - - throw $errorRecordToThrow -} - -<# - .SYNOPSIS - Creates and throws an invalid result exception. - - .PARAMETER Message - The message explaining why this error is being thrown. - - .PARAMETER ErrorRecord - The error record containing the exception that is causing this terminating error. -#> -function New-InvalidResultException { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Message, - - [Parameter()] - [ValidateNotNull()] - [System.Management.Automation.ErrorRecord] - $ErrorRecord - ) - - if ($null -eq $ErrorRecord) { - $exception = New-Object -TypeName 'System.Exception' ` - -ArgumentList @($Message) - } - else { - $exception = New-Object -TypeName 'System.Exception' ` - -ArgumentList @($Message, $ErrorRecord.Exception) - } - - $newObjectParameters = @{ - TypeName = 'System.Management.Automation.ErrorRecord' - ArgumentList = @( - $exception.ToString(), - 'MachineStateIncorrect', - 'InvalidResult', - $null - ) - } - - $errorRecordToThrow = New-Object @newObjectParameters - - throw $errorRecordToThrow -} - -<# - .SYNOPSIS - Retrieves the localized string data based on the machine's culture. - Falls back to en-US strings if the machine's culture is not supported. - - .PARAMETER ResourceName - The name of the resource as it appears before '.strings.psd1' of the localized string file. - For example: - For WindowsOptionalFeature: MSFT_WindowsOptionalFeature - For Service: MSFT_ServiceResource - For Registry: MSFT_RegistryResource - For Helper: SqlServerDscHelper - - .PARAMETER ScriptRoot - Optional. The root path where to expect to find the culture folder. This is only needed - for localization in helper modules. This should not normally be used for resources. -#> -function Get-LocalizedData { - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ResourceName, - - [Parameter()] - [ValidateNotNullOrEmpty()] - [System.String] - $ScriptRoot - ) - - if ( -not $ScriptRoot ) { - $resourceDirectory = Join-Path -Path $PSScriptRoot -ChildPath $ResourceName - $localizedStringFileLocation = Join-Path -Path $resourceDirectory -ChildPath $PSUICulture - } - else { - $localizedStringFileLocation = Join-Path -Path $ScriptRoot -ChildPath $PSUICulture - } - - if (-not (Test-Path -Path $localizedStringFileLocation)) { - # Fallback to en-US - if ( -not $ScriptRoot ) { - $localizedStringFileLocation = Join-Path -Path $resourceDirectory -ChildPath 'en-US' - } - else { - $localizedStringFileLocation = Join-Path -Path $ScriptRoot -ChildPath 'en-US' - } - } - - Import-LocalizedData ` - -BindingVariable 'localizedData' ` - -FileName "$ResourceName.strings.psd1" ` - -BaseDirectory $localizedStringFileLocation - - return $localizedData -} - -Export-ModuleMember -Function @( - 'New-InvalidArgumentException', - 'New-InvalidOperationException', - 'New-ObjectNotFoundException', - 'New-InvalidResultException', - 'Get-LocalizedData' -) diff --git a/DSC/Modules/PowerShellGet.ResourceHelper/PowerShellGet.ResourceHelper.psm1 b/DSC/Modules/PowerShellGet.ResourceHelper/PowerShellGet.ResourceHelper.psm1 deleted file mode 100644 index 2a01934b9..000000000 --- a/DSC/Modules/PowerShellGet.ResourceHelper/PowerShellGet.ResourceHelper.psm1 +++ /dev/null @@ -1,368 +0,0 @@ -# -# Copyright (c) Microsoft Corporation. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# - -<# - Helper functions for PowerShellGet DSC Resources. -#> - -# Import localization helper functions. -$helperName = 'PowerShellGet.LocalizationHelper' -$resourceModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent -$dscResourcesFolderFilePath = Join-Path -Path $resourceModuleRoot -ChildPath "Modules\$helperName\$helperName.psm1" -Import-Module -Name $dscResourcesFolderFilePath - -# Import Localization Strings -$script:localizedData = Get-LocalizedData -ResourceName 'PowerShellGet.ResourceHelper' -ScriptRoot $PSScriptRoot - -<# - .SYNOPSIS - This is a helper function that extract the parameters from a given table. - - .PARAMETER FunctionBoundParameters - Specifies the hash table containing a set of parameters to be extracted. - - .PARAMETER ArgumentNames - Specifies a list of arguments you want to extract. -#> -function New-SplatParameterHashTable { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] - $FunctionBoundParameters, - - [Parameter(Mandatory = $true)] - [System.String[]] - $ArgumentNames - ) - - Write-Verbose -Message ($script:localizedData.CallingFunction -f $($MyInvocation.MyCommand)) - - $returnValue = @{} - - foreach ($arg in $ArgumentNames) { - if ($FunctionBoundParameters.ContainsKey($arg)) { - # Found an argument we are looking for, so we add it to return collection. - $returnValue.Add($arg, $FunctionBoundParameters[$arg]) - } - } - - return $returnValue -} - -<# - .SYNOPSIS - This is a helper function that validate that a value is correct and used correctly. - - .PARAMETER Value - Specifies the value to be validated. - - .PARAMETER Type - Specifies the type of argument. - - .PARAMETER Type - Specifies the name of the provider. - - .OUTPUTS - None. Throws an error if the test fails. -#> -function Test-ParameterValue { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Value, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Type, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $ProviderName - ) - - Write-Verbose -Message ($script:localizedData.CallingFunction -f $($MyInvocation.MyCommand)) - - switch ($Type) { - 'SourceUri' { - # Checks whether given URI represents specific scheme - # Most common schemes: file, http, https, ftp - $scheme = @('http', 'https', 'file', 'ftp') - - $newUri = $Value -as [System.URI] - $returnValue = ($newUri -and $newUri.AbsoluteURI -and ($scheme -icontains $newUri.Scheme)) - - if ($returnValue -eq $false) { - $errorMessage = $script:localizedData.InValidUri -f $Value - New-InvalidArgumentException -ArgumentName $Type -Message $errorMessage - } - } - - 'DestinationPath' { - $returnValue = Test-Path -Path $Value - - if ($returnValue -eq $false) { - $errorMessage = $script:localizedData.PathDoesNotExist -f $Value - New-InvalidArgumentException -ArgumentName $Type -Message $errorMessage - } - } - - <# - 'PackageSource' { - # Value can be either the package source Name or source Uri. - # Check if the source is a Uri. - $uri = $Value -as [System.URI] - - if ($uri -and $uri.AbsoluteURI) { - # Check if it's a valid Uri. - Test-ParameterValue -Value $Value -Type 'SourceUri' -ProviderName $ProviderName - } - else { - # Check if it's a registered package source name. - # $source = PackageManagement\Get-PackageSource -Name $Value -ProviderName $ProviderName -ErrorVariable ev - - if ((-not $source) -or $ev) { - # We do not need to throw error here as Get-PackageSource does already. - Write-Verbose -Message ($script:localizedData.SourceNotFound -f $source) - } - } - } #> - - default { - $errorMessage = $script:localizedData.UnexpectedArgument -f $Type - New-InvalidArgumentException -ArgumentName $Type -Message $errorMessage - } - } -} - -<# - .SYNOPSIS - This is a helper function that does the version validation. - - .PARAMETER Version - Provides the version. -#> -function Test-VersionParameter { - [CmdletBinding()] - param - ( - [Parameter()] - [System.String] - $Version - ) - - Write-Verbose -Message ($localizedData.CallingFunction -f $($MyInvocation.MyCommand)) - - $isValid = $false - - # Case 1: No further check required if a user provides either none or one of these: minimumVersion, maximumVersion, and requiredVersion. - if ($PSBoundParameters.Count -le 1) { - return $true - } - - ########## COME BACK HERE - # Case 2: #If no RequiredVersion is provided. - #if (-not $PSBoundParameters.ContainsKey('Version')) { - # If no RequiredVersion, both MinimumVersion and MaximumVersion are provided. Otherwise fall into the Case #1. - #$isValid = $PSBoundParameters['MinimumVersion'] -le $PSBoundParameters['MaximumVersion'] - #} - $isValid = $true - # Case 3: RequiredVersion is provided. - # In this case MinimumVersion and/or MaximumVersion also are provided. Otherwise fall in to Case #1. - # This is an invalid case. When RequiredVersion is provided, others are not allowed. so $isValid is false, which is already set in the init. - - if ($isValid -eq $false) { - $errorMessage = $script:localizedData.VersionError - New-InvalidArgumentException ` - -ArgumentName 'RequiredVersion, MinimumVersion or MaximumVersion' ` - -Message $errorMessage - } -} - -<# - .SYNOPSIS - This is a helper function that retrieves the InstallationPolicy from the given repository. - - .PARAMETER RepositoryName - Provides the repository Name. -#> -function Get-InstallationPolicy { - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] $RepositoryName - ) - - Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.MyCommand)) - - $repositoryObject = Get-PSResourceRepository -Name $RepositoryName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - - if ($repositoryObject) { - return $repositoryObject.IsTrusted - } -} - -<# - .SYNOPSIS - This method is used to compare current and desired values for any DSC resource. - - .PARAMETER CurrentValues - This is hash table of the current values that are applied to the resource. - - .PARAMETER DesiredValues - This is a PSBoundParametersDictionary of the desired values for the resource. - - .PARAMETER ValuesToCheck - This is a list of which properties in the desired values list should be checked. - If this is empty then all values in DesiredValues are checked. -#> -function Test-DscParameterState { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] - $CurrentValues, - - [Parameter(Mandatory = $true)] - [System.Object] - $DesiredValues, - - [Parameter()] - [System.Array] - $ValuesToCheck - ) - - $returnValue = $true - - if (($DesiredValues.GetType().Name -ne 'HashTable') ` - -and ($DesiredValues.GetType().Name -ne 'CimInstance') ` - -and ($DesiredValues.GetType().Name -ne 'PSBoundParametersDictionary')) { - $errorMessage = $script:localizedData.PropertyTypeInvalidForDesiredValues -f $($DesiredValues.GetType().Name) - New-InvalidArgumentException -ArgumentName 'DesiredValues' -Message $errorMessage - } - - if (($DesiredValues.GetType().Name -eq 'CimInstance') -and ($null -eq $ValuesToCheck)) { - $errorMessage = $script:localizedData.PropertyTypeInvalidForValuesToCheck - New-InvalidArgumentException -ArgumentName 'ValuesToCheck' -Message $errorMessage - } - - if (($null -eq $ValuesToCheck) -or ($ValuesToCheck.Count -lt 1)) { - $keyList = $DesiredValues.Keys - } - else { - $keyList = $ValuesToCheck - } - - $keyList | ForEach-Object -Process { - if (($_ -ne 'Verbose')) { - if (($CurrentValues.ContainsKey($_) -eq $false) ` - -or ($CurrentValues.$_ -ne $DesiredValues.$_) ` - -or (($DesiredValues.GetType().Name -ne 'CimInstance' -and $DesiredValues.ContainsKey($_) -eq $true) -and ($null -ne $DesiredValues.$_ -and $DesiredValues.$_.GetType().IsArray))) { - if ($DesiredValues.GetType().Name -eq 'HashTable' -or ` - $DesiredValues.GetType().Name -eq 'PSBoundParametersDictionary') { - $checkDesiredValue = $DesiredValues.ContainsKey($_) - } - else { - # If DesiredValue is a CimInstance. - $checkDesiredValue = $false - if (([System.Boolean]($DesiredValues.PSObject.Properties.Name -contains $_)) -eq $true) { - if ($null -ne $DesiredValues.$_) { - $checkDesiredValue = $true - } - } - } - - if ($checkDesiredValue) { - $desiredType = $DesiredValues.$_.GetType() - $fieldName = $_ - if ($desiredType.IsArray -eq $true) { - if (($CurrentValues.ContainsKey($fieldName) -eq $false) ` - -or ($null -eq $CurrentValues.$fieldName)) { - Write-Verbose -Message ($script:localizedData.PropertyValidationError -f $fieldName) -Verbose - - $returnValue = $false - } - else { - $arrayCompare = Compare-Object -ReferenceObject $CurrentValues.$fieldName ` - -DifferenceObject $DesiredValues.$fieldName - if ($null -ne $arrayCompare) { - Write-Verbose -Message ($script:localizedData.PropertiesDoesNotMatch -f $fieldName) -Verbose - - $arrayCompare | ForEach-Object -Process { - Write-Verbose -Message ($script:localizedData.PropertyThatDoesNotMatch -f $_.InputObject, $_.SideIndicator) -Verbose - } - - $returnValue = $false - } - } - } - else { - switch ($desiredType.Name) { - 'String' { - if (-not [System.String]::IsNullOrEmpty($CurrentValues.$fieldName) -or ` - -not [System.String]::IsNullOrEmpty($DesiredValues.$fieldName)) { - Write-Verbose -Message ($script:localizedData.ValueOfTypeDoesNotMatch ` - -f $desiredType.Name, $fieldName, $($CurrentValues.$fieldName), $($DesiredValues.$fieldName)) -Verbose - - $returnValue = $false - } - } - - 'Int32' { - if (-not ($DesiredValues.$fieldName -eq 0) -or ` - -not ($null -eq $CurrentValues.$fieldName)) { - Write-Verbose -Message ($script:localizedData.ValueOfTypeDoesNotMatch ` - -f $desiredType.Name, $fieldName, $($CurrentValues.$fieldName), $($DesiredValues.$fieldName)) -Verbose - - $returnValue = $false - } - } - - { $_ -eq 'Int16' -or $_ -eq 'UInt16'} { - if (-not ($DesiredValues.$fieldName -eq 0) -or ` - -not ($null -eq $CurrentValues.$fieldName)) { - Write-Verbose -Message ($script:localizedData.ValueOfTypeDoesNotMatch ` - -f $desiredType.Name, $fieldName, $($CurrentValues.$fieldName), $($DesiredValues.$fieldName)) -Verbose - - $returnValue = $false - } - } - - default { - Write-Warning -Message ($script:localizedData.UnableToCompareProperty ` - -f $fieldName, $desiredType.Name) - - $returnValue = $false - } - } - } - } - } - } - } - - return $returnValue -} diff --git a/DSC/Modules/PowerShellGet.ResourceHelper/en-US/PowerShellGet.ResourceHelper.strings.psd1 b/DSC/Modules/PowerShellGet.ResourceHelper/en-US/PowerShellGet.ResourceHelper.strings.psd1 deleted file mode 100644 index 8e3522fda..000000000 --- a/DSC/Modules/PowerShellGet.ResourceHelper/en-US/PowerShellGet.ResourceHelper.strings.psd1 +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) Microsoft Corporation. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# culture = "en-US" -ConvertFrom-StringData -StringData @' -###PSLOC - InValidUri = InValid Uri: '{0}'. A sample valid uri: https://www.powershellgallery.com/api/v2/. - PathDoesNotExist = Path: '{0}' does not exist. - VersionError = MinimumVersion should be less than the MaximumVersion. The MinimumVersion or MaximumVersion cannot be used with the RequiredVersion in the same command. - UnexpectedArgument = Unexpected argument type: '{0}'. - SourceNotFound = Source '{0}' not found. Please make sure you register it. - CallingFunction = Calling function '{0}'. - PropertyTypeInvalidForDesiredValues = Property 'DesiredValues' must be either a [System.Collections.Hashtable], [CimInstance] or [PSBoundParametersDictionary]. The type detected was {0}. - PropertyTypeInvalidForValuesToCheck = If 'DesiredValues' is a CimInstance, then property 'ValuesToCheck' must contain a value. - PropertyValidationError = Expected to find an array value for property {0} in the current values, but it was either not present or was null. This has caused the test method to return false. - PropertiesDoesNotMatch = Found an array for property {0} in the current values, but this array does not match the desired state. Details of the changes are below. - PropertyThatDoesNotMatch = {0} - {1} - ValueOfTypeDoesNotMatch = {0} value for property {1} does not match. Current state is '{2}' and desired state is '{3}'. - UnableToCompareProperty = Unable to compare property {0} as the type {1} is not handled by the Test-SQLDSCParameterState cmdlet. -###PSLOC -'@ diff --git a/DSC/Tests/Integration/MSFT_PSModule.Integration.Tests.ps1 b/DSC/Tests/Integration/MSFT_PSModule.Integration.Tests.ps1 deleted file mode 100644 index 721b274d5..000000000 --- a/DSC/Tests/Integration/MSFT_PSModule.Integration.Tests.ps1 +++ /dev/null @@ -1,498 +0,0 @@ -<# - .SYNOPSIS - Integration tests for DSC resource PSModule. - - .NOTES - The header and footer was removed that is usually part of the - DscResource.Tests integration test template. - The header was adding the project folder as a PSModulePath which - collide with the PowerShellGet test framework that copies the - module to the regular PowerShell Module folder. -#> - -$script:dscResourceFriendlyName = 'PSModule' -$script:dcsResourceName = "MSFT_$($script:dscResourceFriendlyName)" - -#region Integration Tests -$configurationFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dcsResourceName).config.ps1" -. $configurationFile - -Describe "$($script:dcsResourceName)_Integration" { - $configurationName = "$($script:dcsResourceName)_SetPackageSourceAsNotTrusted_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - } - - $configurationName = "$($script:dcsResourceName)_InstallWithTrusted_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module1_Name - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_UninstallModule1_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Absent' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module1_Name - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_SetPackageSourceAsTrusted_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - } - - $configurationName = "$($script:dcsResourceName)_DefaultParameters_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module1_Name - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_UsingAllowClobber_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module2_Name - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_UninstallModule2_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Absent' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module2_Name - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_RequiredVersion_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module2_Name - $resourceCurrentState.InstalledVersion | Should -Be $ConfigurationData.AllNodes.Module2_RequiredVersion - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - <# - This should not install a newer version of the module since the - previous test installed a module within the version range. - #> - $configurationName = "$($script:dcsResourceName)_VersionRange_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module2_Name - $resourceCurrentState.InstalledVersion | Should -Be $ConfigurationData.AllNodes.Module2_RequiredVersion - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_UninstallModule2_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Absent' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module2_Name - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - <# - This should install a newer version of the module since no - module is installed within the version range. - #> - $configurationName = "$($script:dcsResourceName)_VersionRange_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Module2_Name - $resourceCurrentState.InstalledVersion | Should -Be $ConfigurationData.AllNodes.Module2_MaximumVersion - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } -} -#endregion diff --git a/DSC/Tests/Integration/MSFT_PSModule.config.ps1 b/DSC/Tests/Integration/MSFT_PSModule.config.ps1 deleted file mode 100644 index fcfa4090b..000000000 --- a/DSC/Tests/Integration/MSFT_PSModule.config.ps1 +++ /dev/null @@ -1,227 +0,0 @@ -#region HEADER -# Integration Test Config Template Version: 1.2.0 -#endregion - -$configFile = [System.IO.Path]::ChangeExtension($MyInvocation.MyCommand.Path, 'json') -if (Test-Path -Path $configFile) -{ - <# - Allows reading the configuration data from a JSON file - for real testing scenarios outside of the CI. - #> - $ConfigurationData = Get-Content -Path $configFile | ConvertFrom-Json -} -else -{ - $ConfigurationData = @{ - AllNodes = @( - @{ - NodeName = 'localhost' - CertificateFile = $env:DscPublicCertificatePath - - Module1_Name = 'PSLogging' - Module2_Name = 'SqlServer' - - Module2_RequiredVersion = '21.0.17279' - Module2_MinimumVersion = '21.0.17199' - Module2_MaximumVersion = '21.1.18068' - } - ) - } -} - -<# - .SYNOPSIS - Changes the repository (package source) 'PSGallery' to not trusted. - - .NOTES - Since the module is installed by SYSTEM as default this is done in - case the PSGallery is already trusted for SYSTEM. -#> -Configuration MSFT_PSModule_SetPackageSourceAsNotTrusted_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSRepository 'Integration_Test' - { - Name = 'PSGallery' - } - } -} - -<# - .SYNOPSIS - Installs a module as trusted. - - .NOTES - This assumes that the package source 'PSGallery' is not trusted for SYSTEM. -#> -Configuration MSFT_PSModule_InstallWithTrusted_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.Module1_Name - } - } -} - -<# - .SYNOPSIS - Uninstalls a module ($Node.Module1_Name). -#> -Configuration MSFT_PSModule_UninstallModule1_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Ensure = 'Absent' - Name = $Node.Module1_Name - } - } -} - -<# - .SYNOPSIS - Changes the repository (package source) 'PSGallery' to trusted. - - .NOTES - Since the module is installed by SYSTEM as default, the package - source 'PSGallery' must be trusted for SYSTEM for some of the - tests. -#> -Configuration MSFT_PSModule_SetPackageSourceAsTrusted_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSRepository 'Integration_Test' - { - Name = 'PSGallery' - } - } -} - -<# - .SYNOPSIS - Installs a module with the default parameters. -#> -Configuration MSFT_PSModule_DefaultParameters_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.Module1_Name - } - } -} - -<# - .SYNOPSIS - Installed a module using AllowClobber. - - .NOTES - This test uses SqlServer module that actually needs AllowClobber. - On the build worker there are other modules (SQLPS) already installed, - those modules have the same cmdlets in them. -#> -Configuration MSFT_PSModule_UsingAllowClobber_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.Module2_Name - NoClobber = $false - } - } -} - -<# - .SYNOPSIS - Uninstalls a module ($Node.Module2_Name). -#> -Configuration MSFT_PSModule_UninstallModule2_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Ensure = 'Absent' - Name = $Node.Module2_Name - } - } -} - -<# - .SYNOPSIS - Installs a module with the specific version. -#> -Configuration MSFT_PSModule_RequiredVersion_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.Module2_Name - Version = $Node.Module2_RequiredVersion - NoClobber = $false - } - } -} - -<# - .SYNOPSIS - Installs a module with the specific version. -#> -Configuration MSFT_PSModule_RequiredVersion_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.Module2_Name - Version = $Node.Module2_RequiredVersion - NoClobber = $false - } - } -} - -<# - .SYNOPSIS - Installs a module within the specific version range. -#> -Configuration MSFT_PSModule_VersionRange_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.Module2_Name - Version = "[$($Node.Module2_MinimumVersion), $($Node.Module2_MaximumVersion)]" - NoClobber = $false - } - } -} diff --git a/DSC/Tests/Integration/MSFT_PSRepository.Integration.Tests.ps1 b/DSC/Tests/Integration/MSFT_PSRepository.Integration.Tests.ps1 deleted file mode 100644 index 52d7ecbfb..000000000 --- a/DSC/Tests/Integration/MSFT_PSRepository.Integration.Tests.ps1 +++ /dev/null @@ -1,206 +0,0 @@ -<# - .SYNOPSIS - Integration tests for DSC resource PSModule. - - .NOTES - The header and footer was removed that is usually part of the - DscResource.Tests integration test template. - The header was adding the project folder as a PSModulePath which - collide with the PowerShellGet test framework that copies the - module to the regular PowerShell Module folder. -#> - -$script:dscResourceFriendlyName = 'PSRepository' -$script:dcsResourceName = "MSFT_$($script:dscResourceFriendlyName)" - -#region Integration Tests -$configurationFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dcsResourceName).config.ps1" -. $configurationFile - -Describe "$($script:dcsResourceName)_Integration" { - $configurationName = "$($script:dcsResourceName)_AddRepository_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Name - $resourceCurrentState.SourceLocation | Should -Be $ConfigurationData.AllNodes.TestSourceLocation - $resourceCurrentState.PublishLocation | Should -Be $ConfigurationData.AllNodes.TestPublishLocation - $resourceCurrentState.ScriptSourceLocation | Should -Be $ConfigurationData.AllNodes.TestScriptSourceLocation - $resourceCurrentState.ScriptPublishLocation | Should -Be $ConfigurationData.AllNodes.TestScriptPublishLocation - $resourceCurrentState.PackageManagementProvider | Should -Be 'NuGet' - $resourceCurrentState.Trusted | Should -Be $true - $resourceCurrentState.Registered | Should -Be $true - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_InstallTestModule_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - } - - $configurationName = "$($script:dcsResourceName)_ChangeRepository_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Name - $resourceCurrentState.SourceLocation | Should -Be $ConfigurationData.AllNodes.SourceLocation - $resourceCurrentState.PublishLocation | Should -Be $ConfigurationData.AllNodes.PublishLocation - $resourceCurrentState.ScriptSourceLocation | Should -Be $ConfigurationData.AllNodes.ScriptSourceLocation - $resourceCurrentState.ScriptPublishLocation | Should -Be $ConfigurationData.AllNodes.ScriptPublishLocation - $resourceCurrentState.PackageManagementProvider | Should -Be $ConfigurationData.AllNodes.PackageManagementProvider - $resourceCurrentState.Trusted | Should -Be $false - $resourceCurrentState.Registered | Should -Be $true - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } - - $configurationName = "$($script:dcsResourceName)_RemoveRepository_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } - - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } - - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $resourceCurrentState.Ensure | Should -Be 'Absent' - $resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.Name - $resourceCurrentState.SourceLocation | Should -BeNullOrEmpty - $resourceCurrentState.PublishLocation | Should -BeNullOrEmpty - $resourceCurrentState.ScriptSourceLocation | Should -BeNullOrEmpty - $resourceCurrentState.ScriptPublishLocation | Should -BeNullOrEmpty - $resourceCurrentState.PackageManagementProvider | Should -BeNullOrEmpty - $resourceCurrentState.Trusted | Should -Be $false - $resourceCurrentState.Registered | Should -Be $false - } - - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be $true - } - } -} -#endregion diff --git a/DSC/Tests/Integration/MSFT_PSRepository.config.ps1 b/DSC/Tests/Integration/MSFT_PSRepository.config.ps1 deleted file mode 100644 index ca7302cd3..000000000 --- a/DSC/Tests/Integration/MSFT_PSRepository.config.ps1 +++ /dev/null @@ -1,108 +0,0 @@ -#region HEADER -# Integration Test Config Template Version: 1.2.0 -#endregion - -$configFile = [System.IO.Path]::ChangeExtension($MyInvocation.MyCommand.Path, 'json') -if (Test-Path -Path $configFile) -{ - <# - Allows reading the configuration data from a JSON file - for real testing scenarios outside of the CI. - #> - $ConfigurationData = Get-Content -Path $configFile | ConvertFrom-Json -} -else -{ - $ConfigurationData = @{ - AllNodes = @( - @{ - NodeName = 'localhost' - CertificateFile = $env:DscPublicCertificatePath - - Name = 'PSTestGallery' - - URL = 'https://www.poshtestgallery.com/api/v2' - - - - TestModuleName = 'ContosoServer' - } - ) - } -} - -<# - .SYNOPSIS - Adds a repository. -#> -Configuration MSFT_PSRepository_AddRepository_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSRepository 'Integration_Test' - { - Name = $Node.Name - URL = $Node.TestURL - Priority = $Node.TestPriority - Trusted = $false - } - } -} - -<# - .SYNOPSIS - Installs a module with default parameters from the new repository. -#> -Configuration MSFT_PSRepository_InstallTestModule_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSModule 'Integration_Test' - { - Name = $Node.TestModuleName - Repository = $Node.Name - } - } -} - -<# - .SYNOPSIS - Changes the properties of the repository. -#> -Configuration MSFT_PSRepository_ChangeRepository_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSRepository 'Integration_Test' - { - Name = $Node.Name - URL = $Node.URL - Priority = $Node.Priority - Trusted = $false - } - } -} - -<# - .SYNOPSIS - Removes the repository. -#> -Configuration MSFT_PSRepository_RemoveRepository_Config -{ - Import-DscResource -ModuleName 'PowerShellGet' - - node $AllNodes.NodeName - { - PSRepository 'Integration_Test' - { - Ensure = 'Absent' - Name = $Node.Name - } - } -} diff --git a/DSC/Tests/Unit/MSFT_PSModule.Tests.ps1 b/DSC/Tests/Unit/MSFT_PSModule.Tests.ps1 deleted file mode 100644 index a0f733f83..000000000 --- a/DSC/Tests/Unit/MSFT_PSModule.Tests.ps1 +++ /dev/null @@ -1,613 +0,0 @@ -#region HEADER -# This must be same name as the root folder, and module manifest. -$script:DSCModuleName = 'DSC' -$script:DSCResourceName = 'MSFT_PSModule' - -# Unit Test Template Version: 1.2.4 -$script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) -if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` - (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DscResource.Tests')) -} - -Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force - -$TestEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:DSCModuleName ` - -DSCResourceName $script:DSCResourceName ` - -ResourceType 'Mof' ` - -TestType Unit - -#endregion HEADER - -function Invoke-TestSetup { -} - -function Invoke-TestCleanup { - Restore-TestEnvironment -TestEnvironment $TestEnvironment -} - -# Begin Testing -try { - Invoke-TestSetup - - InModuleScope $script:DSCResourceName { - $mockModuleName = 'MockedModule' - $mockRepositoryName = 'PSGalleryTest' - $mockModuleBase = 'TestDrive:\MockPath' - - $mockModule_v1 = New-Object -TypeName Object | - Add-Member -Name 'Name' -MemberType NoteProperty -Value $mockModuleName -PassThru | - Add-Member -Name 'Description' -MemberType NoteProperty -Value 'Mocked description' -PassThru | - Add-Member -Name 'Guid' -MemberType NoteProperty -Value '4c189dbd-d858-4893-bac0-d682423c5fc7' -PassThru | - Add-Member -Name 'ModuleBase' -MemberType NoteProperty -Value $mockModuleBase -PassThru | - Add-Member -Name 'ModuleType' -MemberType NoteProperty -Value 'Script' -PassThru | - Add-Member -Name 'Author' -MemberType NoteProperty -Value 'Mocked Author' -PassThru | - Add-Member -Name 'Version' -MemberType NoteProperty -Value ([System.Version]'1.0.0.0') -PassThru -Force - - $mockModule_v2 = New-Object -TypeName Object | - Add-Member -Name 'Name' -MemberType NoteProperty -Value $mockModuleName -PassThru | - Add-Member -Name 'Description' -MemberType NoteProperty -Value 'Mocked description' -PassThru | - Add-Member -Name 'Guid' -MemberType NoteProperty -Value '4c189dbd-d858-4893-bac0-d682423c5fc7' -PassThru | - Add-Member -Name 'ModuleBase' -MemberType NoteProperty -Value $mockModuleBase -PassThru | - Add-Member -Name 'ModuleType' -MemberType NoteProperty -Value 'Script' -PassThru | - Add-Member -Name 'Author' -MemberType NoteProperty -Value 'Mocked Author' -PassThru | - Add-Member -Name 'Version' -MemberType NoteProperty -Value ([System.Version]'2.0.0.0') -PassThru -Force - - $mockGalleryModule = New-Object -TypeName PSCustomObject | - Add-Member -Name 'Name' -MemberType NoteProperty -Value $mockModuleName -PassThru | - Add-Member -Name 'Repository' -MemberType NoteProperty -Value 'PSGalleryTest' -PassThru | - Add-Member -Name 'Version' -MemberType NoteProperty -Value ([System.Version]'3.0.0.0') -PassThru -Force - - $mockGetRightModule_SingleModule = { - return @($mockModule_v1) - } - - $mockGetRightModule_MultipleModules = { - return @( - $mockModule_v1 - $mockModule_v2 - ) - } - - $mockGetModule_SingleModule = { - return @($mockModule_v1) - } - - $mockGetModule_SingleModule2 = { - return @($mockGalleryModule) - } - - $mockGetModule_MultipleModules = { - return @( - $mockModule_v1 - $mockModule_v2 - ) - } - - $mockGetModuleRepositoryName = { - return $mockRepositoryName - } - - $mockGetInstallationPolicy_Trusted = { - return $true - } - - $mockGetInstallationPolicy_NotTrusted = { - return $false - } - - $mockFindModule = { - return $mockGalleryModule - } - - Describe 'MSFT_PSModule\Get-TargetResource' -Tag 'Get','BVT' { - Context 'When the system is in the desired state' { - Context 'When the configuration is present' { - Context 'When the module is trusted' { - BeforeEach { - Mock -CommandName Get-RightModule -MockWith $mockGetRightModule_SingleModule - Mock -CommandName Get-ModuleRepositoryName -MockWith $mockGetModuleRepositoryName - } - - It 'Should return the same values as passed as parameters' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - $getTargetResourceResult.Name | Should -Be $mockModuleName - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 1 -Scope It - } - - It 'Should return the correct values for the other properties' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - - $getTargetResourceResult.Ensure | Should -Be 'Present' - $getTargetResourceResult.Repository | Should -Be $mockRepositoryName - $getTargetResourceResult.Description | Should -Be $mockModule_v1.Description - $getTargetResourceResult.Guid | Should -Be $mockModule_v1.Guid - $getTargetResourceResult.ModuleBase | Should -Be $mockModule_v1.ModuleBase - $getTargetResourceResult.ModuleType | Should -Be $mockModule_v1.ModuleType - $getTargetResourceResult.Author | Should -Be $mockModule_v1.Author - $getTargetResourceResult.InstalledVersion | Should -Be $mockModule_v1.Version - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 1 -Scope It - } - } - - Context 'When the module is not trusted' { - BeforeEach { - Mock -CommandName Get-RightModule -MockWith $mockGetRightModule_SingleModule - Mock -CommandName Get-ModuleRepositoryName -MockWith $mockGetModuleRepositoryName - } - - It 'Should return the same values as passed as parameters' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - $getTargetResourceResult.Name | Should -Be $mockModuleName - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 1 -Scope It - } - - It 'Should return the correct values for the other properties' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - - $getTargetResourceResult.Ensure | Should -Be 'Present' - $getTargetResourceResult.Repository | Should -Be $mockRepositoryName - $getTargetResourceResult.Description | Should -Be $mockModule_v1.Description - $getTargetResourceResult.Guid | Should -Be $mockModule_v1.Guid - $getTargetResourceResult.ModuleBase | Should -Be $mockModule_v1.ModuleBase - $getTargetResourceResult.ModuleType | Should -Be $mockModule_v1.ModuleType - $getTargetResourceResult.Author | Should -Be $mockModule_v1.Author - $getTargetResourceResult.InstalledVersion | Should -Be $mockModule_v1.Version - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 1 -Scope It - } - } - - Context 'When there are multiple version of the same module' { - BeforeEach { - Mock -CommandName Get-RightModule -MockWith $mockGetRightModule_MultipleModules - Mock -CommandName Get-ModuleRepositoryName -MockWith $mockGetModuleRepositoryName - } - - It 'Should return the same values as passed as parameters' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - $getTargetResourceResult.Name | Should -Be $mockModuleName - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 1 -Scope It - } - - It 'Should return the correct module version' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - - $getTargetResourceResult.InstalledVersion | Should -Be $mockModule_v2.Version - } - - It 'Should return the correct values for the other properties' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - - $getTargetResourceResult.Ensure | Should -Be 'Present' - $getTargetResourceResult.Repository | Should -Be $mockRepositoryName - $getTargetResourceResult.Description | Should -Be $mockModule_v2.Description - $getTargetResourceResult.Guid | Should -Be $mockModule_v2.Guid - $getTargetResourceResult.ModuleBase | Should -Be $mockModule_v2.ModuleBase - $getTargetResourceResult.ModuleType | Should -Be $mockModule_v2.ModuleType - $getTargetResourceResult.Author | Should -Be $mockModule_v2.Author - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 1 -Scope It - } - } - } - - Context 'When the configuration is absent' { - BeforeEach { - Mock -CommandName Get-RightModule - Mock -CommandName Get-ModuleRepositoryName - } - - It 'Should return the same values as passed as parameters' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - $getTargetResourceResult.Name | Should -Be $mockModuleName - #$getTargetResourceResult.Repository | Should -Be $mockRepositoryName - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 0 -Scope It - } - - It 'Should return the correct values for the other properties' { - $getTargetResourceResult = Get-TargetResource -Name $mockModuleName - - $getTargetResourceResult.Ensure | Should -Be 'Absent' - $getTargetResourceResult.Description | Should -BeNullOrEmpty - $getTargetResourceResult.Guid | Should -BeNullOrEmpty - $getTargetResourceResult.ModuleBase | Should -BeNullOrEmpty - $getTargetResourceResult.ModuleType | Should -BeNullOrEmpty - $getTargetResourceResult.Author | Should -BeNullOrEmpty - #$getTargetResourceResult.InstalledVersion | Should -BeNullOrEmpty - #$getTargetResourceResult.Trusted | Should -BeNullOrEmpty - $getTargetResourceResult.Version | Should -BeNullOrEmpty - $getTargetResourceResult.NoClobber | Should -Be $false - $getTargetResourceResult.SkipPublisherCheck | Should -Be $false - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-ModuleRepositoryName -Exactly -Times 0 -Scope It - } - } - } - } - - Describe 'MSFT_PSModule\Set-TargetResource' -Tag 'Set','BVT' { - Context 'When the system is not in the desired state' { - Context 'When the configuration should be present' { - BeforeAll { - Mock -CommandName Find-PSResource -MockWith $mockFindModule - Mock -CommandName Install-PSResource -MockWith $mockFindModule - } - - Context 'When the Repository is ''PSGallery''' { - BeforeAll { - Mock -CommandName Get-InstallationPolicy -MockWith $mockGetInstallationPolicy_Trusted - Mock -CommandName Test-ParameterValue - } - - It 'Should call the Install-PSResource with the correct parameters' { - { Set-TargetResource -Name $mockModuleName -Repository 'PSGalleryTest' -Version '3.0.0.0' -verbose} | Should -Not -Throw - - Assert-MockCalled -CommandName Find-PSResource -ParameterFilter { - $Name -eq $mockModuleName -and $Repository -eq 'PSGalleryTest' - } -Exactly -Times 1 -Scope It - - #Assert-MockCalled -CommandName Install-PSResource -ParameterFilter { - # $InputObject.Name -eq $mockModuleName -and $InputObject.Repository -eq 'PSGalleryTest' - #} -Exactly -Times 1 -Scope It - } - } - - - Context 'When the module name cannot be found' { - BeforeAll { - Mock -CommandName Find-PSResource -MockWith { - throw 'Mocked error' - } - } - - It 'Should throw the correct error' { - { Set-TargetResource -Name $mockModuleName } | - Should -Throw ($localizedData.ModuleNotFoundInRepository -f $mockModuleName) - } - } - } - - Context 'When the configuration should be absent' { - Context 'When uninstalling a module that has a single version' { - BeforeAll { - Mock -CommandName Get-RightModule -MockWith $mockGetRightModule_SingleModule - Mock -CommandName Remove-Item - } - - It 'Should call the Remove-Item with the correct parameters' { - { Set-TargetResource -Name $mockModuleName -Ensure 'Absent' } | Should -Not -Throw - - Assert-MockCalled -CommandName Get-RightModule -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Remove-Item -ParameterFilter { - $path -eq $mockModuleBase - } -Exactly -Times 1 -Scope It - } - } - - Context 'When the module name cannot be found' { - BeforeAll { - Mock -CommandName Get-RightModule - } - - It 'Should throw the correct error' { - { Set-TargetResource -Name $mockModuleName -Ensure 'Absent' } | - Should -Throw ($localizedData.ModuleWithRightPropertyNotFound -f $mockModuleName) - } - } - - Context 'When a module cannot be removed' { - BeforeAll { - Mock -CommandName Get-RightModule -MockWith $mockGetRightModule_SingleModule - Mock -CommandName Remove-Item -MockWith { - throw 'Mock fail to remove module error' - } - } - - It 'Should throw the correct error' { - { Set-TargetResource -Name $mockModuleName -Ensure 'Absent' } | - Should -Throw ($localizedData.FailToUninstall -f $mockModuleName) - } - } - } - } - } - - Describe 'MSFT_PSModule\Test-TargetResource' -Tag 'Test','BVT' { - Context 'When the system is in the desired state' { - Context 'When the configuration is present' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockModuleName - Repository = $mockRepositoryName - Description = $mockModule_v1.Description - Guid = $mockModule_v1.Guid - ModuleBase = $mockModule_v1.ModuleBase - ModuleType = $mockModule_v1.ModuleType - Author = $mockModule_v1.Author - InstalledVersion = $mockModule_v1.Version - #InstallationPolicy = 'Untrusted' - } - } - } - - It 'Should return the state as $true' { - $testTargetResourceResult = Test-TargetResource -Name $mockModuleName - $testTargetResourceResult | Should -Be $true - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - - Context 'When the configuration is absent' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Absent' - Name = $mockModuleName - Repository = $null - Description = $null - Guid = $null - ModuleBase = $null - ModuleType = $null - Author = $null - InstalledVersion = $null - #InstallationPolicy = $null - } - } - } - - It 'Should return the state as $true' { - $testTargetResourceResult = Test-TargetResource -Ensure 'Absent' -Name $mockModuleName - $testTargetResourceResult | Should -Be $true - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - } - - Context 'When the system is not in the desired state' { - Context 'When the configuration should be present' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Absent' - Name = $mockModuleName - Repository = $mockRepositoryName - Description = $mockModule_v1.Description - Guid = $mockModule_v1.Guid - ModuleBase = $mockModule_v1.ModuleBase - ModuleType = $mockModule_v1.ModuleType - Author = $mockModule_v1.Author - InstalledVersion = $mockModule_v1.Version - #InstallationPolicy = 'Untrusted' - } - } - } - - It 'Should return the state as $false' { - $testTargetResourceResult = Test-TargetResource -Name $mockModuleName - $testTargetResourceResult | Should -Be $false - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - - Context 'When the configuration should be absent' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockModuleName - Repository = $null - Description = $null - Guid = $null - ModuleBase = $null - ModuleType = $null - Author = $null - InstalledVersion = $null - # = $null - } - } - } - - It 'Should return the state as $false' { - $testTargetResourceResult = Test-TargetResource -Ensure 'Absent' -Name $mockModuleName - $testTargetResourceResult | Should -Be $false - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - } - } - - Describe 'MSFT_PSModule\Get-ModuleRepositoryName' -Tag 'Helper' { - BeforeAll { - # Mock the file PSGetModuleInfo.xml in the module base folder. - New-Item -Path $mockModuleBase -ItemType File -Name 'PSGetModuleInfo.xml' -Force - - $mockModule = New-Object -TypeName Object | - Add-Member -Name 'ModuleBase' -MemberType NoteProperty -Value $mockModuleBase -PassThru -Force - - Mock -CommandName Import-Clixml -MockWith { - return New-Object -TypeName Object | - Add-Member -Name 'Repository' -MemberType NoteProperty -Value $mockRepositoryName -PassThru -Force - } - } - - It 'Should return the correct repository name of a module' { - Get-ModuleRepositoryName -Module $mockModule | Should -Be $mockRepositoryName - - Assert-MockCalled -CommandName 'Import-Clixml' -Exactly -Times 1 -Scope It - } - } - - Describe 'MSFT_PSModule\Get-RightModule' -Tag 'Helper' { - BeforeEach { - Mock -CommandName Get-ModuleRepositoryName -MockWith $mockGetModuleRepositoryName - } - - Context 'When the module does not exist' { - BeforeEach { - Mock -CommandName Get-Module - } - - It 'Should return $null' { - Get-RightModule -Name 'UnknownModule' | Should -BeNullOrEmpty - - Assert-MockCalled -CommandName 'Get-Module' -Exactly -Times 1 -Scope It - } - } - - Context 'When one version of the module exist' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - It 'Should return the correct module information' { - $getRightModuleResult = Get-RightModule -Name $mockModuleName - $getRightModuleResult.Name | Should -Be $mockModuleName - - Assert-MockCalled -CommandName 'Get-ModuleRepositoryName' -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName 'Get-Module' -ParameterFilter { - $Name -eq $mockModuleName - } -Exactly -Times 1 -Scope It - } - } - - Context 'When parameter Repository is specified, and one version of the module exist' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - It 'Should return the correct module information' { - $getRightModuleResult = Get-RightModule -Name $mockModuleName -Repository $mockRepositoryName -Verbose - $getRightModuleResult.Name | Should -Be $mockModuleName - - Assert-MockCalled -CommandName 'Get-ModuleRepositoryName' -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName 'Get-Module' -ParameterFilter { - $Name -eq $mockModuleName - } -Exactly -Times 1 -Scope It - } - } - - Context 'When parameter Repository is specified, and one version of the module exist, but from a different repository' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - It 'Should return $null' { - $getRightModuleResult = Get-RightModule -Name $mockModuleName -Repository 'OtherRepository' -Verbose - $getRightModuleResult.Name | Should -BeNullOrEmpty - - Assert-MockCalled -CommandName 'Get-ModuleRepositoryName' -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName 'Get-Module' -ParameterFilter { - $Name -eq $mockModuleName - } -Exactly -Times 1 -Scope It - } - } - - Context 'When the module is required to have a specific version, and the specific version is installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule2 - } - - # It 'Should return the correct module information' { - # $getRightModuleResult = Get-RightModule -Name $mockModuleName -Version '3.0.0.0' -Repository 'PSGalleryTest' -Verbose - # $getRightModuleResult.Name | Should -Be $mockModuleName - - # Assert-MockCalled -CommandName 'Get-ModuleRepositoryName' -Exactly -Times 0 -Scope It - # Assert-MockCalled -CommandName 'Get-Module' -ParameterFilter { - # $Name -eq $mockModuleName - # } -Exactly -Times 1 -Scope It - # } - } - - Context 'When the module is required to have a specific version, and the specific version is not installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - It 'Should return $null' { - $getRightModuleResult = Get-RightModule -Name $mockModuleName -Version '2.0.0.0' -Verbose - $getRightModuleResult.Name | Should -BeNullOrEmpty - - Assert-MockCalled -CommandName 'Get-ModuleRepositoryName' -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName 'Get-Module' -ParameterFilter { - $Name -eq $mockModuleName - } -Exactly -Times 1 -Scope It - } - } - - Context 'When the module is required to have a maximum version, and a suitable module is installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - } - - Context 'When the module is required to have a minimum version, and a suitable module is installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - } - - Context 'When the module is required to have a maximum version, and the suitable module is not installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - } - - Context 'When the module is required to have a minimum version, and the suitable module is not installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - } - - Context 'When the module is required to have a minimum and maximum version' { - Context 'When a suitable module is installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_SingleModule - } - - } - - Context 'When there two suitable modules installed' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_MultipleModules - } - - } - - - Context 'When there two installed modules, but only one module is suitable' { - BeforeEach { - Mock -CommandName Get-Module -MockWith $mockGetModule_MultipleModules - } - } - } - } - } -} -finally { - Invoke-TestCleanup -} diff --git a/DSC/Tests/Unit/MSFT_PSRepository.Tests.ps1 b/DSC/Tests/Unit/MSFT_PSRepository.Tests.ps1 deleted file mode 100644 index 47f68b33d..000000000 --- a/DSC/Tests/Unit/MSFT_PSRepository.Tests.ps1 +++ /dev/null @@ -1,397 +0,0 @@ -#region HEADER -# This must be same name as the root folder, and module manifest. -$script:DSCModuleName = 'DSC' -$script:DSCResourceName = 'MSFT_PSRepository' - -# Unit Test Template Version: 1.2.4 -$script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) -if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` - (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DscResource.Tests')) -} - -Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force - -$TestEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:DSCModuleName ` - -DSCResourceName $script:DSCResourceName ` - -ResourceType 'Mof' ` - -TestType Unit - -#endregion HEADER - -function Invoke-TestSetup { -} - -function Invoke-TestCleanup { - Restore-TestEnvironment -TestEnvironment $TestEnvironment -} - -# Begin Testing -try { - Invoke-TestSetup - - InModuleScope $script:DSCResourceName { - $mockRepositoryName = 'PSTestGallery' - $mockSourceLocation = 'https://www.poshtestgallery.com/api/v2' - $mockPriority = 1 - $mockInstallationPolicy_Trusted = $true - $mockInstallationPolicy_NotTrusted = $false - - #$mockInstallationPolicy_Trusted = 'Trusted' - #$mockInstallationPolicy_NotTrusted = 'Untrusted' - - - $mockRepository = New-Object -TypeName Object | - Add-Member -Name 'Name' -MemberType NoteProperty -Value $mockRepositoryName -PassThru | - Add-Member -Name 'URL' -MemberType NoteProperty -Value $mockSourceLocation -PassThru | - Add-Member -Name 'InstallationPolicy' -MemberType NoteProperty -Value $mockInstallationPolicy_Trusted -PassThru | - Add-Member -Name 'Priority' -MemberType NoteProperty -Value $mockPriority -PassThru | - #Add-Member -Name 'Trusted' -MemberType NoteProperty -Value $mockInstallationPolicy_Trusted -PassThru | - Add-Member -Name 'Trusted' -MemberType NoteProperty -Value $true -PassThru | - Add-Member -Name 'Registered' -MemberType NoteProperty -Value $true -PassThru -Force - - $mockGetPSRepository = { - return @($mockRepository) - } - - Describe 'MSFT_PSRepository\Get-TargetResource' -Tag 'Get' { - Context 'When the system is in the desired state' { - Context 'When the configuration is present' { - BeforeAll { - Mock -CommandName Get-PSResourceRepository -MockWith $mockGetPSRepository - } - - #It 'Should return the same values as passed as parameters' { - # $getTargetResourceResult = Get-TargetResource -Name $mockRepositoryName - # $getTargetResourceResult.Name | Should -Be $mockRepositoryName - - # Assert-MockCalled -CommandName Get-PSResourceRepository -Exactly -Times 1 -Scope It - # } - - It 'Should return the correct values for the other properties' { - $getTargetResourceResult = Get-TargetResource -Name $mockRepositoryName -Verbose - - $getTargetResourceResult.Ensure | Should -Be 'Present' - #$getTargetResourceResult.URL | Should -Be $mockRepository.URL - # $getTargetResourceResult.Priority | Should -Be $mockRepository.Priority - #$getTargetResourceResult.InstallationPolicy | Should -Be $mockRepository.InstallationPolicy - #$getTargetResourceResult.Trusted | Should -Be $mockRepository.Trusted - #$getTargetResourceResult.Trusted | Should -Be $true - $getTargetResourceResult.Registered | Should -Be $true - - Assert-MockCalled -CommandName Get-PSResourceRepository -Exactly -Times 1 -Scope It - } - } - - Context 'When the configuration is absent' { - BeforeAll { - Mock -CommandName Get-PSResourceRepository - } - - It 'Should return the same values as passed as parameters' { - $getTargetResourceResult = Get-TargetResource -Name $mockRepositoryName - $getTargetResourceResult.Name | Should -Be $mockRepositoryName - - Assert-MockCalled -CommandName Get-PSResourceRepository -Exactly -Times 1 -Scope It - } - - It 'Should return the correct values for the other properties' { - $getTargetResourceResult = Get-TargetResource -Name $mockRepositoryName - - $getTargetResourceResult.Ensure | Should -Be 'Absent' - $getTargetResourceResult.URL | Should -BeNullOrEmpty - $getTargetResourceResult.Priority | Should -BeNullOrEmpty - #$getTargetResourceResult.InstallationPolicy | Should -BeNullOrEmpty - #$getTargetResourceResult.Trusted | Should -Be $false - $getTargetResourceResult.Registered | Should -Be $false - - Assert-MockCalled -CommandName Get-PSResourceRepository -Exactly -Times 1 -Scope It - } - } - } - } - - Describe 'MSFT_PSRepository\Set-TargetResource' -Tag 'Set' { - Context 'When the system is not in the desired state' { - BeforeAll { - Mock -CommandName Register-PSResourceRepository - Mock -CommandName Unregister-PSResourceRepository - Mock -CommandName Set-PSResourceRepository - } - - Context 'When the configuration should be present' { - Context 'When the repository does not exist' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Absent' - Name = $mockRepositoryName - URL = $null - Priority = $null - #InstallationPolicy = $null - #Trusted = $false - Registered = $false - } - } - } - - It 'Should return call the correct mocks' { - $setTargetResourceParameters = @{ - Name = $mockRepository.Name - URL = $mockRepository.URL - # Priority = $mockRepository.Priority - #Trusted = $mockRepository.Trusted - #InstallationPolicy = $mockRepository.InstallationPolicy - } - - { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw - - Assert-MockCalled -CommandName Register-PSResourceRepository -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Unregister-PSResourceRepository -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Set-PSresourceRepository -Exactly -Times 0 -Scope It - } - } - - Context 'When the repository do exist but with wrong properties' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockRepository.Name - URL = 'https://www.powershellgallery.com/api/v2' - Priority = '0' - #InstallationPolicy = $mockRepository.InstallationPolicy - #Trusted = $mockRepository.Trusted - Registered = $mockRepository.Registered - } - } - } - - It 'Should return call the correct mocks' { - $setTargetResourceParameters = @{ - Name = $mockRepository.Name - URL = $mockRepository.URL - #Priority = $mockRepository.Priority - #Trusted = $mockRepository.Trusted - #InstallationPolicy = $mockRepository.InstallationPolicy - } - - { MSFT_PSRepository\Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw - - Assert-MockCalled -CommandName Register-PSResourceRepository -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Unregister-PSresourceRepository -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Set-PSResourceRepository -Exactly -Times 1 -Scope It - } - } - } - - Context 'When the configuration should be absent' { - Context 'When the repository do exist' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockRepository.Name - URL = $mockRepository.URL - Priority = $mockRepository.Priority - #InstallationPolicy = $mockRepository.InstallationPolicy - #Trusted = $mockRepository.Trusted - Registered = $mockRepository.Registered - } - } - } - - It 'Should return call the correct mocks' { - $setTargetResourceParameters = @{ - Ensure = 'Absent' - Name = $mockRepositoryName - } - - { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw - - Assert-MockCalled -CommandName Register-PSResourceRepository -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Unregister-PSResourceRepository -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Set-PSResourceRepository -Exactly -Times 0 -Scope It - } - } - } - } - } - - Describe 'MSFT_PSRepository\Test-TargetResource' -Tag 'Test' { - Context 'When the system is in the desired state' { - Context 'When the configuration is present' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockRepository.Name - URL = $mockRepository.URL - Priority = $mockRepository.Priority - #InstallationPolicy = $mockRepository.InstallationPolicy - #Trusted = $mockRepository.Trusted - Registered = $mockRepository.Registered - } - } - } - - It 'Should return the state as $true' { - $testTargetResourceResult = Test-TargetResource -Name $mockRepositoryName - $testTargetResourceResult | Should -Be $true - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - - Context 'When the configuration is absent' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Absent' - Name = $mockRepositoryName - URL = $null - Priority = $null - #InstallationPolicy = $null - #Trusted = $false - Registered = $false - } - } - } - - It 'Should return the state as $true' { - $testTargetResourceResult = Test-TargetResource -Ensure 'Absent' -Name $mockRepositoryName - $testTargetResourceResult | Should -Be $true - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - } - - Context 'When the system is not in the desired state' { - Context 'When the configuration should be present' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Absent' - Name = $mockRepositoryName - URL = $null - Priority = $null - #InstallationPolicy = $null - #Trusted = $false - Registered = $false - } - } - } - - It 'Should return the state as $false' { - $testTargetResourceParameters = @{ - Name = $mockRepository.Name - URL = $mockRepository.URL - Priority = $mockRepository.Priority - #Trusted = $mockRepository.Trusted - #InstallationPolicy = $mockRepository.InstallationPolicy - } - - $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - $testTargetResourceResult | Should -Be $false - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - - Context 'When a property is not in desired state' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockRepository.Name - URL = $mockRepository.URL - Priority = $mockRepository.Priority - #InstallationPolicy = $mockRepository.InstallationPolicy - #Trusted = $mockRepository.Trusted - Registered = $mockRepository.Registered - } - } - } - - $defaultTestCase = @{ - URL = $mockRepository.URL - Priority = $mockRepository.Priority - #Trusted = $mockRepository.Trusted - #InstallationPolicy = $mockRepository.InstallationPolicy - } - - $testCaseSourceLocationIsMissing = $defaultTestCase.Clone() - $testCaseSourceLocationIsMissing['TestName'] = 'SourceLocation is missing' - $testCaseSourceLocationIsMissing['URL'] = 'https://www.powershellgallery.com/api/v2' - - - $testCasePriorityIsMissing = $defaultTestCase.Clone() - $testCasePriorityIsMissing['TestName'] = 'Priority is missing' - $testCasePriorityIsMissing['Priority'] = '50' - - - #$testCaseInstallationPolicyIsMissing = $defaultTestCase.Clone() - #$testCaseInstallationPolicyIsMissing['TestName'] = 'InstallationPolicy is missing' - #$testCaseInstallationPolicyIsMissing['Trusted'] = $mockInstallationPolicy_NotTrusted - - $testCases = @( - $testCaseSourceLocationIsMissing - $testCasePriorityIsMissing - #$testCaseInstallationPolicyIsMissing - ) - - It 'Should return the state as $false when the correct ' -TestCases $testCases { - param - ( - $URL, - $Priority - #$Trusted, - #$InstallationPolicy - ) - - $testTargetResourceParameters = @{ - Name = $mockRepositoryName - URL = $URL - Priority = $Priority - #Trusted = $Trusted - #InstallationPolicy = $InstallationPolicy - } - - $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - $testTargetResourceResult | Should -Be $false - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - - Context 'When the configuration should be absent' { - BeforeEach { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - Name = $mockRepositoryName - URL = $mockRepository.URL - Priority = $mockRepository.Priority - #Trusted = $mockRepository.Trusted - #InstallationPolicy = $mockRepository.InstallationPolicy - Registered = $mockRepository.Registered - } - } - } - - It 'Should return the state as $false' { - $testTargetResourceResult = Test-TargetResource -Ensure 'Absent' -Name $mockRepositoryName - $testTargetResourceResult | Should -Be $false - - Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - } - } - } -} -finally { - Invoke-TestCleanup -} diff --git a/DSC/Tests/Unit/PowerShellGet.LocalizationHelper.Tests.ps1 b/DSC/Tests/Unit/PowerShellGet.LocalizationHelper.Tests.ps1 deleted file mode 100644 index 6b9e6eda9..000000000 --- a/DSC/Tests/Unit/PowerShellGet.LocalizationHelper.Tests.ps1 +++ /dev/null @@ -1,206 +0,0 @@ -<# - .SYNOPSIS - Automated unit test for helper functions in module PowerShellGet.ResourceHelper. -#> - - -$script:helperModuleName = 'PowerShellGet.LocalizationHelper' - -Describe "$script:helperModuleName Unit Tests" { - BeforeAll { - $resourceModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent - $dscResourcesFolderFilePath = Join-Path -Path (Join-Path -Path $resourceModuleRoot -ChildPath 'Modules') ` - -ChildPath $script:helperModuleName - - Import-Module -Name (Join-Path -Path $dscResourcesFolderFilePath ` - -ChildPath "$script:helperModuleName.psm1") -Force - } - - InModuleScope $script:helperModuleName { - Describe 'Get-LocalizedData' { - $mockTestPath = { - return $mockTestPathReturnValue - } - - $mockImportLocalizedData = { - $BaseDirectory | Should -Be $mockExpectedLanguagePath - } - - BeforeEach { - Mock -CommandName Test-Path -MockWith $mockTestPath -Verifiable - Mock -CommandName Import-LocalizedData -MockWith $mockImportLocalizedData -Verifiable - } - - Context 'When loading localized data for Swedish' { - $mockExpectedLanguagePath = 'sv-SE' - $mockTestPathReturnValue = $true - - It 'Should call Import-LocalizedData with sv-SE language' { - Mock -CommandName Join-Path -MockWith { - return 'sv-SE' - } -Verifiable - - { Get-LocalizedData -ResourceName 'DummyResource' } | Should -Not -Throw - - Assert-MockCalled -CommandName Join-Path -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It - } - - $mockExpectedLanguagePath = 'en-US' - $mockTestPathReturnValue = $false - - It 'Should call Import-LocalizedData and fallback to en-US if sv-SE language does not exist' { - Mock -CommandName Join-Path -MockWith { - return $ChildPath - } -Verifiable - - { Get-LocalizedData -ResourceName 'DummyResource' } | Should -Not -Throw - - Assert-MockCalled -CommandName Join-Path -Exactly -Times 3 -Scope It - Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It - } - - Context 'When $ScriptRoot is set to a path' { - $mockExpectedLanguagePath = 'sv-SE' - $mockTestPathReturnValue = $true - - It 'Should call Import-LocalizedData with sv-SE language' { - Mock -CommandName Join-Path -MockWith { - return 'sv-SE' - } -Verifiable - - { Get-LocalizedData -ResourceName 'DummyResource' -ScriptRoot '.' } | Should -Not -Throw - - Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It - } - - $mockExpectedLanguagePath = 'en-US' - $mockTestPathReturnValue = $false - - It 'Should call Import-LocalizedData and fallback to en-US if sv-SE language does not exist' { - Mock -CommandName Join-Path -MockWith { - return $ChildPath - } -Verifiable - - { Get-LocalizedData -ResourceName 'DummyResource' -ScriptRoot '.' } | Should -Not -Throw - - Assert-MockCalled -CommandName Join-Path -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It - } - } - } - - Context 'When loading localized data for English' { - Mock -CommandName Join-Path -MockWith { - return 'en-US' - } -Verifiable - - $mockExpectedLanguagePath = 'en-US' - $mockTestPathReturnValue = $true - - It 'Should call Import-LocalizedData with en-US language' { - { Get-LocalizedData -ResourceName 'DummyResource' } | Should -Not -Throw - } - } - - Assert-VerifiableMock - } - - Describe 'New-InvalidResultException' { - Context 'When calling with Message parameter only' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - - { New-InvalidResultException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage - } - } - - Context 'When calling with both the Message and ErrorRecord parameter' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - $mockExceptionErrorMessage = 'Mocked exception error message' - - $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage - $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null - - $exception = { New-InvalidResultException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord -ErrorAction SilentlyContinue} - $exception | Should -Throw -PassThru $_ | Should -Match ('System.Exception: {0}' -f $mockErrorMessage) - $exception | Should -Throw -PassThru $_ | Should -Match ('System.Exception: {0}' -f $mockExceptionErrorMessage) - } - } - - Assert-VerifiableMock - } - - Describe 'New-ObjectNotFoundException' { - Context 'When calling with Message parameter only' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - - { New-ObjectNotFoundException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage - } - } - - Context 'When calling with both the Message and ErrorRecord parameter' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - $mockExceptionErrorMessage = 'Mocked exception error message' - - $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage - $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null - - $exception = { New-ObjectNotFoundException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } - $exception | Should -Throw -PassThru $_ | Should -Match ('System.Exception: {0}' -f $mockErrorMessage) - $exception | Should -Throw -PassThru $_ | Should -Match ('System.Exception: {0}' -f $mockExceptionErrorMessage) - } - } - - Assert-VerifiableMock - } - - Describe 'New-InvalidOperationException' { - Context 'When calling with Message parameter only' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - - { New-InvalidOperationException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage - } - } - - Context 'When calling with both the Message and ErrorRecord parameter' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - $mockExceptionErrorMessage = 'Mocked exception error message' - - $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage - $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null - - $exception = { New-InvalidOperationException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } - $exception | Should -Throw -PassThru $_ | Should -Match ('System.InvalidOperationException: {0}' -f $mockErrorMessage) - $exception | Should -Throw -PassThru $_ | Should -Match ('System.Exception: {0}' -f $mockExceptionErrorMessage) - } - } - - Assert-VerifiableMock - } - - Describe 'New-InvalidArgumentException' { - Context 'When calling with both the Message and ArgumentName parameter' { - It 'Should throw the correct error' { - $mockErrorMessage = 'Mocked error' - $mockArgumentName = 'MockArgument' - - $exception = { New-InvalidArgumentException -Message $mockErrorMessage -ArgumentName $mockArgumentName } - $exception | Should -Throw -PassThru $_ | Should -Match ("Parameter '{0}'" -f $mockArgumentName) - } - } - - Assert-VerifiableMock - } - } -} diff --git a/DSC/Tests/Unit/PowerShellGet.ResourceHelper.Tests.ps1 b/DSC/Tests/Unit/PowerShellGet.ResourceHelper.Tests.ps1 deleted file mode 100644 index ead1d4da8..000000000 --- a/DSC/Tests/Unit/PowerShellGet.ResourceHelper.Tests.ps1 +++ /dev/null @@ -1,504 +0,0 @@ -<# - .SYNOPSIS - Automated unit test for helper functions in module PowerShellGet.ResourceHelper. -#> - - -$script:helperModuleName = 'PowerShellGet.ResourceHelper' - -$resourceModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent -$dscResourcesFolderFilePath = Join-Path -Path (Join-Path -Path $resourceModuleRoot -ChildPath 'Modules') ` - -ChildPath $script:helperModuleName - -Import-Module -Name (Join-Path -Path $dscResourcesFolderFilePath ` - -ChildPath "$script:helperModuleName.psm1") -Force - -InModuleScope $script:helperModuleName { - Describe 'New-SplatParameterHashTable' { - Context 'When specific parameters should be returned' { - It 'Should return a hashtable with the correct values' { - $mockPSBoundParameters = @{ - Property1 = '1' - Property2 = '2' - Property3 = '3' - Property4 = '4' - } - - $extractArgumentsResult = New-SplatParameterHashTable ` - -FunctionBoundParameters $mockPSBoundParameters ` - -ArgumentNames @('Property2', 'Property3') - - $extractArgumentsResult | Should -BeOfType [System.Collections.Hashtable] - $extractArgumentsResult.Count | Should -Be 2 - $extractArgumentsResult.ContainsKey('Property2') | Should -BeTrue - $extractArgumentsResult.ContainsKey('Property3') | Should -BeTrue - $extractArgumentsResult.Property2 | Should -Be '2' - $extractArgumentsResult.Property3 | Should -Be '3' - } - } - - Context 'When the specific parameters to be returned does not exist' { - It 'Should return an empty hashtable' { - $mockPSBoundParameters = @{ - Property1 = '1' - } - - $extractArgumentsResult = New-SplatParameterHashTable ` - -FunctionBoundParameters $mockPSBoundParameters ` - -ArgumentNames @('Property2', 'Property3') - - $extractArgumentsResult | Should -BeOfType [System.Collections.Hashtable] - $extractArgumentsResult.Count | Should -Be 0 - } - } - - Context 'When and empty hashtable is passed in the parameter FunctionBoundParameters' { - It 'Should return an empty hashtable' { - $mockPSBoundParameters = @{ - } - - $extractArgumentsResult = New-SplatParameterHashTable ` - -FunctionBoundParameters $mockPSBoundParameters ` - -ArgumentNames @('Property2', 'Property3') - - $extractArgumentsResult | Should -BeOfType [System.Collections.Hashtable] - $extractArgumentsResult.Count | Should -Be 0 - } - } - } - - Describe 'Test-ParameterValue' { - BeforeAll { - $mockProviderName = 'PowerShellGet' - } - - Context 'When passing a correct uri as ''Value'' and type is ''SourceUri''' { - It 'Should not throw an error' { - { - Test-ParameterValue ` - -Value 'https://mocked.uri' ` - -Type 'SourceUri' ` - -ProviderName $mockProviderName - } | Should -Not -Throw - } - } - - Context 'When passing an invalid uri as ''Value'' and type is ''SourceUri''' { - It 'Should throw the correct error' { - $mockParameterName = 'mocked.uri' - - { - Test-ParameterValue ` - -Value $mockParameterName ` - -Type 'SourceUri' ` - -ProviderName $mockProviderName - } | Should -Throw ($LocalizedData.InValidUri -f $mockParameterName) - } - } - - Context 'When passing a correct path as ''Value'' and type is ''DestinationPath''' { - It 'Should not throw an error' { - { - Test-ParameterValue ` - -Value 'TestDrive:\' ` - -Type 'DestinationPath' ` - -ProviderName $mockProviderName - } | Should -Not -Throw - } - } - - Context 'When passing an invalid path as ''Value'' and type is ''DestinationPath''' { - It 'Should throw the correct error' { - $mockParameterName = 'TestDrive:\NonExistentPath' - - { - Test-ParameterValue ` - -Value $mockParameterName ` - -Type 'DestinationPath' ` - -ProviderName $mockProviderName - } | Should -Throw ($LocalizedData.PathDoesNotExist -f $mockParameterName) - } - } - - #Context 'When passing a correct uri as ''Value'' and type is ''PackageSource''' { - # It 'Should not throw an error' { - # { - # Test-ParameterValue ` - # -Value 'https://mocked.uri' - #-Type 'PackageSource' ` - #-ProviderName $mockProviderName - # } | Should -Not -Throw - # } - # } - - #Context 'When passing an correct package source as ''Value'' and type is ''PackageSource''' { - # BeforeAll { - # $mockParameterName = 'PSGallery' - - # Mock -CommandName Get-PackageSource -MockWith { - # return New-Object -TypeName Object | - # Add-Member -Name 'Name' -MemberType NoteProperty -Value $mockParameterName -PassThru - # } - # } - #} - - # Context 'When passing type is ''PackageSource'' and passing a package source that does not exist' { - # BeforeAll { - # $mockParameterName = 'PSGallery' - - # Mock -CommandName Get-PackageSource - # } - # } - - Context 'When passing invalid type in parameter ''Type''' { - BeforeAll { - $mockType = 'UnknownType' - } - - It 'Should throw the correct error' { - { - Test-ParameterValue ` - -Value 'AnyArgument' ` - -Type $mockType ` - -ProviderName $mockProviderName - } | Should -Throw ($LocalizedData.UnexpectedArgument -f $mockType) - } - } - } - - Describe 'Test-VersionParameter' { - Context 'When not passing in any parameters (using default values)' { - It 'Should return true' { - Test-VersionParameter | Should -BeTrue - } - } - - Context 'When only ''RequiredVersion'' are passed' { - It 'Should return true' { - #Test-VersionParameter -RequiredVersion '3.0.0.0' | Should -BeTrue - } - } -<# - Context 'When ''MinimumVersion'' has a lower version than ''MaximumVersion''' { - It 'Should throw the correct error' { - { - Test-VersionParameter ` - -MinimumVersion '2.0.0.0' ` - -MaximumVersion '1.0.0.0' - } | Should -Throw $LocalizedData.VersionError - } - } - - Context 'When ''MinimumVersion'' has a lower version than ''MaximumVersion''' { - It 'Should throw the correct error' { - { - Test-VersionParameter ` - -MinimumVersion '2.0.0.0' ` - -MaximumVersion '1.0.0.0' - } | Should -Throw $LocalizedData.VersionError - } - } - - Context 'When ''RequiredVersion'', ''MinimumVersion'', and ''MaximumVersion'' are passed' { - It 'Should throw the correct error' { - { - Test-VersionParameter ` - -RequiredVersion '3.0.0.0' ` - -MinimumVersion '2.0.0.0' ` - -MaximumVersion '1.0.0.0' - } | Should -Throw $LocalizedData.VersionError - } - } - #> - } - - - Describe 'Testing Test-DscParameterState' -Tag TestDscParameterState { - Context -Name 'When passing values' -Fixture { - It 'Should return true for two identical tables' { - $mockDesiredValues = @{ Example = 'test' } - - $testParameters = @{ - CurrentValues = $mockDesiredValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $true - } - - It 'Should return false when a value is different for [System.String]' { - $mockCurrentValues = @{ Example = [System.String]'something' } - $mockDesiredValues = @{ Example = [System.String]'test' } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when a value is different for [System.Int32]' { - $mockCurrentValues = @{ Example = [System.Int32]1 } - $mockDesiredValues = @{ Example = [System.Int32]2 } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when a value is different for [Int16]' { - $mockCurrentValues = @{ Example = [System.Int16]1 } - $mockDesiredValues = @{ Example = [System.Int16]2 } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when a value is different for [UInt16]' { - $mockCurrentValues = @{ Example = [System.UInt16]1 } - $mockDesiredValues = @{ Example = [System.UInt16]2 } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when a value is missing' { - $mockCurrentValues = @{ } - $mockDesiredValues = @{ Example = 'test' } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return true when only a specified value matches, but other non-listed values do not' { - $mockCurrentValues = @{ Example = 'test'; SecondExample = 'true' } - $mockDesiredValues = @{ Example = 'test'; SecondExample = 'false' } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - ValuesToCheck = @('Example') - } - - Test-DscParameterState @testParameters | Should -Be $true - } - - It 'Should return false when only specified values do not match, but other non-listed values do ' { - $mockCurrentValues = @{ Example = 'test'; SecondExample = 'true' } - $mockDesiredValues = @{ Example = 'test'; SecondExample = 'false' } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - ValuesToCheck = @('SecondExample') - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when an empty hash table is used in the current values' { - $mockCurrentValues = @{ } - $mockDesiredValues = @{ Example = 'test'; SecondExample = 'false' } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return true when evaluating a table against a CimInstance' { - $mockCurrentValues = @{ Handle = '0'; ProcessId = '1000' } - - $mockWin32ProcessProperties = @{ - Handle = 0 - ProcessId = 1000 - } - - $mockNewCimInstanceParameters = @{ - ClassName = 'Win32_Process' - Property = $mockWin32ProcessProperties - Key = 'Handle' - ClientOnly = $true - } - - $mockDesiredValues = New-CimInstance @mockNewCimInstanceParameters - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - ValuesToCheck = @('Handle', 'ProcessId') - } - - Test-DscParameterState @testParameters | Should -Be $true - } - - It 'Should return false when evaluating a table against a CimInstance and a value is wrong' { - $mockCurrentValues = @{ Handle = '1'; ProcessId = '1000' } - - $mockWin32ProcessProperties = @{ - Handle = 0 - ProcessId = 1000 - } - - $mockNewCimInstanceParameters = @{ - ClassName = 'Win32_Process' - Property = $mockWin32ProcessProperties - Key = 'Handle' - ClientOnly = $true - } - - $mockDesiredValues = New-CimInstance @mockNewCimInstanceParameters - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - ValuesToCheck = @('Handle', 'ProcessId') - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return true when evaluating a hash table containing an array' { - $mockCurrentValues = @{ Example = 'test'; SecondExample = @('1', '2') } - $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $true - } - - It 'Should return false when evaluating a hash table containing an array with wrong values' { - $mockCurrentValues = @{ Example = 'test'; SecondExample = @('A', 'B') } - $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when evaluating a hash table containing an array, but the CurrentValues are missing an array' { - $mockCurrentValues = @{ Example = 'test' } - $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - - It 'Should return false when evaluating a hash table containing an array, but the property i CurrentValues is $null' { - $mockCurrentValues = @{ Example = 'test'; SecondExample = $null } - $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - } - } - - Context -Name 'When passing invalid types for DesiredValues' -Fixture { - It 'Should throw the correct error when DesiredValues is of wrong type' { - $mockCurrentValues = @{ Example = 'something' } - $mockDesiredValues = 'NotHashTable' - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - $mockCorrectErrorMessage = ($script:localizedData.PropertyTypeInvalidForDesiredValues -f $testParameters.DesiredValues.GetType().Name) - { Test-DscParameterState @testParameters } | Should -Throw $mockCorrectErrorMessage - } - - It 'Should write a warning when DesiredValues contain an unsupported type' { - Mock -CommandName Write-Warning -Verifiable - - # This is a dummy type to test with a type that could never be a correct one. - class MockUnknownType { - [ValidateNotNullOrEmpty()] - [System.String] - $Property1 - - [ValidateNotNullOrEmpty()] - [System.String] - $Property2 - - MockUnknownType() { - } - } - - $mockCurrentValues = @{ Example = New-Object -TypeName MockUnknownType } - $mockDesiredValues = @{ Example = New-Object -TypeName MockUnknownType } - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - } - - Test-DscParameterState @testParameters | Should -Be $false - - Assert-MockCalled -CommandName Write-Warning -Exactly -Times 1 - } - } - - Context -Name 'When passing an CimInstance as DesiredValue and ValuesToCheck is $null' -Fixture { - It 'Should throw the correct error' { - $mockCurrentValues = @{ Example = 'something' } - - $mockWin32ProcessProperties = @{ - Handle = 0 - ProcessId = 1000 - } - - $mockNewCimInstanceParameters = @{ - ClassName = 'Win32_Process' - Property = $mockWin32ProcessProperties - Key = 'Handle' - ClientOnly = $true - } - - $mockDesiredValues = New-CimInstance @mockNewCimInstanceParameters - - $testParameters = @{ - CurrentValues = $mockCurrentValues - DesiredValues = $mockDesiredValues - ValuesToCheck = $null - } - - $mockCorrectErrorMessage = $script:localizedData.PropertyTypeInvalidForValuesToCheck - { Test-DscParameterState @testParameters } | Should -Throw $mockCorrectErrorMessage - } - } - - Assert-VerifiableMock - } -} diff --git a/build.ps1 b/build.ps1 index ff1f68b1a..26ea93c7b 100644 --- a/build.ps1 +++ b/build.ps1 @@ -52,7 +52,6 @@ $script:SrcPath = $config.SourcePath $script:OutDirectory = $config.BuildOutputPath $script:SignedDirectory = $config.SignedOutputPath $script:TestPath = $config.TestPath -$script:DSCModulePath = "DSC" $script:ModuleRoot = $PSScriptRoot $script:Culture = $config.Culture diff --git a/doBuild.ps1 b/doBuild.ps1 index ee7d99785..a2a3f7044 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -44,20 +44,6 @@ function DoBuild Write-Verbose -Verbose -Message "Copying ThirdPartyNotices.txt to '$BuildOutPath'" Copy-Item -Path "./Notice.txt" -Dest "$BuildOutPath" - # - # Copy DSC resources - # TODO: This should not be part of PowerShellGet build/publish and should be moved to its own project - # - Write-Verbose -Verbose -Message "Copying DSC resources to '$BuildOutPath" - Copy-Item -Path "${DSCModulePath}/DscResources" -Dest "$BuildOutPath" -Recurse -Force - - # - # Copy Localization and Resources helper modules - # TODO: This should not be part of PowerShellGet build/publish and should be moved to its own project - # - Write-Verbose -Verbose -Message "Copying DSC resources to '$BuildOutPath" - Copy-Item -Path "${DSCModulePath}/Modules" -Dest "$BuildOutPath" -Recurse -Force - # Build and place binaries if ( Test-Path "${SrcPath}/code" ) { Write-Verbose -Verbose -Message "Building assembly and copying to '$BuildOutPath'" From e6370bee76d42cd008b8f9a616d763f6e91ef917 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 2 Dec 2021 11:31:04 -0500 Subject: [PATCH 110/276] Add -PassThru support for Unregister-PSResourceRepository (#556) add PassThru to Unregister-PSResourceRepository cmdlet --- src/code/RepositorySettings.cs | 10 +++++++++- src/code/UnregisterPSResourceRepository.cs | 17 ++++++++++++++++- test/SetPSResourceRepository.Tests.ps1 | 9 +++++++++ test/UnregisterPSResourceRepository.Tests.ps1 | 10 ++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index a51ab4416..a38f45856 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -185,8 +185,9 @@ public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPrio /// Returns: void /// /// - public static void Remove(string[] repoNames, out string[] errorList) + public static List Remove(string[] repoNames, out string[] errorList) { + List removedRepos = new List(); List tempErrorList = new List(); XDocument doc; try @@ -211,6 +212,11 @@ public static void Remove(string[] repoNames, out string[] errorList) continue; } + removedRepos.Add( + new PSRepositoryInfo(repo, + new Uri(node.Attribute("Url").Value), + Int32.Parse(node.Attribute("Priority").Value), + Boolean.Parse(node.Attribute("Trusted").Value))); // Remove item from file node.Remove(); } @@ -218,6 +224,8 @@ public static void Remove(string[] repoNames, out string[] errorList) // Close the file root.Save(FullRepositoryPath); errorList = tempErrorList.ToArray(); + + return removedRepos; } public static List Read(string[] repoNames, out string[] errorList) diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index bf7647082..46b209e3f 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -3,6 +3,7 @@ using Microsoft.PowerShell.PowerShellGet.UtilClasses; using System; +using System.Collections.Generic; using System.Management.Automation; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets @@ -28,6 +29,12 @@ class UnregisterPSResourceRepository : PSCmdlet [ValidateNotNullOrEmpty] public string[] Name { get; set; } = Utils.EmptyStrArray; + /// + /// When specified, displays the repositories that were just unregistered + /// + [Parameter] + public SwitchParameter PassThru { get; set; } + #endregion #region Method overrides @@ -45,7 +52,7 @@ protected override void ProcessRecord() return; } - RepositorySettings.Remove(Name, out string[] errorList); + List removedRepositories = RepositorySettings.Remove(Name, out string[] errorList); // handle non-terminating errors foreach (string error in errorList) @@ -56,6 +63,14 @@ protected override void ProcessRecord() ErrorCategory.InvalidOperation, this)); } + + if (PassThru) + { + foreach (PSRepositoryInfo repository in removedRepositories) + { + WriteObject(repository); + } + } } #endregion diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index c302c3d79..30c0d3ecc 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -164,4 +164,13 @@ Describe "Test Set-PSResourceRepository" { $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } + + It "set repository and see updated repository with -PassThru" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + $res = Set-PSResourceRepository -Name "testRepository" -URL $tmpDir2Path -PassThru + $res.Name | Should -Be "testRepository" + $res.URL.LocalPath | Should -Contain $tmpDir2Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be False + } } diff --git a/test/UnregisterPSResourceRepository.Tests.ps1 b/test/UnregisterPSResourceRepository.Tests.ps1 index 4359c4be9..9cb30db2b 100644 --- a/test/UnregisterPSResourceRepository.Tests.ps1 +++ b/test/UnregisterPSResourceRepository.Tests.ps1 @@ -5,6 +5,8 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test Register-PSResourceRepository" { BeforeEach { + $TestGalleryName = Get-PoshTestGalleryName + $TestGalleryUrl = Get-PoshTestGalleryLocation Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" @@ -59,4 +61,12 @@ Describe "Test Register-PSResourceRepository" { It "throw error if Name is null" { {Unregister-PSResourceRepository -Name $null -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" } + + It "unregister repository using -PassThru" { + $res = Unregister-PSResourceRepository -Name $TestGalleryName -PassThru + $res.Name | Should -Be $TestGalleryName + $res.Url | Should -Be $TestGalleryURL + $res = Get-PSResourceRepository -Name $TestGalleryName + $res | Should -BeNullOrEmpty + } } From d9e1db9f7c20b8675cb8edb65aae46feda60fa5f Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 2 Dec 2021 09:12:12 -0800 Subject: [PATCH 111/276] Fix CI after removal of DSC modules (#557) --- .ci/ci_auto.yml | 1 - .ci/ci_release.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 8178c08e1..658f10aae 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -109,7 +109,6 @@ stages: } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSGet.Format.ps1xml") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" if (! (Test-Path -Path $netStandardPath)) { diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 722528604..fbb6b580f 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -98,7 +98,6 @@ stages: } Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PowerShellGet.psd1") -Dest $createdSignSrcPath -Force -Verbose Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "PSGet.Format.ps1xml") -Dest $createdSignSrcPath -Force -Verbose - Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Modules") -Dest $createdSignSrcPath -Recurse -Force -Verbose $netStandardPath = Join-Path -Path $createdSignSrcPath -ChildPath "netstandard2.0" if (! (Test-Path -Path $netStandardPath)) { From a4255ffd4d1778cc898a80156117e069fb01d62e Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 2 Dec 2021 14:41:35 -0800 Subject: [PATCH 112/276] Implement -Quiet param for Install and Update -PSResource (#561) --- src/code/InstallHelper.cs | 48 +++++++++++++++++++++----------------- src/code/SavePSResource.cs | 9 ++++++- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 8f5d45d8e..b9eafa4d4 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -326,31 +326,35 @@ private List InstallPackage( _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkg.Name)); - int activityId = 0; - string activity = ""; - string statusDescription = ""; - - if (pkgNamesToInstall.ToList().Contains(pkg.Name, StringComparer.InvariantCultureIgnoreCase)) - { - // Installing parent package (one whose name was passed in to install) - activityId = 0; - activity = string.Format("Installing {0}...", pkg.Name); - statusDescription = string.Format("{0}% Complete:", Math.Round(((double) totalPkgsCount/totalPkgs) * 100), 2); - currentPkgNumOfDependentPkgs = pkg.Dependencies.Count(); - dependentPkgCount = 1; - } - else + // Will suppress progress bar if -Quiet is passed in + if (!_quiet) { - // Installing dependent package - activityId = 1; - activity = string.Format("Installing dependent package {0}...", pkg.Name); - statusDescription = string.Format("{0}% Complete:", Math.Round(((double) dependentPkgCount/currentPkgNumOfDependentPkgs) * 100), 2); - dependentPkgCount++; + int activityId = 0; + string activity = ""; + string statusDescription = ""; + + if (pkgNamesToInstall.ToList().Contains(pkg.Name, StringComparer.InvariantCultureIgnoreCase)) + { + // Installing parent package (one whose name was passed in to install) + activityId = 0; + activity = string.Format("Installing {0}...", pkg.Name); + statusDescription = string.Format("{0}% Complete:", Math.Round(((double)totalPkgsCount / totalPkgs) * 100), 2); + currentPkgNumOfDependentPkgs = pkg.Dependencies.Count(); + dependentPkgCount = 1; + } + else + { + // Installing dependent package + activityId = 1; + activity = string.Format("Installing dependent package {0}...", pkg.Name); + statusDescription = string.Format("{0}% Complete:", Math.Round(((double)dependentPkgCount / currentPkgNumOfDependentPkgs) * 100), 2); + dependentPkgCount++; + } + + var progressRecord = new ProgressRecord(activityId, activity, statusDescription); + _cmdletPassedIn.WriteProgress(progressRecord); } - var progressRecord = new ProgressRecord(activityId, activity, statusDescription); - _cmdletPassedIn.WriteProgress(progressRecord); - // Create PackageIdentity in order to download string createFullVersion = pkg.Version.ToString(); if (pkg.IsPrerelease) diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index e9c456cd7..388d1a091 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -134,6 +134,13 @@ public string Path [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } + /// + /// Suppresses progress information. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] + public SwitchParameter Quiet { get; set; } + #endregion #region Method overrides @@ -246,7 +253,7 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p prerelease: pkgPrerelease, repository: pkgRepository, acceptLicense: true, - quiet: true, + quiet: Quiet, reinstall: true, force: false, trustRepository: TrustRepository, From 5c9bd7b1b4a124c3d322fcf0376c8340709a756c Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 3 Dec 2021 10:17:31 -0800 Subject: [PATCH 113/276] Update help documentation (#558) --- Docs/DesignDoc.md | 74 ------ Docs/FindPSResource.md | 305 ----------------------- Docs/GetPSResource.md | 148 ----------- Docs/GetPSResourceRepository.md | 78 ------ Docs/InstallPSResource.md | 263 -------------------- Docs/PublishPSResource.md | 310 ------------------------ Docs/RegisterPSResourceRepository.md | 176 -------------- Docs/SavePSResource.md | 205 ---------------- Docs/SetPSResourceRepository.md | 174 ------------- Docs/UninstallPSResource.md | 101 -------- Docs/UnregisterPSResourceRepository.md | 69 ------ Docs/UpdatePSResource.md | 217 ----------------- help/Get-PSResource.md | 2 +- help/Get-PSResourceRepository.md | 2 +- help/Install-PSResource.md | 88 ++++++- help/Publish-PSResource.md | 32 +-- help/Register-PSResourceRepository.md | 2 +- help/Save-PSResource.md | 112 ++++++++- help/Set-PSResourceRepository.md | 32 +-- help/Uninstall-PSResource.md | 35 ++- help/Unregister-PSResourceRepository.md | 18 +- help/Update-PSResource.md | 47 +++- src/code/GetPSResource.cs | 4 +- src/code/InstallPSResource.cs | 23 +- src/code/PublishPSResource.cs | 16 +- src/code/SavePSResource.cs | 15 +- src/code/UpdatePSResource.cs | 2 +- 27 files changed, 328 insertions(+), 2222 deletions(-) delete mode 100644 Docs/DesignDoc.md delete mode 100644 Docs/FindPSResource.md delete mode 100644 Docs/GetPSResource.md delete mode 100644 Docs/GetPSResourceRepository.md delete mode 100644 Docs/InstallPSResource.md delete mode 100644 Docs/PublishPSResource.md delete mode 100644 Docs/RegisterPSResourceRepository.md delete mode 100644 Docs/SavePSResource.md delete mode 100644 Docs/SetPSResourceRepository.md delete mode 100644 Docs/UninstallPSResource.md delete mode 100644 Docs/UnregisterPSResourceRepository.md delete mode 100644 Docs/UpdatePSResource.md diff --git a/Docs/DesignDoc.md b/Docs/DesignDoc.md deleted file mode 100644 index fc8ddcbd3..000000000 --- a/Docs/DesignDoc.md +++ /dev/null @@ -1,74 +0,0 @@ -# PowerShellGet V3 Module Design - -## Description - -PowerShellGet V3 is an upgrade to the currently available V2 module. -The V2 module is completely script based, and has dependencies on other PowerShell modules(PackageManagement). - -This version directly uses NuGet APIs, via NuGet managed code binaries. - -For more information, see [Re-architecting PowerShellGet - the PowerShell package manager](https://github.com/PowerShell/PowerShell-RFC/pull/185). - -## Goals - -- Works side by side with current PowerShellGet V2 module - -- Remove dependency on PackageManagement module, and directly use NuGet APIs - -- Leverage the latest NuGet V3 APIs - -- Provide cmdlets that perform similar functions but do not interfere with V2 cmdlets - -- Implement as binary cmdlets and minimize use of PowerShell scripts - -- Remove unneeded components (DscResources). TODO: Discuss with Sydney and Steve. - -- Minimize binary dependencies - -- Work over all PowerShell supported platforms - -- Minimize code duplication - -- Have only one .NET dependency (netstandard2.0) for Windows 5.x compatibility - -## Compatibility Module - -### Update module as needed - -### Write/update tests as needed - -## Summary of work estimates - -### Cmdlet work estimates - -TODO: - -### Compatibility Module work estimates - -TODO: - -## Cmdlets - -### Find-PSResource - -[Find-PSResource](./FindPSResource.md) - -### Get-PSResource - -### Get-PSResourceRepository - -### Install-PSResource - -### Publish-PSResource - -### Register-PSResourceRepository - -### Save-PSResource - -### Set-PSResourceRepository - -### Uninstall-PSResource - -### Unregister-PSResourceRepository - -### Update-PSResource diff --git a/Docs/FindPSResource.md b/Docs/FindPSResource.md deleted file mode 100644 index aebf29349..000000000 --- a/Docs/FindPSResource.md +++ /dev/null @@ -1,305 +0,0 @@ -# Find-PSResource - -The `Find-PSResource` cmdlet combines the `Find-Module, Find-Script, Find-DscResource, Find-Command` cmdlets from V2. -It performs a search on a repository (local or remote) based on the `-Name` parameter argument. -It returns `PSResourceInfo` objects which describe each resource item found (with Name, Version, Prerelease and Description information displayed, but other properties available too). -Other parameters allow the returned results to be filtered by item Type, Tag, Version and IncludeDependencies. - -Alternatively, a `-CommandName` or `-DscResourceName` can be provided and resource packages having those commands or Dsc resources will be returned. This has not been implemented yet. -The `-ModuleName` parameter allows the command or dsc resource name search to be limited to a subset of module packages. This has not been implemented yet. - -## Syntax - -### ResourceNameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tag ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] -``` - -### CommandNameParameterSet -``` PowerShell -[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] -``` - -### DscResourceNameParameterSet -``` PowerShell -[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] -``` -### TagParameterSet -``` PowerShell -[[-Name ][-Tag ] [-Prerelease] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] -``` - -### TypeParameterSet -``` PowerShell -[[Name ] [-Prerelease] [-Type ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name of a resource or resources to find. -Accepts wild card character '*'. - -```yml -Type: string[] -Parameter Sets: ResourceNameParameterSet -``` - -### -Type - -Specifies one or more resource types to find. -Resource types supported are: Module, Script, Command, DscResource. - -```yml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] -Parameter Sets: ResourceNameParameterSet -AllowedValues: 'Module','Script','DscResource','Command' -``` - -### -Version - -Specifies the version of the resource to be returned. - -```yml -Type: string -Parameter Sets: (All) -``` - -### -Prerelease - -When specified, includes prerelease versions in search results returned. - -```yml -Type: SwitchParameter -Parameter Sets: (All) -``` - -### -Tag - -Filters search results for resources that include one or more of the specified tags. - -```yml -Type: string[] -Parameter Sets: (All) -``` - -### -Repository - -Specifies one or more repository names to search. -If not specified, search will include all currently registered repositories, in order of highest priority, til first repository package is found in. - -```yml -Type: string[] -Parameter Sets: (All) -``` - -### -Credential - -Optional credentials to be used when accessing a repository. - -```yml -Type: PSCredential -Parameter Sets: (All) -``` - -### -IncludeDependencies - -When specified, search will return all matched resources along with any resources the matched resources depends on. -Dependencies are deduplicated. - -```yml -Type: SwitchParameter -Parameter Sets: (All) -``` - -### -CommandName - -Specifies a list of command names that searched module packages will provide. -Wildcards are supported. -Not yet implemented. - -```yml -Type: string[] -Parameter Sets: CommandNameParameterSet -``` - -### -DscResourceName - -Specifies a list of dsc resource names that searched module packages will provide. -Wildcards are supported. -Not yet implemented. - -```yml -Type: string[] -Parameter Sets: DscResourceNameParameterSet -``` - -### -ModuleName - -Specifies a module resource package name type to search for. -Wildcards are supported. -Not yet implemented. - -```yml -Type: string -Parameter Sets: CommandNameParameterSet, DscResourceParameterSet -``` - -### Outputs - -```json -"PSResourceInfo" : { - "Author", - "CompanyName", - "Copyright", - "Dependencies", - "Description", - "IconUri", - "Includes", - "InstalledDate", - "InstalledLocation", - "IsPrerelease", - "LicenseUri", - "Name", - "PackageManagementProvider", - "PowerShellGetFormatVersion", - "PrereleaseLabel", - "ProjectUri", - "PublishedDate", - "ReleaseNotes", - "Repository", - "RepositorySourceLocation", - "Tags", - "Type", - "UpdatedDate", - "Version" -} -``` - -## Notes - -Search strategy will depend on what NuGet APIs support on the server. -PowerShell has its own wildcard behavior that may not be compatible with the NuGet APIs. -The V2 APIs do provide property filtering and some limited wildcard support. -It is not yet clear if V2 or V3 APIs should be used. -Need benefit cost analysis. - -Search can be performed on remote or local (file based) repositories, depending on the repository Url. - -Does the `-Credential` parameter apply to all repositories being searched? -If so, can that result in an error for repositories that do not require credentials? -How are multiple repository searches that require different credentials handled? -Should searches with credential be limited to a single repository? - -Should search results be cached locally on the client machine? -If so, should the cache be per PowerShell session or file based? -At what point should the local cache be updated from the server? -Should there be a parameter switch that forces the search to go directly to the server and skip the local cache? -Should the cache be used if a specific repository is specified? -We should assume that a specific resource package version is identical over any repository from which it is retrieved. - -Should a search with no name or 'all' wildcard result in all repository items returned? -Should there be a default limit for number of items returned, and if so can it be bypassed? - -The V2 `Find-Command, Find-DscResource` will be combined into `Find-PSResource`. -The `Find-RoleCapability` cmdlet will be dropped for the first release of V3. - -## Tests - -Most search tests can be performed on a local repository. - -Some tests should be performed on remote repository (PSGallery) to verify remote operation, but can be limited. - -### -Name param - -- Single name search -- Wildcard search -- Multiple name search -- Cancel search -- Errors: Not found (single name, wildcard, multiple name) -- Errors: Repository: Invalid name, connection error, etc - -### -Type param - -- Validate correct resource type returned - -### -Version param - -- Validate correct resource version returned -- Validate wild card (if supported), correct version range returned -- Errors: Not found -- Errors: Invalid version string format - -### -Prerelease param - -- Validate prerelease version returned - -### -Tags param - -- Validate tag filtering on returned resources - -### -Repository param - -- All repository search -- Single repository search -- Multiple repository search -- Errors: Repository not found - -### -Credential param - -- Validate credential search -- Errors: Credential: Invalid - -### -IncludeDependencies param - -- Validate dependency inclusion in return results - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement package search helpers - -Create helper functions that support all search functions -Use existing code as starting point -4 days - -### Investigate V3 API wildcard support - -Look into how V3 APIs can be used to reduce what is returned from the server -7 days - -### Implement package filtering functions - -Create helper functions to provide filtering of search results -3 days - -### Investigate and implement local cache - -Write mini-design document on local caching strategy -Implement local cache -10 days - -### Create test support - -Create any test repositories and mocks for tests -4 days - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -5 days - -### Write support function tests - -Create all needed tests to validate caching and search helpers -5 days diff --git a/Docs/GetPSResource.md b/Docs/GetPSResource.md deleted file mode 100644 index fcaf0212f..000000000 --- a/Docs/GetPSResource.md +++ /dev/null @@ -1,148 +0,0 @@ -# Get-PSResource - -The `Get-PSResource` cmdlet combines the `Get-InstalledModule, Get-InstalledScript` cmdlets from V2. -It performs a search within module or script installation paths based on the `-Name` parameter argument. -It returns `PSRepositoryItemInfo` objects which describe each resource item found. -Other parameters allow the returned results to be filtered by version, prerelease version, and path. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Version ] [-Type ] [-Prerelease] [-Path ] [-WhatIf] [-Confirm] [] -``` - - -## Parameters - -### -Name - -Name of a resource or resources to find. -Accepts wild card characters. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Version - -Specifies the version of the resource to be returned. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -Type - -Specifies one or more resource types to find. -Two resource types are supported: Module and Script. - -```yml -Type: string[] -Parameter Sets: ResourceNameParameterSet -AllowedValues: 'Module','Script' -``` - -### -Prerelease - -When specified, includes prerelease versions in search. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -Path - -Specifies the path to search in. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - - -### Outputs - -```json -"PSRepositoryItemInfo" : { - "Name", - "Version", - "Type", - "Description", - "Author", - "CompanyName", - "Copyright", - "PublishedDate", - "InstalledDate", - "UpdatedDate", - "LicenseUri", - "ProjectUri", - "IconUri", - "Tags", - "Includes", - "PowerShellGetFormatVersion", - "ReleaseNotes", - "Dependencies", - "RepositorySourceLocation", - "Repository", - "PackageManagementProvider", - "AdditionalMetadata" -} -``` - -## Notes - -Currently the `-Prerelease` parameter is not implemented. - -Add why - -## Tests - -Most search tests can be performed on a local file system. - -### -Name param - -- Single name search -- Wildcard search -- Multiple name search -- Cancel search -- Errors: Not found (single name, wildcard, multiple name) -- Errors: File path: Invalid name, cannot find, etc - -### -Version param - -- Validate correct resource version returned -- Validate wild card (if supported), correct version range returned -- Errors: Not found -- Errors: Invalid version string format - -### -Prerelease param - -- Validate prerelease version returned - -### -Path param - -- Single path search -- OneDrive path search -- Errors: Path not found - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -2 days - -### Create test support - -Create any test repositories and mocks for tests -4 days - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -5 days - diff --git a/Docs/GetPSResourceRepository.md b/Docs/GetPSResourceRepository.md deleted file mode 100644 index f333058c9..000000000 --- a/Docs/GetPSResourceRepository.md +++ /dev/null @@ -1,78 +0,0 @@ -# Get-PSResourceRepository - -The `Get-PSResourceRepository` cmdlet replaces the `Get-PSRepository` cmdlet from V2. - -It searches for the PowerShell resource repositories that are registered on the machine. -By default it will return all registered repositories, or if the `-Name` parameter argument is specified -then it wil return the repository whose name matches the specified value. - -It returns `PSRepositoryInfo` objects which describe each resource item found. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name of a registered repository to find. -Supports wild card characters. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### Outputs - -```json -"PSRepositoryInfo" : { - "Name", - "Url", - "Trusted", - "Priority" -} -``` - -## Notes - -Running the `Get-PSResourceRepository` cmdlet without a Name parameter specified will return all registered repositories. - -## Tests - -Tests added for terminating and non-terminating error handling. - -Tests able to get repositories with different allowed URL URI schemes. - -### -Name param - -- Single name search -- wilcard search and empty value (returns all) compatibility -- Multiple name search -- Errors: Repository not found (single name, multiple name) - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Switch output to PSRepositoryInfo type - -Switch from returning Object object to PSRepositoryInfo object, and create that class -1-2 days - -### Create test support - -Create any test repositories and mocks for tests -1 day - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -1 day diff --git a/Docs/InstallPSResource.md b/Docs/InstallPSResource.md deleted file mode 100644 index b9a946204..000000000 --- a/Docs/InstallPSResource.md +++ /dev/null @@ -1,263 +0,0 @@ -# Install-PSResource - -The `Install-PSResource` cmdlet combines the `Install-Module, Install-Script` cmdlets from V2. -It performs an installation from a package found on a repository (local or remote) based on the `-Name` parameter argument. -It does not return an object. -Other parameters allow the returned results to be further filtered. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Version ] [-Prerelease] [-Repository ] -[-Credential ] [-Scope ] [-NoClobber] [-TrustRepository] -[-Reinstall] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] [] -``` -### InputObjectParameterSet -``` PowerShell -[[-InputObject] ] -``` -### RequiredResourceParameterSet -``` PowerShell -[[-RequiredResource] ] [-Quiet] [-WhatIf] [-Confirm] [] -``` -### RequiredResourceFileParameterSet -``` PowerShell -[[-RequiredResourceFile] ] [-Quiet] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name of a resource or resources to be installed. -Accepts wild card characters. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Version - -Specifies the version or version range of the resource to be installed. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -Prerelease - -When specified, allows installation of prerelease versions. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -Repository - -Specifies one or more repository names to search. -If not specified, search will the highest priority repository. - -```yml -Type: string[] -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -Credential - -Optional credentials to be used when accessing a private repository. - -```yml -Type: PSCredential -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -Scope - -When specified, will install to either CurrentUser or AllUsers scope. - -```yml -Type: String -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -AllowedValues: 'CurrentUser','AllUsers' -``` - -### -NoClobber - -Prevents installing modules that have the same cmdlets as a differently named module already installed. - -```yml -Type: string[] -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -TrustRepository - -If specified, suppresses prompt for untrusted repositories. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -Reinstall - -If specified, overwrites a previously installed resource with the same name and version. - -```yml -Type: string -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -Quiet - -If specified, suppresses progress information. - -```yml -Type: string -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -AcceptLicense - -If specified, modules that require a license agreement will be automatically accepted during installation. - -```yml -Type: string -Parameter Sets: NameParameterSet, RequiredResourceFileParameterSet -``` - -### -RequiredResourceFile - -Specifies a file - -```yml -Type: string -Parameter Sets: RequiredResourceFileParameterSet -``` - -### -RequiredResourceJSON - -Installs the resources specified in the json configuration. - -```yml -Type: string or hashtable -Parameter Sets: RequiredResourceParameterSet -``` - -### -InputObject - -Installs the resources passed in via pipeline. - -```yml -Type: ? -Parameter Sets: InputObjectParameterSet -``` - -### Outputs - -No output. - -## Notes - - -### -Name param - -- Single name search -- Wildcard search -- Multiple name search -- Cancel search -- Errors: Not found (single name, wildcard, multiple name) -- Errors: Repository: Invalid name, connection error, etc - -### -Version param - -- Validate correct resource version installed -- Validate wild card (if supported), correct version range installed -- Errors: Not found -- Errors: Invalid version string format - -### -Prerelease param - -- Validate prerelease version installed - -### -Repository param - -- All repository search -- Single repository search -- Multiple repository search -- Errors: Repository not found - -### -Credential param - -- Validate credential search -- Errors: Credential: Invalid - -### -Scope param - -- Validate installation to correct scope (both current and all users) - -### -NoClobber param - -- Validate proper warning message if clobbering will happen - -### -TrustRepository param - -- Validate that user is not prompted and has access to repository - -### -Reinstall param - -- Validate proper installation when the module version is already installed -- Validate proper installation if resource is not installed - -### -Quiet param - -- Validate that progress bar is supressed - -### -AcceptLicense param - -- Validate that there is no prompt for modules that require license agreement - -### -RequiredResourceFile param - -- - -### -RequiredResourceJSON param - -- Validate that installation works with hashtable input -- Validate that installation works with string input -- Validate that all parameters work in string or hashtable -- Error: incorrect formatting -- Error: incorrect object type - -### -InputObject param - -- Validate that object passed in is able to install - - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement package install helpers - -Create helper functions that support all search functions -Use existing code as starting point -4 days - -### Create test support - -Create any test repositories and mocks for tests -4 days - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -5 days - diff --git a/Docs/PublishPSResource.md b/Docs/PublishPSResource.md deleted file mode 100644 index e1a38b8da..000000000 --- a/Docs/PublishPSResource.md +++ /dev/null @@ -1,310 +0,0 @@ -# Publish-PSResource - -The `Publish-PSResource` cmdlet combines the `Publish-Module` and `Publish-Script` cmdlets from V2. - -It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. - -## Syntax - -### PathParameterSet -``` PowerShell -[[-APIKey] ] [-Repository ] [-DestinationPath ] [-Path] ] [-Credential ] [-SkipDependenciesCheck] [-ReleaseNotes ] [-Tags ] [-LicenseUrl ] [-IconUrl ] [-ProjectUrl ] [-NuspecPath ] [-Proxy ][-ProxyCredential ] [-WhatIf] [-Confirm] [] -``` - -### PathLiteralParameterSet -``` PowerShell -[[-APIKey] ] [-Repository ] [-DestinationPath ] [-LiteralPath] ] [-Credential ] [-SkipDependenciesCheck] [-ReleaseNotes ] [-Tags ] [-LicenseUrl ] [-IconUrl ] [-ProjectUrl ] [-NuspecPath ] [-Proxy ][-ProxyCredential ] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -APIKey - -Specifies the API key that you want to use to publish a resource to the online gallery. -Not mandatory. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -Repository - -Specifies the repository to publish to. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -DestinationPath - -Specifies the location to be used to publish a nupkg locally. - -```yml -Type: string -Parameter Sets: (All) -``` - -### -Path - -When specified, includes prerelease versions in search. - -```yml -Type: string -Parameter Sets: PathParameterSet -``` - -### -LiteralPath - -Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is used exactly as entered. No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. Single quotation marks tell PowerShell not to interpret any characters as escape sequences. - -```yml -Type: string -Parameter Sets: PathLiteralParameterSet -``` - -### -Credential - -Specifies a user account that has rights to a specific repository (used for finding dependencies). - -```yml -Type: PSCredential -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -SkipDependenciesCheck - -Bypasses the default check that all dependencies are present. - -```yml -Type: SwitchParameter -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -ReleaseNotes - -Updates nuspec: specifies a string containing release notes or comments that you want to be available to users of this version of the resource. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -Tags - -Updates nuspec: adds one or more tags to the resource that you are publishing. This applies only to the nuspec. - -```yml -Type: string[] -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -LicenseUrl - -Updates nuspec: specifies the URL of licensing terms for the resource you want to publish. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -IconUrl - -Updates nuspec: specifies the URL of an icon for the resource. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -ProjectUrl - -Updates nuspec: specifies the URL of a webpage about this project. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -Exclude - -Excludes files from a nuspec - -```yml -Type: string[] -Parameter Sets: ModuleNameParameterSet -``` - -### -NuspecPath - -Specifies a nuspec file by path rather than relying on this module to produce one. - -```yml -Type: string -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -Proxy - -Specifies a proxy server for the request, rather than a direct connection to the internet resource. - -```yml -Type: Uri -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -ProxyCredential - -Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. - -```yml -Type: PSCredential -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### -PassThru - -When specified, displays the succcessfully published resource and its information. - -```yml -Type: PSCredential -Parameter Sets: PathParameterSet, PathLiteralSet -``` - -### Outputs - -if `-PassThru` is not specified output is none - -if `-PassThru` is specified output is: - -```json -"PSRepositoryItemInfo" : { - "Name", - "Version", - "Type", - "Description", - "Author", - "CompanyName", - "Copyright", - "PublishedDate", - "InstalledDate", - "UpdatedDate", - "LicenseUri", - "ProjectUri", - "IconUri", - "Tags", - "Includes", - "PowerShellGetFormatVersion", - "ReleaseNotes", - "Dependencies", - "RepositorySourceLocation", - "Repository", - "PackageManagementProvider", - "AdditionalMetadata" -} -``` - -## Notes - -## Tests - -Some tests should be performed to publish a resource of type Module, and othersfor resource of type Script. - -Tests should have varying levels of required and optional nuspec data to test parsing helper methods. - -### -APIKey param - -- Validate not null or empty if paramater arguemnt provided -- Errors: APIKey not valid or incorrect format - -### -Repository param - --Validate not null or empty if paramater arguemnt provided --Errors: Repository referenced is not registered or found. - -### -DestinationPath param - --Validate not null or empty if paramater arguemnt provided --Errors: DestinationPath does not exist. - -### -Path param - --Validate not null or empty if paramater arguemnt provided --Errors: validate not null or empty if provided, path does not exist - -### -LiteralPath param - --Validate not null or empty if paramater arguemnt provided --Errors: Literal path does not exist. - -### -Credential param - --Validate not null or empty if paramater arguemnt provided - -### -ReleaseNotes param - --Validate not null or empty if paramater arguemnt provided - -### -Tags param - --Validate not null or empty if paramater arguemnt provided - -### -LicenseUrl param - --Validate not null or empty if paramater arguemnt provided - -### -IconUrl param - --Validate not null or empty if paramater arguemnt provided - -### -ProjectUrl param - --Validate not null or empty if paramater arguemnt provided - -### -Exclude param - --Validate not null or empty if paramater arguemnt provided --Errors: files specified do not exist - -### -NuspecPath param - --Validate not null or empty if paramater arguemnt provided --Errors: file does not exist, not of valid format or extension. - -### -Proxy param - --Validate not null or empty if paramater arguemnt provided - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement publish function helper methods - -Create helper functions that support all search functions -Use existing code as starting point -1-2 days - -### Implement publish function method - -Create main publish function method, use existing code as starting point -1 day - -### Create test support - -Create any test repositories and mocks for tests -1 day - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -1-2 days - -### Write support function tests - -Create all needed tests to validate publish helpers -1-2 days diff --git a/Docs/RegisterPSResourceRepository.md b/Docs/RegisterPSResourceRepository.md deleted file mode 100644 index f5fb2e1c2..000000000 --- a/Docs/RegisterPSResourceRepository.md +++ /dev/null @@ -1,176 +0,0 @@ -# Register-PSResourceRepository - -The `Register-PSResourceRepository` cmdlet replaces the `Register-PSRepository` from V2. - -It registers a repository for PowerShell resources. The repository is registered to the user's machine. - -The Register-PSResourceRepository cmdlet determines which repository will be the default when searching for PowerShell modules. This is done by specifying the priority for a repository when registering it. So later when other cmdlets are used to search for/install a resource, it will look through all registered repositories (in order of highest ranking priority and then by alphabetical order) until it finds the first match. The aforementioned compatible cmdlets that use this default repository rankings include: Find-PSResource, Install-PSResource, and Publish-PSResource cmdlets. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-URL ] [-Priority ] [-Trusted] [-WhatIf] [-Confirm] [] -``` - -### PSGalleryParameterSet -``` PowerShell -[[-Priority ] [-Trusted] [-PSGallery] [-WhatIf] [-Confirm] [] -``` - -### RepositoriesParameterSet -``` PowerShell -[[-Repositories] >] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name for the repository to be registered. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -URL - -Specifies the URL location of the repository to be registered. - -```yml -Type: Uri -Parameter Sets: NameParameterSet -``` - -### -PSGallery - -When specified, registers PSGallery repository. - -```yml -Type: SwitchParameter -Parameter Sets: PSGalleryParameterSet -``` - -### -Repositories - -Specifies a hashtable of repositories and is used to register multiple repositories at once. - -```yml -Type: List -Parameter Sets: RepositoriesParameterSet -``` - -### -Trusted - -Specifies whether the repository should be trusted. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet, PSGalleryParameterSet -``` - -### -Proxy - -Specifies a proxy server for the request, rather than a direct connection to the internet resource. - -```yml -Type: Uri -Parameter Sets: NameParameterSet, PSGalleryNamesSet, RepositoriesParameterSet -``` - -### -ProxyCredential - -Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. - -```yml -Type: PSCredential -Parameter Sets: NameParameterSet, PSGalleryNamesSet, RepositoriesParameterSet -``` - -### -Priority - -Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. or example, if a item was being searched for across two repositories with the aforementioned ranking than the repository with priority 10 would be searched first. - -```yml -Type: int -Parameter Sets: NameParameterSet, PSGalleryParameterSet -``` - -### -PassThru - -When specified, displays the succcessfully registered repository and its information. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet, PSGalleryParameterSet, RepositoriesParameterSet -``` - -### Outputs - -if `-PassThru` not specified, output is none - -if `-PassThru` is specified, output is: - -```json -"PSRepositoryInfo" : { - "Name", - "Url", - "Trusted", - "Priority" -} -``` - -## Notes - -In this V3 cmdlet, repository uniqueness is dictated by the `-Name` parameter. This is unlike in the V2 cmdlet `Register-PSRepository`, whre the `-SourceLocation` parameter (equivalent of `URL` parameter here) dictated uniqueness, so a repository could not be registered if one with the same `-SourceLocation` value had already been registered. - -## Tests - -Tests able to register repositories with different allowed URL URI schemes. - -### -Name param - -- Single name registering -- Errors: Invalid name (i.e with wildcard character) -- Errors: Name is null -- Errors: Name is just whitespace -- Errors: Name is not unique (another repository is already registered with same name) -- Errors: Name is "PSGallery" when registering with NameParameterSet - -### -URL param - -- Errors: URL is null when NameParameterSet is used -- Errors: URL is of invalid URI scheme (i.e not HTTPS, HTTP, FTP, File Based URI scheme) - -### -Repositories param - -- Errors: Expected Hashtable keys not found -- Errors: PSGallery provided with Name or URI key -- Errors: Name key value is "PSGallery" - -### -Priority param - -- Validate priority value supplied is in range of 0-50 - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement repository registering function - -Write ProcessRecord() function, perhaps split time/task by ParamaterSet and corresponding functionality -1-2 days - -### Create test support - -Create any test repositories and mocks for tests -1 day - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -1 day diff --git a/Docs/SavePSResource.md b/Docs/SavePSResource.md deleted file mode 100644 index 741e94002..000000000 --- a/Docs/SavePSResource.md +++ /dev/null @@ -1,205 +0,0 @@ -# Save-PSResource - -The `Save-PSResource` cmdlet combines the `Save-Module, Save-Script` cmdlets from V2. -It saves from a package found on a repository (local or remote) based on the `-Name` parameter argument. -It does not return an object. -Other parameters allow the returned results to be further filtered. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Version ] [-Prerelease] [-Repository ] -[-Path string] [-Credential ] [-AsNupkg] [-IncludeXML] [-TrustRepository] [-WhatIf] [-Confirm] [] -``` - -### InputObjectParameterSet -``` PowerShell -[[-InputObject] ] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name of a resource or resources to save from a repository. -A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Version - -Specifies the version or version range of the resource to be saved. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -Prerelease - -When specified, allow saving prerelease versions. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -Repository - -Specifies one or more repository names to search. -If not specified, search will only search the highest priority repository. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Credential - -Optional credentials to be used when accessing a private repository. - -```yml -Type: PSCredential -Parameter Sets: NameParameterSet -``` - -### -AsNupkg - -When specified, saves the resource as a .nupkg. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -IncludeXML - -Saves the metadata XML file with the resource. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Path - -Specifies the destination where the resource is to be saved. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -TrustRepository - -When specified, suppresses being prompted for untrusted sources. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -InputObject - -Used to pass in an object via pipeline to save. - -```yml -Type: object[] -Parameter Sets: InputObjectParameterSet -``` - -### Outputs - -No output. - -## Notes - -Should -TrustRepository parameter be removed? Ie, should repositories be trusted by default? -Now that we have repository priorities, one could set an untrusted repository to a lower priority. - -How often is a repository intentionally set as 'untrusted'? - - -## Tests - -Most search tests can be performed on a local repository. - -### -Name param - -- Single name search -- Wildcard search -- Multiple name search -- Cancel search -- Errors: Not found (single name, wildcard, multiple name) -- Errors: Repository: Invalid name, connection error, etc - -### -Version param - -- Validate correct resource version returned -- Validate wild card (if supported), correct version range returned -- Errors: Not found -- Errors: Invalid version string format - -### -Prerelease param - -- Validate prerelease version returned - -### -Repository param - -- All repository search -- Single repository search -- Multiple repository search -- Errors: Repository not found - -### -Credential param - -- Validate credential search -- Errors: Credential: Invalid - -### -AsNupkg param - -- Validate that package gets saved as .nupkg -- Errors: package is unable to save - -### -IncludeXML param - -- Validate that package gets saved with xml -- Errors: unable to create XML, unable to save XML - -### -Path param - -- Validate that package saves in the correct path -- Errors: unable to access path (such as OneDrive or paths with spaces) - -### -TrustRepository - -- Validate that user is not prompted and has access to repository - - - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement uninstall helpers - -Create helper functions that support all search functions -Use existing code as starting point -2 days - -### Create test support - -Create any test repositories and mocks for tests -4 days - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -5 days diff --git a/Docs/SetPSResourceRepository.md b/Docs/SetPSResourceRepository.md deleted file mode 100644 index d363f2a04..000000000 --- a/Docs/SetPSResourceRepository.md +++ /dev/null @@ -1,174 +0,0 @@ -# Set-PSResourceRepository - -The `Set-PSResourceRepository` cmdlet replaces the `Set-PSRepository` cmdlet from V2. - -It sets the values for an already registered module repository. Specifically, it sets values for -either the `-URL`, `-Trusted` and `-Priority` parameter arguments by additionally providing the `-Name` parameter argument. - -The settings are persistent on the machine and apply to all versions of PowerShell installed for that user. - -The `-URL` for the PSGallery repository, which is pre-defined for this repository which is registered by default on each user's PowerShell instance, cannot be set via this cmdlet and will generate an exception. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-URL ] [-Credential ] [-Trusted] [-WhatIf] [-Confirm] [] -``` - -### RepositoriesParameterSet -``` PowerShell -[[-Repositories] ] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Specifies name of the registered repository to be set. -Does not accept wildcard characters. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -URL - -Specifies the location of the repository to be set. -Types of Uri's supported: HTTPS, HTTP, File base, FTP scheme - -```yml -Type: Uri -Parameter Sets: NameParameterSet -``` - -### -Credential - -Specifies a user account that has rights to find a resource from a specific repository. - -```yml -Type: PSCredential -Parameter Sets: NameParameterSet -``` - -### -Repositories - -Specifies an array of hashtables containing information on repositories and is used to register multiple repositories at once. - -```yml -Type: Hashtable[] -Parameter Sets: RepositoriesParameterSet -``` - -### -Trusted - -When specified, repository will be set to trusted. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -Proxy - -Specifies a proxy server for the request, rather than a direct connection to the internet resource. - -```yml -Type: Uri -Parameter Sets: NameParameterSet, RepositoriesParameterSet -``` - -### -ProxyCredential - -Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. - -```yml -Type: PSCredential -Parameter Sets: NameParameterSet, RepositoriesParameterSet -``` - -### -Priority - -Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. -Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). -For example, if a item was being searched for across two repositories with the aforementioned ranking than the repository with priority 10 would be searched first. - -```yml -Type: int -Parameter Sets: NameParameterSet, RepositoriesParameterSet -``` - -### -PassThru - -When specified, displays the succcessfully set repository and its information - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet, RepositoriesParameterSet -``` - -### Outputs - -if `-PassThru` not specified output is none - -if `-PassThru` is specified output is: - -```json -"PSRepositoryInfo" : { - "Name", - "Url", - "Trusted", - "Priority" -} -``` - -## Notes - -## Tests - -Tests added will need to set repositories to URLs with different allowed URI schemes. - -Test to verify Set-PSResourceRepository with PSGallery `-Name` and `-URL` value is not allowed, and generates error with expected error message. - -### -Name param - -- Single name search -- Errors: Not found (single name) -- Errors: Invalid name (i.e with wildcard character) -- Errors: Repository: Repository with name not found, etc - -### -URL param - -- Errors: if URL with unsupported type Uri scheme used, or if correct scheme but value is for path/location that doesn't exist -- Errors: if URL to be changed is used in conjuction with `-Name` parameter argument with value of PSGallery - -### -Repositories param - -- Errors: Expected Hashtable keys not found - -### -Priority param - -- Validate priority value supplied is in range of 0-50 - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement repository update function - -Create and implement repository update function -1 day - -### Create test support - -Create any test repositories and mocks for tests -1 day - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -1 day diff --git a/Docs/UninstallPSResource.md b/Docs/UninstallPSResource.md deleted file mode 100644 index ed447b88e..000000000 --- a/Docs/UninstallPSResource.md +++ /dev/null @@ -1,101 +0,0 @@ -# Uninstall-PSResource - -The `Uninstall-PSResource` cmdlet combines the `Uninstall-Module, Uninstall-Script` cmdlets from V2. -It uninstalls a package found in a module or script installation path based on the `-Name` parameter argument. -It does not return an object. -Other parameters allow the returned results to be further filtered. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Version ] [-PrereleaseOnly] [-Tags ] -[-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name of a resource or resources that has been installed. -Accepts wild card characters. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Version - -Specifies the version of the resource to be uninstalled. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -PrereleaseOnly - -When specified, allows ONLY prerelease versions to be uninstalled. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### Outputs - -No output. - - -## Notes - -Should a -PassThru parameter be added? - -## Tests - -Most search tests can be performed on a local repository. - -### -Name param - -- Single name search -- Wildcard search -- Multiple name search -- Cancel search -- Errors: Not found (single name, wildcard, multiple name) -- Errors: Path errors (OneDrive access, etc) - -### -Version param - -- Validate correct resource version returned -- Validate wild card (if supported), correct version range returned -- Errors: Not found -- Errors: Invalid version string format - -### -Prerelease param - -- Validate prerelease version returned - - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement uninstall helper - -Create helper functions that support all search functions -Use existing code as starting point -2 days - -### Create test support - -Create any test repositories and mocks for tests -4 days - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -5 days diff --git a/Docs/UnregisterPSResourceRepository.md b/Docs/UnregisterPSResourceRepository.md deleted file mode 100644 index b7ef83ea0..000000000 --- a/Docs/UnregisterPSResourceRepository.md +++ /dev/null @@ -1,69 +0,0 @@ -# Unregister-PSResourceRepository - -The `Unregister-PSResourceRepository` cmdlet replaces the `Unregister-PSRepository` cmdlet from V2. - -It unregisters a repository that's found to be registered on the machine. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Specifies name(s) of the repositories to unregister. -Does not accept wild card characters. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### Outputs - -none - -## Notes - -`-Name` parameter doesn't support wildcard characters. - -## Tests - -Tests able to unregister repositories with different allowed URL URI schemas. - -Tests added for terminating and non-terminating error handling. - -Tests to unregister multiple repositories provided to `-Name`. - -### -Name param - -- Single name unregister -- Multiple name unregister -- Errors: Not found (single name,multiple name -- Errors: Name contains wildcard which isn't supported - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement unregister function - -Create unregister function -1 day - -### Create test support - -Create any test repositories and mocks for tests -1 day - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -1 day diff --git a/Docs/UpdatePSResource.md b/Docs/UpdatePSResource.md deleted file mode 100644 index dceff9cd7..000000000 --- a/Docs/UpdatePSResource.md +++ /dev/null @@ -1,217 +0,0 @@ -# Update-PSResource - -The `Update-PSResource` cmdlet combines the `Update-Module, Update-Script` cmdlets from V2. -It performs an upgraded installation of a package that is already installed based on the `-Name` parameter argument. -It does not return an object. -Other parameters allow the returned results to be further filtered. - -## Syntax - -### NameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Version ] [-Prerelease] [-Scope ] -[-Repository ] [-TrustRepository] [-Credential ] [-Quiet] -[-AcceptLicense] [-NoClobber] [-WhatIf] [-Confirm] [] -``` - -## Parameters - -### -Name - -Name of a resource or resources to find. -Accepts wild card characters. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -InputObject - -Specifies an object that is passed in via pipeline. -The object should be of type PSCustomObject. - -```yml -Type: PSCustomObject[] -Parameter Sets: InputObjectParameterSet -``` - -### -Version - -Specifies the version the resource is to be updated to. - -```yml -Type: string -Parameter Sets: NameParameterSet -``` - -### -Prerelease - -When specified, allows updating to a prerelease version. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -Repository - -Specifies one or more repository names to update from. -If not specified, will search in the highest priority repository. - -```yml -Type: string[] -Parameter Sets: NameParameterSet -``` - -### -Scope - -Specifies the scope of the resource to update. - -```yml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType -Parameter Sets: NameParameterSet -AllowedValues: 'CurrentUser','AllUsers' -``` - -### -TrustRepository - -Suppresses being prompted for untrusted sources. - -```yml -Type: SwitchParameter -Parameter Sets: NameParameterSet -``` - -### -Credential - -Optional credentials to be used when accessing a repository. - -```yml -Type: PSCredential -Parameter Sets: NameParameterSet -``` - -### -Quiet - -Suppresses progress information. - -```yml -Type: SwitchParameter -Parameter Sets: (All) -``` - -### -AcceptLicense - -For modules that require a license, AcceptLicense automatically accepts the license agreement during update. - -```yml -Type: SwitchParameter -Parameter Sets: (All) -``` - -### Outputs - -No output. - -## Notes - -Should a -PassThru parameter be added? - -## Tests - -Most update tests can be performed on a local repository. - -Some tests should be performed on remote repository (PoshTestGallery) to verify remote operation, but can be limited. - -### -Name param - -- Single name search -- Wildcard search -- Multiple name search -- Cancel search -- Errors: Not found (single name, wildcard, multiple name) -- Errors: Repository: Invalid name, connection error, etc - -### -Version param - -- Validate the resource is updated to the correct version -- Validate wild card (if supported), that the resource is updated to the correct version range -- Errors: Not found -- Errors: Invalid version string format - -### -Prerelease param - -- Validate prerelease version returned - -### -Repository param - -- All repository search -- Single repository search -- Multiple repository search -- Errors: Repository not found - -### -Credential param - -- Validate credential search -- Errors: Credential: Invalid - -### -Scope param - -- Validate only the resource from the proper scope gets updated - -### -TrustRepository param - -- Validate that prompt is suppresed - -### -Quiet param - -- Validate that progress information is suppressed - -### -AcceptLicense - -- Validate that modules which require license agreements are approved without a prompt - -## Work Items - -### Create cmdlet and parameter sets - -Create cmdlet class, parameters, and functional stubs -1 day - -### Implement package search helpers - -Create helper functions that support all search functions -Use existing code as starting point -4 days - -### Investigate V3 API wildcard support - -Look into how V3 APIs can be used to reduce what is returned from the server -7 days - -### Implement package filtering functions - -Create helper functions to provide filtering of search results -3 days - -### Investigate and implement local cache - -Write mini-design document on local caching strategy -Implement local cache -10 days - -### Create test support - -Create any test repositories and mocks for tests -4 days - -### Write cmdlet tests - -Create all functional tests to validate cmdlet -5 days - -### Write support function tests - -Create all needed tests to validate caching and search helpers -5 days diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index e04f58b50..c52afbc2b 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -69,7 +69,7 @@ Aliases: Required: False Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: True (ByValue) Accept wildcard characters: True ``` diff --git a/help/Get-PSResourceRepository.md b/help/Get-PSResourceRepository.md index a2aeff8ea..35c32e0f3 100644 --- a/help/Get-PSResourceRepository.md +++ b/help/Get-PSResourceRepository.md @@ -81,7 +81,7 @@ Aliases: Required: False Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: True (ByValue) Accept wildcard characters: True ``` diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index ddecc1257..8272e9fbc 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -16,7 +16,13 @@ Installs resources (modules and scripts) from a registered repository onto the m ``` Install-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] [] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-PassThru] [-WhatIf] [-Confirm] [] +``` + +### InputObjectParameterSet +``` +Install-PSResource [-InputObject ] [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -67,7 +73,7 @@ Aliases: Required: True Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` @@ -131,13 +137,13 @@ Optional credentials to be used when accessing a repository. ```yaml Type: System.Management.Automation.PSCredential -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` @@ -146,7 +152,7 @@ Specifies the scope under which a user has access. ```yaml Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Accepted values: CurrentUser, AllUsers @@ -162,7 +168,7 @@ Suppress prompts to trust repository. The prompt to trust repository only occurs ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -177,7 +183,7 @@ Writes over any previously installed resource version that already exists on the ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -192,7 +198,7 @@ Supresses installation progress bar. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -207,7 +213,7 @@ Specifies that the resource should accept any request to accept license. This wi ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -217,12 +223,72 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -NoClobber +Prevents installing a package that contains cmdlets that already exist on the machine. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SkipDependencyCheck +Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PassThru +Passes the resource installed to the console. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -InputObject +Used for pipeline input. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: cf Required: False @@ -238,7 +304,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: wi Required: False diff --git a/help/Publish-PSResource.md b/help/Publish-PSResource.md index 247919a52..8c74c9dce 100644 --- a/help/Publish-PSResource.md +++ b/help/Publish-PSResource.md @@ -12,16 +12,8 @@ Publishes a specified module from the local computer to PSResource repository. ## SYNTAX -### PathParameterSet ``` -Publish-PSResource [-APIKey ] [-Repository ] [-Path] - [-Credential ] [-SkipDependenciesCheck] - [-WhatIf] [-Confirm] [] -``` - -### PathLiteralParameterSet -``` -Publish-PSResource [-APIKey ] [-Repository ] -LiteralPath +Publish-PSResource [-APIKey ] [-Repository ] [-Path] [-DestinationPath] [-Credential ] [-SkipDependenciesCheck] [-WhatIf] [-Confirm] [] ``` @@ -54,7 +46,7 @@ Specifies the API key that you want to use to publish a resource to the online g ```yaml Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -69,7 +61,7 @@ Specifies the repository to publish to. ```yaml Type: System.String -Parameter Sets: PathParameterSet, PathLiteralParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -84,22 +76,22 @@ When specified, includes prerelease versions in search. ```yaml Type: System.String -Parameter Sets: PathParameterSet +Parameter Sets: (All) Aliases: Required: True Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` -### -LiteralPath -Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is used exactly as entered. No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. Single quotation marks tell PowerShell not to interpret any characters as escape sequences. +### -DestinationPath +Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. ```yaml Type: System.String -Parameter Sets: PathLiteralParameterSet +Parameter Sets: (All) Aliases: Required: True @@ -114,7 +106,7 @@ Specifies a user account that has rights to a specific repository (used for find ```yaml Type: System.Management.Automation.PSCredential -Parameter Sets: PathParameterSet, PathLiteralParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -129,7 +121,7 @@ Bypasses the default check that all dependencies are present on the repository w ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: PathParameterSet, PathLiteralParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -144,7 +136,7 @@ Prompts you for confirmation before running the cmdlet. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: PathParameterSet, PathLiteralParameterSet +Parameter Sets: (All) Aliases: cf Required: False @@ -160,7 +152,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: PathParameterSet, PathLiteralParameterSet +Parameter Sets: (All) Aliases: wi Required: False diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index a676178d2..bf90cb349 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -139,7 +139,7 @@ Specifies whether the repository should be trusted. ```yaml Type: SwitchParameter -Parameter Sets: NameParameterSet, PSGalleryParameterSet +Parameter Sets: (All) Aliases: Required: False diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 44d7f90a5..8e9f667af 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -12,10 +12,16 @@ Saves resources (modules and scripts) from a registered repository onto the mach ## SYNTAX +### NameParameterSet ``` Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-WhatIf] [-Confirm] - [] + [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] +``` + +### InputObjectParameterSet +``` +Save-PSResource [-InputObject] [-Credential ] [-AsNupkg] + [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -61,7 +67,7 @@ Aliases: Required: True Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` @@ -120,11 +126,26 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Credential +Optional credentials to be used when accessing a repository. + +```yaml +Type: System.Management.Automation.PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -AsNupkg Saves the resource as a zipped .nupkg file. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -139,7 +160,7 @@ Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has i ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -154,7 +175,7 @@ Specifies the path to save the resource to. ```yaml Type: System.String -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -164,12 +185,87 @@ Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` +### -TrustRepository +Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PassThru +Passes the resource saved to the console. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SkipDependencyCheck +Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Quiet +Supresses progress information. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -InputObject +Used for pipeline input. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: cf Required: False @@ -185,7 +281,7 @@ The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: wi Required: False diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index a775ad574..b65cabe1a 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -87,7 +87,7 @@ Aliases: Required: True Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` @@ -102,30 +102,30 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` -### -Repositories -Specifies a hashtable of repositories and is used to set multiple repositories at once. +### -Trusted +Specifies whether the repository should be trusted. ```yaml -Type: Hashtable[] -Parameter Sets: RepositoriesParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: NameParameterSet Aliases: -Required: True +Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName) +Accept pipeline input: False Accept wildcard characters: False ``` -### -Trusted -Specifies whether the repository should be trusted. +### -URL +Specifies the location of the repository to be set. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: String Parameter Sets: NameParameterSet Aliases: @@ -136,13 +136,13 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -URL -Specifies the location of the repository to be set. +### -PassThru +When specified, displays the succcessfully registered repository and its information ```yaml -Type: String -Parameter Sets: NameParameterSet -Aliases: +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: cf Required: False Position: Named diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index 9dbd89a48..6bfdef5b7 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -12,8 +12,14 @@ Uninstalls a resource (module or script) that has been installed on the machine ## SYNTAX +### NameParameterSet ``` -Uninstall-PSResource [-Name] [-Version ] [-Force] [-WhatIf] [] +Uninstall-PSResource [-Name] [-Version ] [-SkipDependencyCheck] [-WhatIf] [] +``` + +### InputObjectParameterSet +``` +Uninstall-PSResource [-InputObject] [-SkipDependencyCheck] [-WhatIf] [] ``` ## DESCRIPTION @@ -54,13 +60,13 @@ Name of a resource or resources that has been installed. Accepts wild card chara ```yaml Type: System.String[] -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: True Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: True (ByValue) Accept wildcard characters: True ``` @@ -79,12 +85,12 @@ Accept pipeline input: True Accept wildcard characters: False ``` -### -Force -Skips check to see if any modules have a dependency on the resource to be uninstalled. +### -SkipDependencyCheck +Skips check to see if other resources are dependent on the resource being uninstalled. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -94,13 +100,28 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -InputObject +Used for pipeline input. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: wi Required: False diff --git a/help/Unregister-PSResourceRepository.md b/help/Unregister-PSResourceRepository.md index 95f69b31f..764a5eb28 100644 --- a/help/Unregister-PSResourceRepository.md +++ b/help/Unregister-PSResourceRepository.md @@ -12,8 +12,9 @@ Un-registers a repository from the repository store. ## SYNTAX +### NameParameterSet ``` -Unregister-PSResourceRepository [-Name] [-WhatIf] [-Confirm] [] +Unregister-PSResourceRepository [-Name] [-PassThru][-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -68,6 +69,21 @@ Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` +### -PassThru +Passes the resource installed to the console. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Confirm Prompts you for confirmation before running the cmdlet. diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 77723f3b4..167a60673 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -15,7 +15,7 @@ Updates a package already installed on the user's machine. ### NameParameterSet (Default) ``` Update-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-WhatIf] [-Confirm] [] + [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -192,6 +192,51 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Force +When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PassThru +Passes the resource updated to the console. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SkipdependencyCheck +Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Confirm Prompts you for confirmation before running the cmdlet. diff --git a/src/code/GetPSResource.cs b/src/code/GetPSResource.cs index ab24dec78..facee6bf5 100644 --- a/src/code/GetPSResource.cs +++ b/src/code/GetPSResource.cs @@ -34,14 +34,14 @@ public sealed class GetPSResource : PSCmdlet /// /// Specifies the version of the resource to include to look for. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty()] public string Version { get; set; } /// /// Specifies the path to look in. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty()] public string Path { get; set; } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index f2fc2e8ca..75ea69220 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -53,49 +53,43 @@ class InstallPSResource : PSCmdlet /// /// Specifies a user account that has rights to find a resource from a specific repository. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public PSCredential Credential { get; set; } /// /// Specifies the scope of installation. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public ScopeType Scope { get; set; } /// /// Suppresses being prompted for untrusted sources. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public SwitchParameter TrustRepository { get; set; } /// /// Overwrites a previously installed resource with the same name and version. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public SwitchParameter Reinstall { get; set; } /// /// Suppresses progress information. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public SwitchParameter Quiet { get; set; } /// /// For modules that require a license, AcceptLicense automatically accepts the license agreement during installation. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public SwitchParameter AcceptLicense { get; set; } /// /// Prevents installing a package that contains cmdlets that already exist on the machine. /// - [Parameter(ParameterSetName = NameParameterSet)] + [Parameter] public SwitchParameter NoClobber { get; set; } /// @@ -108,8 +102,7 @@ class InstallPSResource : PSCmdlet /// /// Passes the resource installed to the console. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public SwitchParameter PassThru { get; set; } /// diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 1797eccd8..e46487cec 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -32,14 +32,14 @@ public sealed class PublishPSResource : PSCmdlet /// /// Specifies the API key that you want to use to publish a module to the online gallery. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public string ApiKey { get; set; } /// /// Specifies the repository to publish to. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] [ArgumentCompleter(typeof(RepositoryNameCompleter))] public string Repository { get; set; } @@ -48,7 +48,7 @@ public sealed class PublishPSResource : PSCmdlet /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public string Path { @@ -75,7 +75,7 @@ public string Path /// Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the /// -Repository parameter to publish to a repository and also save the exact same package to the local file system. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public string DestinationPath { @@ -111,21 +111,21 @@ public string DestinationPath /// /// Specifies a user account that has rights to a specific repository (used for finding dependencies). /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public PSCredential Credential { get; set; } /// /// Bypasses the default check that all dependencies are present. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public SwitchParameter SkipDependenciesCheck { get; set; } /// /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public Uri Proxy { set @@ -142,7 +142,7 @@ public Uri Proxy { /// /// Specifies a user account that has permission to use the proxy server that is specified by the Proxy parameter. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] public PSCredential ProxyCredential { set diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 388d1a091..e5aa02066 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -63,27 +63,25 @@ public sealed class SavePSResource : PSCmdlet /// /// Specifies a user account that has rights to save a resource from a specific repository. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public PSCredential Credential { get; set; } /// /// Saves the resource as a .nupkg /// - [Parameter()] + [Parameter] public SwitchParameter AsNupkg { get; set; } /// /// Saves the metadata XML file with the resource /// - [Parameter()] + [Parameter] public SwitchParameter IncludeXML { get; set; } /// /// The destination where the resource is to be installed. Works for all resource types. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] [ValidateNotNullOrEmpty] public string Path { @@ -110,14 +108,13 @@ public string Path /// /// Suppresses being prompted for untrusted sources. /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + [Parameter] public SwitchParameter TrustRepository { get; set; } /// /// Passes the resource saved to the console. /// - [Parameter()] + [Parameter] public SwitchParameter PassThru { get; set; } /// diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index dc947e084..abf2c6034 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -100,7 +100,7 @@ public sealed class UpdatePSResource : PSCmdlet /// /// Passes the resource updated to the console. /// - [Parameter()] + [Parameter] public SwitchParameter PassThru { get; set; } /// From d4e02626a8420b82bb1a2c3ccda6038a4cad3933 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 7 Dec 2021 12:47:01 -0500 Subject: [PATCH 114/276] Install should not silently fail (#554) install should not fail silently --- src/code/InstallHelper.cs | 58 ++++++++++++++++++++++---------- src/code/InstallPSResource.cs | 1 + src/code/SavePSResource.cs | 2 +- test/InstallPSResource.Tests.ps1 | 10 ++++-- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index b9eafa4d4..7ed9d1916 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -50,6 +50,7 @@ internal class InstallHelper : PSCmdlet private bool _noClobber; private bool _savePkg; List _pathsToSearch; + List _pkgNamesToInstall; #endregion @@ -111,6 +112,7 @@ public List InstallPackages( // Create list of installation paths to search. _pathsToSearch = new List(); + _pkgNamesToInstall = names.ToList(); // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations @@ -126,7 +128,6 @@ public List InstallPackages( // Go through the repositories and see which is the first repository to have the pkg version available return ProcessRepositories( - packageNames: names, repository: repository, trustRepository: _trustRepository, credential: _credential, @@ -139,23 +140,22 @@ public List InstallPackages( // This method calls iterates through repositories (by priority order) to search for the pkgs to install private List ProcessRepositories( - string[] packageNames, string[] repository, bool trustRepository, PSCredential credential, bool skipDependencyCheck) { var listOfRepositories = RepositorySettings.Read(repository, out string[] _); - List pkgNamesToInstall = packageNames.ToList(); var yesToAll = false; var noToAll = false; var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); List allPkgsInstalled = new List(); + foreach (var repo in listOfRepositories) { // If no more packages to install, then return - if (!pkgNamesToInstall.Any()) return allPkgsInstalled; + if (!_pkgNamesToInstall.Any()) return allPkgsInstalled; string repoName = repo.Name; _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); @@ -187,7 +187,7 @@ private List ProcessRepositories( // Finds parent packages and dependencies IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( - name: pkgNamesToInstall.ToArray(), + name: _pkgNamesToInstall.ToArray(), type: ResourceType.None, version: _versionRange != null ? _versionRange.OriginalString : null, prerelease: _prerelease, @@ -216,7 +216,6 @@ private List ProcessRepositories( // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) if (!_reinstall) { - // Removes all of the names that are already installed from the list of names to search for pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); } @@ -227,19 +226,29 @@ private List ProcessRepositories( List pkgsInstalled = InstallPackage( pkgsFromRepoToInstall, - pkgNamesToInstall, repo.Url.AbsoluteUri, credential, isLocalRepo); foreach (PSResourceInfo pkg in pkgsInstalled) { - pkgNamesToInstall.Remove(pkg.Name); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); } allPkgsInstalled.AddRange(pkgsInstalled); } + // At this only package names left were those which could not be found in registered repositories + foreach (string pkgName in _pkgNamesToInstall) + { + var message = String.Format("Package '{0}' with requested version range {1} could not be installed as it was not found in any registered repositories", + pkgName, + _versionRange.ToString()); + var ex = new ArgumentException(message); + var ResourceNotFoundError = new ErrorRecord(ex, "ResourceNotFoundError", ErrorCategory.ObjectNotFound, null); + _cmdletPassedIn.WriteError(ResourceNotFoundError); + } + return allPkgsInstalled; } @@ -286,6 +295,7 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); } return filteredPackages.Values.ToArray(); @@ -293,7 +303,6 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable InstallPackage( IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) - List pkgNamesToInstall, // those requested by the user to be installed string repoUrl, PSCredential credential, bool isLocalRepo) @@ -333,7 +342,7 @@ private List InstallPackage( string activity = ""; string statusDescription = ""; - if (pkgNamesToInstall.ToList().Contains(pkg.Name, StringComparer.InvariantCultureIgnoreCase)) + if (_pkgNamesToInstall.Contains(pkg.Name, StringComparer.InvariantCultureIgnoreCase)) { // Installing parent package (one whose name was passed in to install) activityId = 0; @@ -364,10 +373,16 @@ private List InstallPackage( if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) { - _cmdletPassedIn.WriteVerbose(string.Format("Error parsing package '{0}' version '{1}' into a NuGetVersion", - pkg.Name, pkg.Version.ToString())); + var message = String.Format("{0} package could not be installed with error: could not parse package '{0}' version '{1} into a NuGetVersion", + pkg.Name, + pkg.Version.ToString()); + var ex = new ArgumentException(message); + var packageIdentityVersionParseError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); + _cmdletPassedIn.WriteError(packageIdentityVersionParseError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); continue; } + var pkgIdentity = new PackageIdentity(pkg.Name, pkgVersion); var cacheContext = new SourceCacheContext(); @@ -492,11 +507,12 @@ private List InstallPackage( var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); if (!File.Exists(moduleManifest)) { - var message = String.Format("Module manifest file: {0} does not exist. This is not a valid PowerShell module.", moduleManifest); + var message = String.Format("{0} package could not be installed with error: Module manifest file: {1} does not exist. This is not a valid PowerShell module.", pkgIdentity.Id, moduleManifest); var ex = new ArgumentException(message); var psdataFileDoesNotExistError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); _cmdletPassedIn.WriteError(psdataFileDoesNotExistError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); continue; } @@ -553,6 +569,7 @@ private List InstallPackage( "InstallPackageFailed", ErrorCategory.InvalidOperation, _cmdletPassedIn)); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); } finally { @@ -611,11 +628,12 @@ private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string t if (!File.Exists(LicenseFilePath)) { - var exMessage = "License.txt not Found. License.txt must be provided when user license acceptance is required."; + var exMessage = String.Format("{0} package could not be installed with error: License.txt not found. License.txt must be provided when user license acceptance is required.", p.Name); var ex = new ArgumentException(exMessage); var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); _cmdletPassedIn.WriteError(acceptLicenseError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)); success = false; } @@ -638,11 +656,12 @@ private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string t // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install if (!_acceptLicense) { - var message = $"License Acceptance is required for module '{p.Name}'. Please specify '-AcceptLicense' to perform this operation."; + var message = String.Format("{0} package could not be installed with error: License Acceptance is required for module '{0}'. Please specify '-AcceptLicense' to perform this operation.", p.Name); var ex = new ArgumentException(message); var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); _cmdletPassedIn.WriteError(acceptLicenseError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)); success = false; } } @@ -687,13 +706,14 @@ private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) duplicateCmdlets.AddRange(duplicateCmds); var errMessage = string.Format( - "The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", + "{1} package could not be installed with error: The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", String.Join(", ", duplicateCmdlets), pkgName); var ex = new ArgumentException(errMessage); var noClobberError = new ErrorRecord(ex, "CommandAlreadyExists", ErrorCategory.ResourceExists, null); _cmdletPassedIn.WriteError(noClobberError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)); foundClobber = true; return foundClobber; @@ -716,10 +736,12 @@ private void CreateMetadataXMLFile(string dirNameVersion, string installPath, PS // Write all metadata into metadataXMLPath if (!pkg.TryWrite(metadataXMLPath, out string error)) { - var message = string.Format("Error parsing metadata into XML: '{0}'", error); + var message = string.Format("{0} package could not be installed with error: Error parsing metadata into XML: '{1}'", pkg.Name, error); var ex = new ArgumentException(message); var ErrorParsingMetadata = new ErrorRecord(ex, "ErrorParsingMetadata", ErrorCategory.ParserError, null); - WriteError(ErrorParsingMetadata); + + _cmdletPassedIn.WriteError(ErrorParsingMetadata); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); } } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 75ea69220..88fbde63d 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -5,6 +5,7 @@ using NuGet.Versioning; using System; using System.Collections.Generic; +using System.Linq; using System.Management.Automation; using Dbg = System.Diagnostics.Debug; diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index e5aa02066..97dd07ac9 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -260,7 +260,7 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p includeXML: IncludeXML, skipDependencyCheck: SkipDependencyCheck, savePkg: true, - pathsToInstallPkg: new List { _path } ); + pathsToInstallPkg: new List { _path }); if (PassThru) { diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index b0812c636..dad59071b 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -36,7 +36,7 @@ Describe 'Test Install-PSResource for Module' { } It "Install specific module resource by name" { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName + Install-PSResource -Name "TestModule" -Repository $TestGalleryName $pkg = Get-Module "TestModule" -ListAvailable $pkg.Name | Should -Be "TestModule" $pkg.Version | Should -Be "1.3.0" @@ -57,9 +57,11 @@ Describe 'Test Install-PSResource for Module' { } It "Should not install resource given nonexistant name" { - Install-PSResource -Name NonExistantModule -Repository $TestGalleryName + Install-PSResource -Name "NonExistantModule" -Repository $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue $pkg = Get-Module "NonExistantModule" -ListAvailable $pkg.Name | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } # Do some version testing, but Find-PSResource should be doing thorough testing @@ -97,7 +99,9 @@ Describe 'Test Install-PSResource for Module' { ) { param($Version, $Description) - Install-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName + Install-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + $res = Get-Module "TestModule" -ListAvailable $res | Should -BeNullOrEmpty } From 421d77a4d9bc49fcd72e81019837bd29f5cf06e8 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 8 Dec 2021 17:11:18 -0500 Subject: [PATCH 115/276] Tests and error handling (#564) clean up tests and add tests for certain errors --- src/code/PublishPSResource.cs | 3 +- src/code/UnregisterPSResourceRepository.cs | 10 ++ test/FindPSResource.Tests.ps1 | 8 +- test/GetPSResourceRepository.Tests.ps1 | 33 +++--- test/RegisterPSResourceRepository.Tests.ps1 | 88 +++++++-------- test/SavePSResource.Tests.ps1 | 68 ++++++------ test/SetPSResourceRepository.Tests.ps1 | 103 ++++++++++-------- test/UninstallPSResource.Tests.ps1 | 4 +- test/UnregisterPSResourceRepository.Tests.ps1 | 12 +- test/UpdatePSResource.Tests.ps1 | 91 ++++++++-------- 10 files changed, 228 insertions(+), 192 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index e46487cec..8428020a8 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -181,8 +181,7 @@ protected override void ProcessRecord() var pkgFileOrDir = new DirectoryInfo(_path); bool isScript = _path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase); - // TODO: think about including the repository the resource is being published to - if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine.", _path))) + if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine", _path))) { WriteVerbose("ShouldProcess is set to false."); return; diff --git a/src/code/UnregisterPSResourceRepository.cs b/src/code/UnregisterPSResourceRepository.cs index 46b209e3f..c18257007 100644 --- a/src/code/UnregisterPSResourceRepository.cs +++ b/src/code/UnregisterPSResourceRepository.cs @@ -45,6 +45,16 @@ protected override void BeginProcessing() } protected override void ProcessRecord() { + Name = Utils.ProcessNameWildcards(Name, out string[] _, out bool nameContainsWildcard); + if (nameContainsWildcard) + { + var message = String.Format("Name: '{0}, cannot contain wildcards", String.Join(", ", Name)); + var ex = new ArgumentException(message); + var NameContainsWildCardError = new ErrorRecord(ex, "nameContainsWildCardError", ErrorCategory.ReadError, null); + WriteError(NameContainsWildCardError); + return; + } + string nameArrayAsString = string.Join(", ", Name); WriteVerbose(String.Format("removing repository {0}. Calling Remove() API now", nameArrayAsString)); if (!ShouldProcess(nameArrayAsString, "Unregister repositories from repository store")) diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index f539a67d6..7eb777767 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -72,7 +72,7 @@ Describe 'Test Find-PSResource for Module' { $foundTestScript = $True } - if(-not [string]::IsNullOrEmpty($item.PrereleaseLabel)) + if($item.IsPrerelease) { $foundPreview = $True } @@ -101,7 +101,7 @@ Describe 'Test Find-PSResource for Module' { $foundTestScript = $True } - if(-not [string]::IsNullOrEmpty($item.PrereleaseLabel)) + if($item.IsPrerelease) { $foundPreview = $True } @@ -210,10 +210,10 @@ Describe 'Test Find-PSResource for Module' { It "find resource with latest (including prerelease) version given Prerelease parameter" { # test_module resource's latest version is a prerelease version, before that it has a non-prerelease version - $res = Find-PSResource -Name "test_module" -Repository $TestGalleryName + $res = Find-PSResource -Name $testModuleName -Repository $TestGalleryName $res.Version | Should -Be "5.0.0.0" - $resPrerelease = Find-PSResource -Name "test_module" -Prerelease -Repository $TestGalleryName + $resPrerelease = Find-PSResource -Name $testModuleName -Prerelease -Repository $TestGalleryName $resPrerelease.Version | Should -Be "5.2.5.0" $resPrerelease.PrereleaseLabel | Should -Be "alpha001" } diff --git a/test/GetPSResourceRepository.Tests.ps1 b/test/GetPSResourceRepository.Tests.ps1 index aa9d4773c..6d5e2e8f9 100644 --- a/test/GetPSResourceRepository.Tests.ps1 +++ b/test/GetPSResourceRepository.Tests.ps1 @@ -5,6 +5,9 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test Register-PSResourceRepository" { BeforeEach { + $TestRepoName1 = "testRepository" + $TestRepoName2 = "testRepository2" + $TestRepoName3 = "testRepository3" Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" @@ -22,16 +25,16 @@ Describe "Test Register-PSResourceRepository" { } It "get single already registered repo" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - $res = Get-PSResourceRepository -Name "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + $res = Get-PSResourceRepository -Name $TestRepoName1 $res | Should -Not -BeNullOrEmpty - $res.Name | Should -Be "testRepository" + $res.Name | Should -Be $TestRepoName1 } It "get all repositories matching single wildcard name" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path - Register-PSResourceRepository -Name "testRepository3" -URL $tmpDir3Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName3 -URL $tmpDir3Path $res = Get-PSResourceRepository -Name "testReposit*" foreach ($entry in $res) { $entry.Name | Should -Match "testReposit" @@ -39,8 +42,8 @@ Describe "Test Register-PSResourceRepository" { } It "get all repositories matching multiple wildcard names" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path Register-PSResourceRepository -Name "MyGallery" -URL $tmpDir3Path $res = Get-PSResourceRepository -Name "testReposit*","*Gallery" @@ -50,12 +53,12 @@ Describe "Test Register-PSResourceRepository" { } It "get all repositories matching multiple valid names provided" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path Register-PSResourceRepository -Name "MyGallery" -URL $tmpDir2Path - $res = Get-PSResourceRepository -Name "testRepository","MyGallery" + $res = Get-PSResourceRepository -Name $TestRepoName1,"MyGallery" foreach ($entry in $res) { - $entry.Name | Should -BeIn "testRepository","MyGallery" + $entry.Name | Should -BeIn $TestRepoName1,"MyGallery" } } @@ -70,16 +73,16 @@ Describe "Test Register-PSResourceRepository" { It "given invalid and valid Names, get valid ones and write error for non valid ones" { $nonRegisteredRepoName = "nonRegisteredRepository" - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path - $res = Get-PSResourceRepository -Name "testRepository",$nonRegisteredRepoName,"testRepository2" -ErrorVariable err -ErrorAction SilentlyContinue + $res = Get-PSResourceRepository -Name $TestRepoName1,$nonRegisteredRepoName,$TestRepoName2 -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" # should have successfully got the other valid/registered repositories with no error foreach ($entry in $res) { - $entry.Name | Should -BeIn "testRepository","testRepository2" + $entry.Name | Should -BeIn $TestRepoName1,$TestRepoName2 } } diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index c8c1a659f..712204ec9 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -7,14 +7,16 @@ Describe "Test Register-PSResourceRepository" { BeforeEach { $PSGalleryName = Get-PSGalleryName $PSGalleryURL = Get-PSGalleryLocation + $TestRepoName1 = "testRepository" + $TestRepoName2 = "testRepository2" + $TestRepoName3 = "testRepository3" + $relativeCurrentPath = Get-Location Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) Get-NewTestDirs($tmpDirPaths) - - $relativeCurrentPath = Get-Location } AfterEach { Get-RevertPSResourceRepositoryFile @@ -26,24 +28,24 @@ Describe "Test Register-PSResourceRepository" { } It "register repository given Name, URL (bare minimum for NameParmaterSet)" { - $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -PassThru - $res.Name | Should -Be "testRepository" + $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -PassThru + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } It "register repository with Name, URL, Trusted (NameParameterSet)" { - $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -Trusted -PassThru - $res.Name | Should -Be "testRepository" + $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -PassThru + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 50 } It "register repository given Name, URL, Trusted, Priority (NameParameterSet)" { - $res = Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path -Trusted -Priority 20 -PassThru - $res.Name | Should -Be "testRepository" + $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -PassThru + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 20 @@ -77,23 +79,23 @@ Describe "Test Register-PSResourceRepository" { } It "register repositories with Repositories parameter, all name parameter style repositories (RepositoriesParameterSet)" { - $hashtable1 = @{Name = "testRepository"; URL = $tmpDir1Path} - $hashtable2 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} - $hashtable3 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir1Path} + $hashtable2 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} + $hashtable3 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3 Register-PSResourceRepository -Repositories $arrayOfHashtables - $res = Get-PSResourceRepository -Name "testRepository" + $res = Get-PSResourceRepository -Name $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False $res.Priority | Should -Be 50 - $res2 = Get-PSResourceRepository -Name "testRepository2" + $res2 = Get-PSResourceRepository -Name $TestRepoName2 $res2.URL.LocalPath | Should -Contain $tmpDir2Path $res2.Trusted | Should -Be True $res2.Priority | Should -Be 50 - $res3 = Get-PSResourceRepository -Name "testRepository3" + $res3 = Get-PSResourceRepository -Name $TestRepoName3 $res3.URL.LocalPath | Should -Contain $tmpDir3Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 20 @@ -112,9 +114,9 @@ Describe "Test Register-PSResourceRepository" { It "register repositories with Repositories parameter, name and psgallery parameter styles (RepositoriesParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName $hashtable1 = @{PSGallery = $True} - $hashtable2 = @{Name = "testRepository"; URL = $tmpDir1Path} - $hashtable3 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} - $hashtable4 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $hashtable2 = @{Name = $TestRepoName1; URL = $tmpDir1Path} + $hashtable3 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} + $hashtable4 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 Register-PSResourceRepository -Repositories $arrayOfHashtables @@ -124,24 +126,24 @@ Describe "Test Register-PSResourceRepository" { $res1.Trusted | Should -Be False $res1.Priority | Should -Be 50 - $res2 = Get-PSResourceRepository -Name "testRepository" + $res2 = Get-PSResourceRepository -Name $TestRepoName1 $res2.URL.LocalPath | Should -Contain $tmpDir1Path $res2.Trusted | Should -Be False $res2.Priority | Should -Be 50 - $res3 = Get-PSResourceRepository -Name "testRepository2" + $res3 = Get-PSResourceRepository -Name $TestRepoName2 $res3.URL.LocalPath | Should -Contain $tmpDir2Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 50 - $res4 = Get-PSResourceRepository -Name "testRepository3" + $res4 = Get-PSResourceRepository -Name $TestRepoName3 $res4.URL.LocalPath | Should -Contain $tmpDir3Path $res4.Trusted | Should -Be True $res4.Priority | Should -Be 20 } It "not register repository when Name is provided but URL is not" { - {Register-PSResourceRepository -Name "testRepository" -URL "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + {Register-PSResourceRepository -Name $TestRepoName1 -URL "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } It "not register repository when Name is empty but URL is provided" { @@ -172,24 +174,24 @@ Describe "Test Register-PSResourceRepository" { It "not register incorrectly formatted PSGallery type repo among correct ones when incorrect type is " -TestCases $testCases { param($Type, $IncorrectHashTable) - $correctHashtable1 = @{Name = "testRepository"; URL = $tmpDir1Path} - $correctHashtable2 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} - $correctHashtable3 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable1 = @{Name = $TestRepoName1; URL = $tmpDir1Path} + $correctHashtable2 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} + $correctHashtable3 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 - Unregister-PSResourceRepository -Name "PSGallery" + Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUrlForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" - $res = Get-PSResourceRepository -Name "testRepository" - $res.Name | Should -Be "testRepository" + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 - $res2 = Get-PSResourceRepository -Name "testRepository2" - $res2.Name | Should -Be "testRepository2" + $res2 = Get-PSResourceRepository -Name $TestRepoName2 + $res2.Name | Should -Be $TestRepoName2 - $res3 = Get-PSResourceRepository -Name "testRepository3" - $res3.Name | Should -Be "testRepository3" + $res3 = Get-PSResourceRepository -Name $TestRepoName3 + $res3.Name | Should -Be $TestRepoName3 } $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, @@ -200,32 +202,32 @@ Describe "Test Register-PSResourceRepository" { It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { param($Type, $IncorrectHashTable, $ErrorId) - $correctHashtable1 = @{Name = "testRepository2"; URL = $tmpDir2Path; Trusted = $True} - $correctHashtable2 = @{Name = "testRepository3"; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable1 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} $correctHashtable3 = @{PSGallery = $True; Priority = 30}; $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 - Unregister-PSResourceRepository -Name "PSGallery" + Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly $ErrorId - $res = Get-PSResourceRepository -Name "testRepository2" - $res.Name | Should -Be "testRepository2" + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 - $res2 = Get-PSResourceRepository -Name "testRepository3" - $res2.Name | Should -Be "testRepository3" + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 - $res3 = Get-PSResourceRepository -Name "PSGallery" - $res3.Name | Should -Be "PSGallery" + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName $res3.Priority | Should -Be 30 } It "should register repository with relative location provided as URL" { - Register-PSResourceRepository -Name "testRepository" -URL "./" - $res = Get-PSResourceRepository -Name "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL "./" + $res = Get-PSResourceRepository -Name $TestRepoName1 - $res.Name | Should -Be "testRepository" + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $relativeCurrentPath $res.Trusted | Should -Be False $res.Priority | Should -Be 50 diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index b21f27d90..66858ce6d 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -10,6 +10,8 @@ Describe 'Test Save-PSResource for PSResources' { $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "test_module" + $testModuleName2 = "TestModule" + $testScriptName = "TestTestScript" Get-NewPSResourceRepositoryFile Register-LocalRepos @@ -27,14 +29,14 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save specific module resource by name" { - Save-PSResource -Name "TestModule" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 } It "Save specific script resource by name" { - Save-PSResource -Name "TestTestScript" -Repository $TestGalleryName -Path $SaveDir + Save-PSResource -Name $testScriptName -Repository $TestGalleryName -Path $SaveDir $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestTestScript.ps1" $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 @@ -63,32 +65,32 @@ Describe 'Test Save-PSResource for PSResources' { # Do some version testing, but Find-PSResource should be doing thorough testing It "Should save resource given name and exact version" { - Save-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.2.0" } It "Should save resource given name and exact version with bracket syntax" { - Save-PSResource -Name "TestModule" -Version "[1.2.0]" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version "[1.2.0]" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.2.0" } It "Should save resource given name and exact range inclusive [1.0.0, 1.1.1]" { - Save-PSResource -Name "TestModule" -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.1.1" } It "Should save resource given name and exact range exclusive (1.0.0, 1.1.1)" { - Save-PSResource -Name "TestModule" -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.1" @@ -100,14 +102,14 @@ Describe 'Test Save-PSResource for PSResources' { ) { param($Version, $Description) - Save-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version $Version -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -BeNullOrEmpty } It "Save resource when given Name, Version '*', should install the latest version" { - Save-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version "*" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.3.0" @@ -137,8 +139,8 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save resource via InputObject by piping from Find-PSresource" { - Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Find-PSResource -Name $testModuleName2 -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.3.0" @@ -147,8 +149,8 @@ Describe 'Test Save-PSResource for PSResources' { It "Save resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { try { Set-PSResourceRepository PoshTestGallery -Trusted:$false - Save-PSResource -Name "TestModule" -Repository $TestGalleryName -TrustRepository -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -TrustRepository -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.3.0" @@ -176,14 +178,14 @@ Describe 'Test Save-PSResource for PSResources' { Set-PSResourceRepository "psgettestlocal2" -Trusted:$True Save-PSResource -Name "TestModule" -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } It "Save PSResourceInfo object piped in" { - Find-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Find-PSResource -Name $testModuleName2 -Version "1.1.0.0" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } @@ -196,7 +198,7 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save module as a nupkg" { - Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -AsNupkg write-host $SaveDir write-host $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testmodule.1.3.0.nupkg" @@ -204,14 +206,14 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save script as a nupkg" { - Save-PSResource -Name "TestTestScript" -Version "1.3.1" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + Save-PSResource -Name $testScriptName -Version "1.3.1" -Repository $TestGalleryName -Path $SaveDir -AsNupkg $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testtestscript.1.3.1.nupkg" $pkgDir | Should -Not -BeNullOrEmpty } It "Save module and include XML metadata file" { - Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -IncludeXML - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -IncludeXML + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName $pkgDirVersion.Name | Should -Be "1.3.0" @@ -220,15 +222,15 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save module using -PassThru" { - $res = Save-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru - $res.Name | Should -Be "TestModule" + $res = Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru + $res.Name | Should -Be $testModuleName2 $res.Version | Should -Be "1.3.0.0" } <# # Tests should not write to module directory It "Save specific module resource by name if no -Path param is specifed" { - Save-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkgDir = Get-ChildItem -Path . | Where-Object Name -eq "TestModule" + Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName + $pkgDir = Get-ChildItem -Path . | Where-Object Name -eq $testModuleName2 $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 @@ -244,10 +246,10 @@ Describe 'Test Save-PSResource for PSResources' { It "Install resource should prompt 'trust repository' if repository is not trusted" { Set-PSResourceRepository PoshTestGallery -Trusted:$false - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -confirm:$false + Install-PSResource -Name $testModuleName2 -Repository $TestGalleryName -confirm:$false - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" + $pkg = Get-Module $testModuleName2 -ListAvailable + $pkg.Name | Should -Be $testModuleName2 Set-PSResourceRepository PoshTestGallery -Trusted } diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index 30c0d3ecc..74f107ecc 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -7,14 +7,15 @@ Describe "Test Set-PSResourceRepository" { BeforeEach { $PSGalleryName = Get-PSGalleryName $PSGalleryURL = Get-PSGalleryLocation + $TestRepoName1 = "testRepository" + $TestRepoName2 = "testRepository2" + $relativeCurrentPath = Get-Location Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) Get-NewTestDirs($tmpDirPaths) - - $relativeCurrentPath = Get-Location } AfterEach { Get-RevertPSResourceRepositoryFile @@ -26,38 +27,38 @@ Describe "Test Set-PSResourceRepository" { } It "set repository given Name and URL parameters" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Set-PSResourceRepository -Name "testRepository" -URL $tmpDir2Path - $res = Get-PSResourceRepository -Name "testRepository" - $res.Name | Should -Be "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir2Path + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False } It "set repository given Name and Priority parameters" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Set-PSResourceRepository -Name "testRepository" -Priority 25 - $res = Get-PSResourceRepository -Name "testRepository" - $res.Name | Should -Be "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -Priority 25 + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False } It "set repository given Name and Trusted parameters" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Set-PSResourceRepository -Name "testRepository" -Trusted - $res = Get-PSResourceRepository -Name "testRepository" - $res.Name | Should -Be "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -Trusted + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be True } It "not set repository and write error given just Name parameter" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - {Set-PSResourceRepository -Name "testRepository" -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + {Set-PSResourceRepository -Name $TestRepoName1 -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } $testCases = @{Type = "contains *"; Name = "test*Repository"; ErrorId = "ErrorInNameParameterSet"}, @@ -67,7 +68,7 @@ Describe "Test Set-PSResourceRepository" { It "not set repository and throw error given Name (NameParameterSet)" -TestCases $testCases { param($Type, $Name) - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path {Set-PSResourceRepository -Name $Name -Priority 25 -ErrorAction Stop} | Should -Throw -ErrorId "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } @@ -77,11 +78,11 @@ Describe "Test Set-PSResourceRepository" { It "not set repository and write error given Name (RepositoriesParameterSet)" -TestCases $testCases2 { param($Type, $Name, $ErrorId) - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path - $hashtable1 = @{Name = "testRepository"; URL = $tmpDir3Path} - $hashtable2 = @{Name = "testRepository2"; Priority = 25} + $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir3Path} + $hashtable2 = @{Name = $TestRepoName2; Priority = 25} $incorrectHashTable = @{Name = $Name; Trusted = $True} $arrayOfHashtables = $hashtable1, $incorrectHashTable, $hashtable2 @@ -89,35 +90,35 @@ Describe "Test Set-PSResourceRepository" { $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" - $res = Get-PSResourceRepository -Name "testRepository" + $res = Get-PSResourceRepository -Name $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir3Path $res.Trusted | Should -Be False - $res2 = Get-PSResourceRepository -Name "testRepository2" + $res2 = Get-PSResourceRepository -Name $TestRepoName2 $res2.Priority | Should -Be 25 $res2.Trusted | Should -Be False } It "set repositories with Repositories parameter" { - Unregister-PSResourceRepository -Name "PSGallery" - Register-PSResourceRepository -Name "testRepository1" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path Register-PSResourceRepository -PSGallery - $hashtable1 = @{Name = "testRepository1"; URL = $tmpDir2Path}; - $hashtable2 = @{Name = "testRepository2"; Priority = 25}; - $hashtable3 = @{Name = "PSGallery"; Trusted = $True}; + $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir2Path}; + $hashtable2 = @{Name = $TestRepoName2; Priority = 25}; + $hashtable3 = @{Name = $PSGalleryName; Trusted = $True}; $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3 Set-PSResourceRepository -Repositories $arrayOfHashtables - $res = Get-PSResourceRepository -Name "testRepository1" - $res.Name | Should -Be "testRepository1" + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False - $res2 = Get-PSResourceRepository -Name "testRepository2" - $res2.Name | Should -Be "testRepository2" + $res2 = Get-PSResourceRepository -Name $TestRepoName2 + $res2.Name | Should -Be $TestRepoName2 $res2.URL.LocalPath | Should -Contain $tmpDir2Path $res2.Priority | Should -Be 25 $res2.Trusted | Should -Be False @@ -130,45 +131,53 @@ Describe "Test Set-PSResourceRepository" { } It "not set and throw error for trying to set PSGallery URL (NameParameterSet)" { - Unregister-PSResourceRepository -Name "PSGallery" + Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -PSGallery - {Set-PSResourceRepository -Name "PSGallery" -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + {Set-PSResourceRepository -Name $PSGalleryName -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } It "not set repository and throw error for trying to set PSGallery URL (RepositoriesParameterSet)" { - Unregister-PSResourceRepository -Name "PSGallery" + Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -PSGallery - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - $hashtable1 = @{Name = "PSGallery"; URL = $tmpDir1Path} - $hashtable2 = @{Name = "testRepository"; Priority = 25} + $hashtable1 = @{Name = $PSGalleryName; URL = $tmpDir1Path} + $hashtable2 = @{Name = $TestRepoName1; Priority = 25} $arrayOfHashtables = $hashtable1, $hashtable2 Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" - $res = Get-PSResourceRepository -Name "testRepository" + $res = Get-PSResourceRepository -Name $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False } It "should set repository with relative URL provided" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Set-PSResourceRepository -Name "testRepository" -URL $relativeCurrentPath - $res = Get-PSResourceRepository -Name "testRepository" - $res.Name | Should -Be "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -URL $relativeCurrentPath + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $relativeCurrentPath $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } + It "should set repository with local file share NuGet based Uri" { + Register-PSResourceRepository -Name "localFileShareTestRepo" -URL $tmpDir1Path + Set-PSResourceRepository -Name "localFileShareTestRepo" -URL "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + $res = Get-PSResourceRepository -Name "localFileShareTestRepo" + $res.Name | Should -Be "localFileShareTestRepo" + $res.URL.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + } + It "set repository and see updated repository with -PassThru" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - $res = Set-PSResourceRepository -Name "testRepository" -URL $tmpDir2Path -PassThru - $res.Name | Should -Be "testRepository" + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + $res = Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir2Path -PassThru + $res.Name | Should -Be $TestRepoName1 $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 94acd9947..3c4bcdc66 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -175,7 +175,7 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Do not Uninstall module that is a dependency for another module" { - $null = Install-PSResource "test_module" -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue Uninstall-PSResource -Name "RequiredModule1" -ErrorVariable ev -ErrorAction SilentlyContinue @@ -186,7 +186,7 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall module that is a dependency for another module using -SkipDependencyCheck" { - $null = Install-PSResource "test_module" -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue Uninstall-PSResource -Name "RequiredModule1" -SkipDependencyCheck diff --git a/test/UnregisterPSResourceRepository.Tests.ps1 b/test/UnregisterPSResourceRepository.Tests.ps1 index 9cb30db2b..5b9cc9fd0 100644 --- a/test/UnregisterPSResourceRepository.Tests.ps1 +++ b/test/UnregisterPSResourceRepository.Tests.ps1 @@ -46,6 +46,14 @@ Describe "Test Register-PSResourceRepository" { } + It "not register when -Name contains wildcard" { + Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Unregister-PSResourceRepository -Name "testRepository*" -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "nameContainsWildCardError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" + } + It "when multiple repo Names provided, if one name isn't valid unregister the rest and write error message" { $nonRegisteredRepoName = "nonRegisteredRepository" Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path @@ -66,7 +74,9 @@ Describe "Test Register-PSResourceRepository" { $res = Unregister-PSResourceRepository -Name $TestGalleryName -PassThru $res.Name | Should -Be $TestGalleryName $res.Url | Should -Be $TestGalleryURL - $res = Get-PSResourceRepository -Name $TestGalleryName + $res = Get-PSResourceRepository -Name $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue $res | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" } } diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 29549d3db..c2449a276 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -9,6 +9,7 @@ Describe 'Test Update-PSResource' { BeforeAll{ $TestGalleryName = Get-PoshTestGalleryName $NuGetGalleryName = Get-NuGetGalleryName + $testModuleName = "TestModule" Get-NewPSResourceRepositoryFile Get-PSResourceRepository } @@ -22,10 +23,10 @@ Describe 'Test Update-PSResource' { } It "update resource installed given Name parameter" { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name "TestModule" -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule" + Update-PSResource -Name $testModuleName -Repository $TestGalleryName + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -40,7 +41,7 @@ Describe 'Test Update-PSResource' { } It "update resources installed given Name (with wildcard) parameter" { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName Install-PSResource -Name "TestModule99" -Version "0.0.4.0" -Repository $TestGalleryName Update-PSResource -Name "TestModule*" -Repository $TestGalleryName @@ -53,7 +54,7 @@ Describe 'Test Update-PSResource' { { if ([System.Version]$item.Version -gt [System.Version]$inputHashtable[$item.Name]) { - if ($item.Name -like "TestModule") + if ($item.Name -like $testModuleName) { $isTestModuleUpdated = $true } @@ -69,10 +70,10 @@ Describe 'Test Update-PSResource' { } It "update resource installed given Name and Version (specific) parameters" { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule" + Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { @@ -99,13 +100,13 @@ Describe 'Test Update-PSResource' { It "update resource when given Name to " -TestCases $testCases2{ param($Version, $ExpectedVersions) - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName foreach ($item in $res) { - $item.Name | Should -Be "TestModule" + $item.Name | Should -Be $testModuleName $ExpectedVersions | Should -Contain $item.Version } } @@ -117,10 +118,10 @@ Describe 'Test Update-PSResource' { It "Should not update resource with incorrectly formatted version such as " -TestCases $testCases{ param($Version, $Description) - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { @@ -156,12 +157,12 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under CurrentUser scope" -skip:(!$IsWindows) { # TODO: perhaps also install TestModule with the highest version (the one above 1.2.0.0) to the AllUsers path too - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser - Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -Scope CurrentUser + Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName -Scope CurrentUser - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -178,12 +179,12 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under AllUsers scope" -skip:(!($IsWindows -and (Test-IsAdmin))) { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser - Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -Scope AllUsers + Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName -Scope AllUsers - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { @@ -199,10 +200,10 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under no specified scope" -skip:(!$IsWindows) { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -222,11 +223,11 @@ Describe 'Test Update-PSResource' { It "Update resource under CurrentUser scope - Unix only" -Skip:(Get-IsWindows) { # this line is commented out because AllUsers scope requires sudo and that isn't supported in CI yet # Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser - Update-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser + Update-PSResource -Name $testModuleName -Repository $TestGalleryName -Scope CurrentUser - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -245,12 +246,12 @@ Describe 'Test Update-PSResource' { # Expected path should be similar to: '/usr/local/share/powershell/Modules' # this test is skipped because it requires sudo to run and has yet to be resolved in CI It "Update resource under AllUsers scope - Unix only" -Skip:($true) { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser - Update-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers + Update-PSResource -Name $testModuleName -Repository $TestGalleryName -Scope AllUsers - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -270,11 +271,11 @@ Describe 'Test Update-PSResource' { It "Update resource under no specified scope - Unix only" -Skip:(Get-IsWindows) { # this is commented out because it requires sudo to run with AllUsers scope and this hasn't been resolved in CI yet # Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser - Update-PSResource -Name "TestModule" -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -307,12 +308,12 @@ Describe 'Test Update-PSResource' { } It "update resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName Set-PSResourceRepository PoshTestGallery -Trusted:$false - Update-PSResource -Name "TestModule" -Version "1.2.0.0" -Repository $TestGalleryName -TrustRepository - $res = Get-PSResource -Name "TestModule" + Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName -TrustRepository + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -328,10 +329,10 @@ Describe 'Test Update-PSResource' { } It "Update module using -WhatIf, should not update the module" { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name "TestModule" -WhatIf + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -WhatIf - $res = Get-PSResource -Name "TestModule" + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) @@ -346,10 +347,10 @@ Describe 'Test Update-PSResource' { } It "update resource installed given -Name and -PassThru parameters" { - Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - $res = Update-PSResource -Name "TestModule" -Version "1.3.0.0" -Repository $TestGalleryName -PassThru - $res.Name | Should -Be "TestModule" + $res = Update-PSResource -Name $testModuleName -Version "1.3.0.0" -Repository $TestGalleryName -PassThru + $res.Name | Should -Be $testModuleName $res.Version | Should -Be "1.3.0.0" } } From 08abd67d678ccecaa0158ce5d01f0bc878f39ae7 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 8 Dec 2021 14:25:08 -0800 Subject: [PATCH 116/276] Update change log for beta 12 release (#567) * Update change log for beta 12 release * Fix progress bar and test issues --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++ src/PowerShellGet.psd1 | 26 ++------------------- src/code/InstallHelper.cs | 38 +++++++----------------------- test/FindPSResource.Tests.ps1 | 9 ++++--- test/InstallPSResource.Tests.ps1 | 5 +++- 5 files changed, 61 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f380816ec..ee2512d2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,45 @@ # CHANGELOG +## 3.0.12-beta + +### Changes +- Support searching for all packages from a repository (i.e 'Find-PSResource -Name '*''). Note, wildcard search is not supported for AzureDevOps feed repositories and will write an error message accordingly). +- Packages found are now unique by Name,Version,Repository. +- Support searching for and returning packages found across multiple repositories when using wildcard with Repository parameter (i.e 'Find-PSResource -Name 'PackageExistingInMultipleRepos' -Repository '*'' will perform an exhaustive search). + - PSResourceInfo objects can be piped into: Install-PSResource, Uninstall-PSResource, Save-PSResource. PSRepositoryInfo objects can be piped into: Unregister-PSResourceRepository +- For more consistent pipeline support, the following cmdlets have pipeline support for the listed parameter(s): + - Find-PSResource (Name param, ValueFromPipeline) + - Get-PSResource (Name param, ValueFromPipeline) + - Install-PSResource (Name param, ValueFromPipeline) + - Publish-PSResource (None) + - Save-PSResource (Name param, ValueFromPipeline) + - Uninstall-PSResource (Name param, ValueFromPipeline) + - Update-PSResource (Name param, ValueFromPipeline) + - Get-PSResourceRepository (Name param, ValueFromPipeline) + - Set-PSResourceRepository (Name param, ValueFromPipeline) + - Register-PSResourceRepository (None) + - Unregister-PSResourceRepository (Name param, ValueFromPipelineByPropertyName) +- Implement '-Tag' parameter set for Find-PSResource (i.e 'Find-PSResource -Tag 'JSON'') +- Implement '-Type' parameter set for Find-PSResource (i.e 'Find-PSResource -Type Module') +- Implement CommandName and DSCResourceName parameter sets for Find-PSResource (i.e Find-PSResource -CommandName "Get-TargetResource"). +- Add consistent pre-release version support for cmdlets, including Uninstall-PSResource and Get-PSResource. For example, running 'Get-PSResource 'MyPackage' -Version '2.0.0-beta'' would only return MyPackage with version "2.0.0" and prerelease "beta", NOT MyPackage with version "2.0.0.0" (i.e a stable version). +- Add progress bar for installation completion for Install-PSResource, Update-PSResource and Save-PSResource. +- Implement '-Quiet' param for Install-PSResource, Save-PSResource and Update-PSResource. This suppresses the progress bar display when passed in. +- Implement '-PassThru' parameter for all appropriate cmdlets. Install-PSResource, Save-PSResource, Update-PSResource and Unregister-PSResourceRepository cmdlets now have '-PassThru' support thus completing this goal. +- Implement '-SkipDependencies' parameter for Install-PSResource, Save-PSResource, and Update-PSResource cmdlets. +- Implement '-AsNupkg' and '-IncludeXML' parameters for Save-PSResource. +- Implement '-DestinationPath' parameter for Publish-PSResource +- Add '-NoClobber' functionality to Install-PSResource. +- Add thorough error handling to Update-PSResource to cover more cases and gracefully write errors when updates can't be performed. +- Add thorough error handling to Install-PSResource to cover more cases and not fail silently when installation could not happen successfully. Also fixes bug where package would install even if it was already installed and '-Reinstall' parameter was not specified. +- Restore package if installation attempt fails when reinstalling a package. +- Fix bug with some Modules installing as Scripts. +- Fix bug with separating '$env:PSModulePath' to now work with path separators across all OS systems including Unix. +- Fix bug to register repositories with local file share paths, ensuring repositories with valid URIs can be registered. +- Revert cmdlet name 'Get-InstalledPSResource' to 'Get-PSResource' +- Remove DSCResources from PowerShellGet. +- Remove unnecessary assemblies. + ## 3.0.11-beta ### Changes diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 4df94c15f..4a48d4cde 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -40,30 +40,8 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' - -### 3.0.11 -In this release, all cmdlets have been reviewed and implementation code refactored as needed. -Cmdlets have most of their functionality, but some parameters are not yet implemented and will be added in future releases. -All tests have been reviewed and rewritten as needed. - -- Graceful handling of paths that do not exist -- The repository store (PSResourceRepository.xml) is auto-generated if it does not already exist. It also automatically registers the PowerShellGallery with a default priority of 50 and a default trusted value of false. -- Better Linux support, including graceful exits when paths do not exist -- Better pipeline input support all cmdlets -- General wildcard support for all cmdlets -- WhatIf support for all cmdlets -- All cmdlets output concrete return types -- Better help documentation for all cmdlets -- Using an exact prerelease version with Find, Install, or Save no longer requires `-Prerelease` tag -- Support for finding, installing, saving, and updating PowerShell resources from Azure Artifact feeds -- Publish-PSResource now properly dispays 'Tags' in nuspec -- Find-PSResource quickly cancels transactions with 'CTRL + C' -- Register-PSRepository now handles relative paths -- Find-PSResource and Save-PSResource deduplicates dependencies -- Install-PSResource no longer creates version folder with the prerelease tag -- Update-PSResource can now update all resources, and no longer requires name param -- Save-PSResource properly handles saving scripts -- Get-PSResource uses default PowerShell paths +### 3.0.12 beta release +See change log (CHANGELOG.md) at https://github.com/PowerShell/PowerShellGet '@ } } diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 7ed9d1916..300c5b6c9 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -310,17 +310,11 @@ private List InstallPackage( List pkgsSuccessfullyInstalled = new List(); int totalPkgs = pkgsToInstall.Count(); - // counters for tracking dependent package and current package out of total - int totalPkgsCount = 0; - int dependentPkgCount = 1; - // by default this is 1, because if a parent package was already installed and only the dependent package - // needs to be installed we don't want a default value of 0 which throws a division error. - // if parent package isn't already installed we'll set this value properly in the below if condition anyways - int currentPkgNumOfDependentPkgs = 1; - + // Counters for tracking current package out of total + int totalInstalledPkgCount = 0; foreach (PSResourceInfo pkg in pkgsToInstall) { - totalPkgsCount++; + totalInstalledPkgCount++; var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try { @@ -331,35 +325,21 @@ private List InstallPackage( // TODO: check the attributes and if it's read only then set it // attribute may be inherited from the parent // TODO: are there Linux accommodations we need to consider here? - dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly; + dir.Attributes &= ~FileAttributes.ReadOnly; _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkg.Name)); - // Will suppress progress bar if -Quiet is passed in if (!_quiet) { int activityId = 0; string activity = ""; string statusDescription = ""; - if (_pkgNamesToInstall.Contains(pkg.Name, StringComparer.InvariantCultureIgnoreCase)) - { - // Installing parent package (one whose name was passed in to install) - activityId = 0; - activity = string.Format("Installing {0}...", pkg.Name); - statusDescription = string.Format("{0}% Complete:", Math.Round(((double)totalPkgsCount / totalPkgs) * 100), 2); - currentPkgNumOfDependentPkgs = pkg.Dependencies.Count(); - dependentPkgCount = 1; - } - else - { - // Installing dependent package - activityId = 1; - activity = string.Format("Installing dependent package {0}...", pkg.Name); - statusDescription = string.Format("{0}% Complete:", Math.Round(((double)dependentPkgCount / currentPkgNumOfDependentPkgs) * 100), 2); - dependentPkgCount++; - } - + // Installing parent package (one whose name was passed in to install) + activityId = 0; + activity = string.Format("Installing {0}...", pkg.Name); + statusDescription = string.Format("{0}% Complete:", Math.Round(((double)totalInstalledPkgCount / totalPkgs) * 100), 2); + var progressRecord = new ProgressRecord(activityId, activity, statusDescription); _cmdletPassedIn.WriteProgress(progressRecord); } diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 7eb777767..20290a610 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -250,7 +250,8 @@ Describe 'Test Find-PSResource for Module' { } } - It "find all resources of Type Module when Type parameter set is used" { + # Skip test for now because it takes too long to run (> 60 sec) + It "find all resources of Type Module when Type parameter set is used" -Skip { $foundScript = $False $res = Find-PSResource -Type Module -Repository $PSGalleryName $res.Count | Should -BeGreaterThan 1 @@ -336,7 +337,8 @@ Describe 'Test Find-PSResource for Module' { $resNonDefault.Repository | Should -Be $repoLowerPriorityRanking } - It "find resource given CommandName (CommandNameParameterSet)" { + # Skip test for now because it takes too run (132.24 sec) + It "find resource given CommandName (CommandNameParameterSet)" -Skip { $res = Find-PSResource -CommandName $commandName -Repository $PSGalleryName foreach ($item in $res) { $item.Name | Should -Be $commandName @@ -351,7 +353,8 @@ Describe 'Test Find-PSResource for Module' { $res.ParentResource.Includes.Command | Should -Contain $commandName } - It "find resource given DSCResourceName (DSCResourceNameParameterSet)" { + # Skip test for now because it takes too long to run (> 60 sec) + It "find resource given DSCResourceName (DSCResourceNameParameterSet)" -Skip { $res = Find-PSResource -DscResourceName $dscResourceName -Repository $PSGalleryName foreach ($item in $res) { $item.Name | Should -Be $dscResourceName diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index dad59071b..b87fd9868 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -5,7 +5,9 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Install-PSResource for Module' { - BeforeAll{ + BeforeAll { + $OldProgressPreference = $ProgressPreference + $ProgressPreference = "SilentlyContinue" $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName @@ -21,6 +23,7 @@ Describe 'Test Install-PSResource for Module' { } AfterAll { + $ProgressPreference = $OldProgressPreference Get-RevertPSResourceRepositoryFile } From 042b43b2edfe186ba61d4c676e6944b0e010d0b5 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 8 Dec 2021 19:19:07 -0500 Subject: [PATCH 117/276] Fix tests errors being written out to output (#568) * for errors being written in Save write to a variable * for Uninstall, fix errors being written * add more verification that Install step also worked --- test/SavePSResource.Tests.ps1 | 8 ++++++-- test/UninstallPSResource.Tests.ps1 | 22 +++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 66858ce6d..067baecbb 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -52,9 +52,11 @@ Describe 'Test Save-PSResource for PSResources' { } It "Should not save resource given nonexistant name" { - Save-PSResource -Name NonExistentModule -Repository $TestGalleryName -Path $SaveDir + Save-PSResource -Name NonExistentModule -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "NonExistentModule" $pkgDir.Name | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } It "Not Save module with Name containing wildcard" { @@ -102,9 +104,11 @@ Describe 'Test Save-PSResource for PSResources' { ) { param($Version, $Description) - Save-PSResource -Name $testModuleName2 -Version $Version -Repository $TestGalleryName -Path $SaveDir + Save-PSResource -Name $testModuleName2 -Version $Version -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 $pkgDir | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } It "Save resource when given Name, Version '*', should install the latest version" { diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 3c4bcdc66..eba8cfbc5 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -43,15 +43,27 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall a specific script by name" { - $null = Install-PSResource Test-RPC -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource "test_script" -Repository $TestGalleryName -TrustRepository + $res = Get-PSResource -Name "test_script" + $res.Name | Should -Be "test_script" - Uninstall-PSResource -name Test-RPC + Uninstall-PSResource -name "test_script" + $res = Get-PSResource -Name "test_script" + $res | Should -BeNullOrEmpty } It "Uninstall a list of scripts by name" { - $null = Install-PSResource adsql, airoute -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name adsql, airoute + $null = Install-PSResource "test_script", "TestTestScript" -Repository $TestGalleryName -TrustRepository + $res = Get-PSResource -Name "test_script" + $res2 = Get-PSResource -Name "TestTestScript" + $res.Name | Should -Be "test_script" + $res2.Name | Should -Be "TestTestScript" + + Uninstall-PSResource -Name "test_script", "TestTestScript" + $res = Get-PSResource -Name "test_script" + $res2 = Get-PSResource -Name "TestTestScript" + $res | Should -BeNullOrEmpty + $res2 | Should -BeNullOrEmpty } It "Uninstall a module when given name and specifying all versions" { From 3fb6056297f3e94269eaf975f862a7f6bc9b822d Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 8 Dec 2021 16:40:10 -0800 Subject: [PATCH 118/276] Suppress progress bar during testing (#569) --- src/code/InstallHelper.cs | 15 +- test/GetInstalledPSResource.Tests.ps1 | 1 + test/InstallPSResource.Tests.ps1 | 4 +- test/SavePSResource.Tests.ps1 | 521 +++++++++++++------------- test/UninstallPSResource.Tests.ps1 | 447 +++++++++++----------- test/UpdatePSResource.Tests.ps1 | 3 +- 6 files changed, 495 insertions(+), 496 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 300c5b6c9..64c42dddd 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -332,16 +332,11 @@ private List InstallPackage( if (!_quiet) { int activityId = 0; - string activity = ""; - string statusDescription = ""; - - // Installing parent package (one whose name was passed in to install) - activityId = 0; - activity = string.Format("Installing {0}...", pkg.Name); - statusDescription = string.Format("{0}% Complete:", Math.Round(((double)totalInstalledPkgCount / totalPkgs) * 100), 2); - - var progressRecord = new ProgressRecord(activityId, activity, statusDescription); - _cmdletPassedIn.WriteProgress(progressRecord); + int percentComplete = ((totalInstalledPkgCount * 100) / totalPkgs); + string activity = string.Format("Installing {0}...", pkg.Name); + string statusDescription = string.Format("{0}% Complete", percentComplete); + _cmdletPassedIn.WriteProgress( + new ProgressRecord(activityId, activity, statusDescription)); } // Create PackageIdentity in order to download diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index b7901be78..63d44e241 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +$ProgressPreference = "SilentlyContinue" Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Get-PSResource for Module' { diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index b87fd9868..b5cf93604 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -1,13 +1,12 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +$ProgressPreference = "SilentlyContinue" Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Install-PSResource for Module' { BeforeAll { - $OldProgressPreference = $ProgressPreference - $ProgressPreference = "SilentlyContinue" $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName @@ -23,7 +22,6 @@ Describe 'Test Install-PSResource for Module' { } AfterAll { - $ProgressPreference = $OldProgressPreference Get-RevertPSResourceRepositoryFile } diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 067baecbb..6704ee72b 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -1,261 +1,262 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe 'Test Save-PSResource for PSResources' { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - $NuGetGalleryName = Get-NuGetGalleryName - $testModuleName = "test_module" - $testModuleName2 = "TestModule" - $testScriptName = "TestTestScript" - Get-NewPSResourceRepositoryFile - Register-LocalRepos - - $SaveDir = Join-Path $TestDrive 'SavedResources' - New-Item -Item Directory $SaveDir -Force - } - - AfterEach { - # Delte contents of save directory - Remove-Item -Path (Join-Path $SaveDir '*') -Recurse -Force -ErrorAction SilentlyContinue - } - - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - It "Save specific module resource by name" { - Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 - } - - It "Save specific script resource by name" { - Save-PSResource -Name $testScriptName -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestTestScript.ps1" - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 - } - - It "Save multiple resources by name" { - $pkgNames = @("TestModule","TestModule99") - Save-PSResource -Name $pkgNames -Repository $TestGalleryName -Path $SaveDir - $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "TestModule" -or $_.Name -eq "TestModule99" } - $pkgDirs.Count | Should -Be 2 - (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 - (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 - } - - It "Should not save resource given nonexistant name" { - Save-PSResource -Name NonExistentModule -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "NonExistentModule" - $pkgDir.Name | Should -BeNullOrEmpty - $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" - } - - It "Not Save module with Name containing wildcard" { - Save-PSResource -Name "TestModule*" -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue - $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "NameContainsWildcard,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" - } - - # Do some version testing, but Find-PSResource should be doing thorough testing - It "Should save resource given name and exact version" { - Save-PSResource -Name $testModuleName2 -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.2.0" - } - - It "Should save resource given name and exact version with bracket syntax" { - Save-PSResource -Name $testModuleName2 -Version "[1.2.0]" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.2.0" - } - - It "Should save resource given name and exact range inclusive [1.0.0, 1.1.1]" { - Save-PSResource -Name $testModuleName2 -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.1.1" - } - - It "Should save resource given name and exact range exclusive (1.0.0, 1.1.1)" { - Save-PSResource -Name $testModuleName2 -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.1" - } - - It "Should not save resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, - @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} - ) { - param($Version, $Description) - - Save-PSResource -Name $testModuleName2 -Version $Version -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -BeNullOrEmpty - $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" - } - - It "Save resource when given Name, Version '*', should install the latest version" { - Save-PSResource -Name $testModuleName2 -Version "*" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" - } - - It "Save resource with latest (including prerelease) version given Prerelease parameter" { - Save-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModulePrerelease" - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "0.0.1" - } - - It "Save a module with a dependency" { - Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir - $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } - $pkgDirs.Count | Should -Be 2 - (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 - (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 - } - - It "Save a module with a dependency and skip saving the dependency" { - Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir -SkipDependencyCheck - $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } - $pkgDirs.Count | Should -Be 1 - (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 - } - - It "Save resource via InputObject by piping from Find-PSresource" { - Find-PSResource -Name $testModuleName2 -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" - } - - It "Save resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { - try { - Set-PSResourceRepository PoshTestGallery -Trusted:$false - Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -TrustRepository -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" - } - finally { - Set-PSResourceRepository PoshTestGallery -Trusted - } - } - - It "Save resource from local repository given Repository parameter" { - $publishModuleName = "TestFindModule" - $repoName = "psgettestlocal" - Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName $repoName - Set-PSResourceRepository "psgettestlocal" -Trusted:$true - - Save-PSResource -Name $publishModuleName -Repository $repoName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $publishModuleName - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 - } - - It "Save specific module resource by name when no repository is specified" { - Set-PSResourceRepository "PoshTestGallery" -Trusted:$True - Set-PSResourceRepository "PSGallery" -Trusted:$True - Set-PSResourceRepository "psgettestlocal2" -Trusted:$True - - Save-PSResource -Name "TestModule" -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 - } - - It "Save PSResourceInfo object piped in" { - Find-PSResource -Name $testModuleName2 -Version "1.1.0.0" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 - } - - It "Save PSResourceInfo object piped in for prerelease version object" { - Find-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 - } - - It "Save module as a nupkg" { - Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -AsNupkg - write-host $SaveDir - write-host - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testmodule.1.3.0.nupkg" - $pkgDir | Should -Not -BeNullOrEmpty - } - - It "Save script as a nupkg" { - Save-PSResource -Name $testScriptName -Version "1.3.1" -Repository $TestGalleryName -Path $SaveDir -AsNupkg - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testtestscript.1.3.1.nupkg" - $pkgDir | Should -Not -BeNullOrEmpty - } - - It "Save module and include XML metadata file" { - Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -IncludeXML - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" - $xmlFile = Get-ChildItem -Path $pkgDirVersion.FullName | Where-Object Name -eq "PSGetModuleInfo.xml" - $xmlFile | Should -Not -BeNullOrEmpty - } - - It "Save module using -PassThru" { - $res = Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru - $res.Name | Should -Be $testModuleName2 - $res.Version | Should -Be "1.3.0.0" - } -<# - # Tests should not write to module directory - It "Save specific module resource by name if no -Path param is specifed" { - Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName - $pkgDir = Get-ChildItem -Path . | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 - - # Delete all files and subdirectories in the current , but keep the directory $SaveDir - if (Test-Path -Path $pkgDir.FullName) { - Remove-Item -Path $pkgDir.FullName -Recurse -Force -ErrorAction SilentlyContinue - } - } -#> - -<# - # This needs to be manually tested due to prompt - It "Install resource should prompt 'trust repository' if repository is not trusted" { - Set-PSResourceRepository PoshTestGallery -Trusted:$false - - Install-PSResource -Name $testModuleName2 -Repository $TestGalleryName -confirm:$false - - $pkg = Get-Module $testModuleName2 -ListAvailable - $pkg.Name | Should -Be $testModuleName2 - - Set-PSResourceRepository PoshTestGallery -Trusted - } -#> +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$ProgressPreference = "SilentlyContinue" +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Save-PSResource for PSResources' { + + BeforeAll { + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + $NuGetGalleryName = Get-NuGetGalleryName + $testModuleName = "test_module" + $testModuleName2 = "TestModule" + $testScriptName = "TestTestScript" + Get-NewPSResourceRepositoryFile + Register-LocalRepos + + $SaveDir = Join-Path $TestDrive 'SavedResources' + New-Item -Item Directory $SaveDir -Force + } + + AfterEach { + # Delte contents of save directory + Remove-Item -Path (Join-Path $SaveDir '*') -Recurse -Force -ErrorAction SilentlyContinue + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Save specific module resource by name" { + Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save specific script resource by name" { + Save-PSResource -Name $testScriptName -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestTestScript.ps1" + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save multiple resources by name" { + $pkgNames = @("TestModule","TestModule99") + Save-PSResource -Name $pkgNames -Repository $TestGalleryName -Path $SaveDir + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "TestModule" -or $_.Name -eq "TestModule99" } + $pkgDirs.Count | Should -Be 2 + (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 + (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 + } + + It "Should not save resource given nonexistant name" { + Save-PSResource -Name NonExistentModule -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "NonExistentModule" + $pkgDir.Name | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + + It "Not Save module with Name containing wildcard" { + Save-PSResource -Name "TestModule*" -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "NameContainsWildcard,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + + # Do some version testing, but Find-PSResource should be doing thorough testing + It "Should save resource given name and exact version" { + Save-PSResource -Name $testModuleName2 -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.2.0" + } + + It "Should save resource given name and exact version with bracket syntax" { + Save-PSResource -Name $testModuleName2 -Version "[1.2.0]" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.2.0" + } + + It "Should save resource given name and exact range inclusive [1.0.0, 1.1.1]" { + Save-PSResource -Name $testModuleName2 -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.1.1" + } + + It "Should save resource given name and exact range exclusive (1.0.0, 1.1.1)" { + Save-PSResource -Name $testModuleName2 -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.1" + } + + It "Should not save resource with incorrectly formatted version such as " -TestCases @( + @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, + @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + ) { + param($Version, $Description) + + Save-PSResource -Name $testModuleName2 -Version $Version -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -BeNullOrEmpty + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + + It "Save resource when given Name, Version '*', should install the latest version" { + Save-PSResource -Name $testModuleName2 -Version "*" -Repository $TestGalleryName -Path $SaveDir -ErrorAction SilentlyContinue + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" + } + + It "Save resource with latest (including prerelease) version given Prerelease parameter" { + Save-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModulePrerelease" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "0.0.1" + } + + It "Save a module with a dependency" { + Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } + $pkgDirs.Count | Should -Be 2 + (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 + (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 + } + + It "Save a module with a dependency and skip saving the dependency" { + Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir -SkipDependencyCheck + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } + $pkgDirs.Count | Should -Be 1 + (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 + } + + It "Save resource via InputObject by piping from Find-PSresource" { + Find-PSResource -Name $testModuleName2 -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" + } + + It "Save resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { + try { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -TrustRepository -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" + } + finally { + Set-PSResourceRepository PoshTestGallery -Trusted + } + } + + It "Save resource from local repository given Repository parameter" { + $publishModuleName = "TestFindModule" + $repoName = "psgettestlocal" + Get-ModuleResourcePublishedToLocalRepoTestDrive $publishModuleName $repoName + Set-PSResourceRepository "psgettestlocal" -Trusted:$true + + Save-PSResource -Name $publishModuleName -Repository $repoName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $publishModuleName + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save specific module resource by name when no repository is specified" { + Set-PSResourceRepository "PoshTestGallery" -Trusted:$True + Set-PSResourceRepository "PSGallery" -Trusted:$True + Set-PSResourceRepository "psgettestlocal2" -Trusted:$True + + Save-PSResource -Name "TestModule" -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save PSResourceInfo object piped in" { + Find-PSResource -Name $testModuleName2 -Version "1.1.0.0" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save PSResourceInfo object piped in for prerelease version object" { + Find-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 + } + + It "Save module as a nupkg" { + Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + write-host $SaveDir + write-host + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testmodule.1.3.0.nupkg" + $pkgDir | Should -Not -BeNullOrEmpty + } + + It "Save script as a nupkg" { + Save-PSResource -Name $testScriptName -Version "1.3.1" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testtestscript.1.3.1.nupkg" + $pkgDir | Should -Not -BeNullOrEmpty + } + + It "Save module and include XML metadata file" { + Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -IncludeXML + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.3.0" + $xmlFile = Get-ChildItem -Path $pkgDirVersion.FullName | Where-Object Name -eq "PSGetModuleInfo.xml" + $xmlFile | Should -Not -BeNullOrEmpty + } + + It "Save module using -PassThru" { + $res = Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru + $res.Name | Should -Be $testModuleName2 + $res.Version | Should -Be "1.3.0.0" + } +<# + # Tests should not write to module directory + It "Save specific module resource by name if no -Path param is specifed" { + Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName + $pkgDir = Get-ChildItem -Path . | Where-Object Name -eq $testModuleName2 + $pkgDir | Should -Not -BeNullOrEmpty + (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 + + # Delete all files and subdirectories in the current , but keep the directory $SaveDir + if (Test-Path -Path $pkgDir.FullName) { + Remove-Item -Path $pkgDir.FullName -Recurse -Force -ErrorAction SilentlyContinue + } + } +#> + +<# + # This needs to be manually tested due to prompt + It "Install resource should prompt 'trust repository' if repository is not trusted" { + Set-PSResourceRepository PoshTestGallery -Trusted:$false + + Install-PSResource -Name $testModuleName2 -Repository $TestGalleryName -confirm:$false + + $pkg = Get-Module $testModuleName2 -ListAvailable + $pkg.Name | Should -Be $testModuleName2 + + Set-PSResourceRepository PoshTestGallery -Trusted + } +#> } \ No newline at end of file diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index eba8cfbc5..b4542254a 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -1,222 +1,225 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe 'Test Uninstall-PSResource for Modules' { - - BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName - $PSGalleryName = Get-PSGalleryName - $testModuleName = "test_module" - $testScriptName = "test_script" - Get-NewPSResourceRepositoryFile - Uninstall-PSResource -name ContosoServer -Version "*" - } - BeforeEach{ - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - } - AfterAll { - Get-RevertPSResourceRepositoryFile - } - - It "Uninstall a specific module by name" { - Uninstall-PSResource -name ContosoServer - Get-Module ContosoServer -ListAvailable | Should -Be $null - } - - $testCases = @{Name="Test?Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"}, - @{Name="Test[Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"} - - It "not uninstall module given Name with invalid wildcard characters" -TestCases $testCases { - param($Name, $ErrorId) - Uninstall-PSResource -Name $Name -ErrorVariable err -ErrorAction SilentlyContinue - $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource" - } - - It "Uninstall a list of modules by name" { - $null = Install-PSResource BaseTestPackage -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name BaseTestPackage, ContosoServer - Get-Module ContosoServer, BaseTestPackage -ListAvailable | Should -be $null - } - - It "Uninstall a specific script by name" { - $null = Install-PSResource "test_script" -Repository $TestGalleryName -TrustRepository - $res = Get-PSResource -Name "test_script" - $res.Name | Should -Be "test_script" - - Uninstall-PSResource -name "test_script" - $res = Get-PSResource -Name "test_script" - $res | Should -BeNullOrEmpty - } - - It "Uninstall a list of scripts by name" { - $null = Install-PSResource "test_script", "TestTestScript" -Repository $TestGalleryName -TrustRepository - $res = Get-PSResource -Name "test_script" - $res2 = Get-PSResource -Name "TestTestScript" - $res.Name | Should -Be "test_script" - $res2.Name | Should -Be "TestTestScript" - - Uninstall-PSResource -Name "test_script", "TestTestScript" - $res = Get-PSResource -Name "test_script" - $res2 = Get-PSResource -Name "TestTestScript" - $res | Should -BeNullOrEmpty - $res2 | Should -BeNullOrEmpty - } - - It "Uninstall a module when given name and specifying all versions" { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name ContosoServer -version "*" - $pkgs = Get-Module ContosoServer -ListAvailable - $pkgs.Version | Should -Not -Contain "1.0.0" - $pkgs.Version | Should -Not -Contain "1.5.0" - $pkgs.Version | Should -Not -Contain "2.0.0" - $pkgs.Version | Should -Not -Contain "2.5.0" - } - - It "Uninstall a module when given name and using the default version (ie all versions, not explicitly specified)" { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name ContosoServer - $pkgs = Get-Module ContosoServer -ListAvailable - $pkgs.Version | Should -Not -Contain "1.0.0" - $pkgs.Version | Should -Not -Contain "1.5.0" - $pkgs.Version | Should -Not -Contain "2.0.0" - $pkgs.Version | Should -Not -Contain "2.5.0" - } - - It "Uninstall module when given Name and specifying exact version" { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" - $pkgs = Get-Module ContosoServer -ListAvailable - $pkgs.Version | Should -Not -Contain "1.0.0" - } - - $testCases = @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - - It "Uninstall module when given Name to " -TestCases $testCases { - param($Version, $ExpectedVersion) - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name ContosoServer -Version $Version - $pkgs = Get-Module ContosoServer -ListAvailable - $pkgs.Version | Should -Not -Contain $Version - } - - $testCases2 = @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, - @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} - - It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases2 { - param($Version, $Description) - - {Uninstall-PSResource -Name "ContosoServer" -Version $Version} | Should -Throw "Argument for -Version parameter is not in the proper format." - } - - $testCases3 = @{Version='(2.5.0.0)'; Description="exclusive version (8.1.0.0)"}, - @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"} - - It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases3 { - param($Version, $Description) - - Uninstall-PSResource -Name "ContosoServer" -Version $Version - - $pkg = Get-Module ContosoServer -ListAvailable - $pkg.Version | Should -Be "2.5" - } - - It "Uninstall prerelease version module when prerelease version specified" { - Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName - Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" - $res = Get-PSResource $testModuleName -Version "5.2.5-alpha001" - $res | Should -BeNullOrEmpty - } - - It "Not uninstall non-prerelease version module when similar prerelease version is specified" { - Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $TestGalleryName - Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" - $res = Get-PSResource -Name $testModuleName -Version "5.0.0.0" - $res.Name | Should -Be $testModuleName - $res.Version | Should -Be "5.0.0.0" - } - - It "Uninstall prerelease version script when prerelease version specified" { - Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName - Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha001" - $res = Get-PSResource -Name $testScriptName - $res | Should -BeNullOrEmpty - } - - It "Not uninstall non-prerelease version module when prerelease version specified" { - Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $TestGalleryName - Uninstall-PSResource -Name $testScriptName -Version "2.5.0-alpha001" - $res = Get-PSResource -Name $testScriptName -Version "2.5.0.0" - $res.Name | Should -Be $testScriptName - $res.Version | Should -Be "2.5.0.0" - } - - It "Uninstall module using -WhatIf, should not uninstall the module" { - Uninstall-PSResource -Name "ContosoServer" -WhatIf - $pkg = Get-Module ContosoServer -ListAvailable - $pkg.Version | Should -Be "2.5" - } - - It "Do not Uninstall module that is a dependency for another module" { - $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name "RequiredModule1" -ErrorVariable ev -ErrorAction SilentlyContinue - - $pkg = Get-Module "RequiredModule1" -ListAvailable - $pkg | Should -Not -Be $null - - $ev.FullyQualifiedErrorId | Should -BeExactly 'UninstallPSResourcePackageIsaDependency,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource' - } - - It "Uninstall module that is a dependency for another module using -SkipDependencyCheck" { - $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue - - Uninstall-PSResource -Name "RequiredModule1" -SkipDependencyCheck - - $pkg = Get-Module "RequiredModule1" -ListAvailable - $pkg | Should -BeNullOrEmpty - } - - It "Uninstall PSResourceInfo object piped in" { - Install-PSResource -Name "ContosoServer" -Version "1.5.0.0" -Repository $TestGalleryName - Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" | Uninstall-PSResource - $res = Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" - $res | Should -BeNullOrEmpty - } - - It "Uninstall PSResourceInfo object piped in for prerelease version object" { - Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource - $res = Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" - $res | Should -BeNullOrEmpty - } -} +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$ProgressPreference = "SilentlyContinue" +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Uninstall-PSResource for Modules' { + + BeforeAll{ + $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName + $testModuleName = "test_module" + $testScriptName = "test_script" + Get-NewPSResourceRepositoryFile + Uninstall-PSResource -name ContosoServer -Version "*" + } + + BeforeEach { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + } + + AfterAll { + Get-RevertPSResourceRepositoryFile + } + + It "Uninstall a specific module by name" { + Uninstall-PSResource -name ContosoServer + Get-Module ContosoServer -ListAvailable | Should -Be $null + } + + $testCases = @{Name="Test?Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"}, + @{Name="Test[Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"} + + It "not uninstall module given Name with invalid wildcard characters" -TestCases $testCases { + param($Name, $ErrorId) + Uninstall-PSResource -Name $Name -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource" + } + + It "Uninstall a list of modules by name" { + $null = Install-PSResource BaseTestPackage -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue -SkipDependencyCheck + + Uninstall-PSResource -Name BaseTestPackage, ContosoServer + Get-Module ContosoServer, BaseTestPackage -ListAvailable | Should -be $null + } + + It "Uninstall a specific script by name" { + $null = Install-PSResource "test_script" -Repository $TestGalleryName -TrustRepository + $res = Get-PSResource -Name "test_script" + $res.Name | Should -Be "test_script" + + Uninstall-PSResource -name "test_script" + $res = Get-PSResource -Name "test_script" + $res | Should -BeNullOrEmpty + } + + It "Uninstall a list of scripts by name" { + $null = Install-PSResource "test_script", "TestTestScript" -Repository $TestGalleryName -TrustRepository + $res = Get-PSResource -Name "test_script" + $res2 = Get-PSResource -Name "TestTestScript" + $res.Name | Should -Be "test_script" + $res2.Name | Should -Be "TestTestScript" + + Uninstall-PSResource -Name "test_script", "TestTestScript" + $res = Get-PSResource -Name "test_script" + $res2 = Get-PSResource -Name "TestTestScript" + $res | Should -BeNullOrEmpty + $res2 | Should -BeNullOrEmpty + } + + It "Uninstall a module when given name and specifying all versions" { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name ContosoServer -version "*" + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain "1.0.0" + $pkgs.Version | Should -Not -Contain "1.5.0" + $pkgs.Version | Should -Not -Contain "2.0.0" + $pkgs.Version | Should -Not -Contain "2.5.0" + } + + It "Uninstall a module when given name and using the default version (ie all versions, not explicitly specified)" { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name ContosoServer + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain "1.0.0" + $pkgs.Version | Should -Not -Contain "1.5.0" + $pkgs.Version | Should -Not -Contain "2.0.0" + $pkgs.Version | Should -Not -Contain "2.5.0" + } + + It "Uninstall module when given Name and specifying exact version" { + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain "1.0.0" + } + + $testCases = @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, + @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, + @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + + It "Uninstall module when given Name to " -TestCases $testCases { + param($Version, $ExpectedVersion) + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name ContosoServer -Version $Version + $pkgs = Get-Module ContosoServer -ListAvailable + $pkgs.Version | Should -Not -Contain $Version + } + + $testCases2 = @{Version='[1.*.0]'; Description="version with wilcard in middle"}, + @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, + @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.5.0.]'; Description="version with missing digit at end"}, + @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + + It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases2 { + param($Version, $Description) + + {Uninstall-PSResource -Name "ContosoServer" -Version $Version} | Should -Throw "Argument for -Version parameter is not in the proper format." + } + + $testCases3 = @{Version='(2.5.0.0)'; Description="exclusive version (8.1.0.0)"}, + @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"} + + It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases3 { + param($Version, $Description) + + Uninstall-PSResource -Name "ContosoServer" -Version $Version + + $pkg = Get-Module ContosoServer -ListAvailable + $pkg.Version | Should -Be "2.5" + } + + It "Uninstall prerelease version module when prerelease version specified" { + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName + Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res = Get-PSResource $testModuleName -Version "5.2.5-alpha001" + $res | Should -BeNullOrEmpty + } + + It "Not uninstall non-prerelease version module when similar prerelease version is specified" { + Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" + $res = Get-PSResource -Name $testModuleName -Version "5.0.0.0" + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "5.0.0.0" + } + + It "Uninstall prerelease version script when prerelease version specified" { + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName + Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res = Get-PSResource -Name $testScriptName + $res | Should -BeNullOrEmpty + } + + It "Not uninstall non-prerelease version module when prerelease version specified" { + Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testScriptName -Version "2.5.0-alpha001" + $res = Get-PSResource -Name $testScriptName -Version "2.5.0.0" + $res.Name | Should -Be $testScriptName + $res.Version | Should -Be "2.5.0.0" + } + + It "Uninstall module using -WhatIf, should not uninstall the module" { + Uninstall-PSResource -Name "ContosoServer" -WhatIf + $pkg = Get-Module ContosoServer -ListAvailable + $pkg.Version | Should -Be "2.5" + } + + It "Do not Uninstall module that is a dependency for another module" { + $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name "RequiredModule1" -ErrorVariable ev -ErrorAction SilentlyContinue + + $pkg = Get-Module "RequiredModule1" -ListAvailable + $pkg | Should -Not -Be $null + + $ev.FullyQualifiedErrorId | Should -BeExactly 'UninstallPSResourcePackageIsaDependency,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource' + } + + It "Uninstall module that is a dependency for another module using -SkipDependencyCheck" { + $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + + Uninstall-PSResource -Name "RequiredModule1" -SkipDependencyCheck + + $pkg = Get-Module "RequiredModule1" -ListAvailable + $pkg | Should -BeNullOrEmpty + } + + It "Uninstall PSResourceInfo object piped in" { + Install-PSResource -Name "ContosoServer" -Version "1.5.0.0" -Repository $TestGalleryName + Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" | Uninstall-PSResource + $res = Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" + $res | Should -BeNullOrEmpty + } + + It "Uninstall PSResourceInfo object piped in for prerelease version object" { + Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName + Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource + $res = Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" + $res | Should -BeNullOrEmpty + } +} diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index c2449a276..cb11a8b59 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -1,12 +1,13 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +$ProgressPreference = "SilentlyContinue" Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Update-PSResource' { - BeforeAll{ + BeforeAll { $TestGalleryName = Get-PoshTestGalleryName $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "TestModule" From f22c1319106fdf45a38f691bfc45dcbba4080bf6 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Fri, 17 Dec 2021 10:01:00 -0800 Subject: [PATCH 119/276] Add new SBOM parameters (#579) --- .ci/ci_release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index fbb6b580f..ce6a61901 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -243,6 +243,8 @@ stages: parameters: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' + PackageName: 'PowerShellGet' + PackageVersion: '3.0.12' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' From 1242151789400fc6cda38cb16e68f8a6451038f7 Mon Sep 17 00:00:00 2001 From: Cansu Erdogan Date: Fri, 14 Jan 2022 17:24:23 -0600 Subject: [PATCH 120/276] Add support for credential persistence (#480) add support for credential persistence --- src/PSGet.Format.ps1xml | 98 +- src/code/FindHelper.cs | 25 +- src/code/InstallHelper.cs | 16 + src/code/PSCredentialInfo.cs | 107 + src/code/PSRepositoryInfo.cs | 9 +- src/code/RegisterPSResourceRepository.cs | 64 +- src/code/RepositorySettings.cs | 131 +- src/code/SetPSResourceRepository.cs | 73 +- src/code/Utils.cs | 1737 ++++++++++------- test/GetPSResourceRepository.Tests.ps1 | 15 +- test/PSCredentialInfo.Tests.ps1 | 82 + test/PSGetTestUtils.psm1 | 19 + test/PublishPSResource.Tests.ps1 | 19 +- test/RegisterPSResourceRepository.Tests.ps1 | 79 +- test/SetPSResourceRepository.Tests.ps1 | 102 +- test/UnregisterPSResourceRepository.Tests.ps1 | 2 +- test/testRepositoriesWithCredentialInfo.xml | 7 + 17 files changed, 1814 insertions(+), 771 deletions(-) create mode 100644 src/code/PSCredentialInfo.cs create mode 100644 test/PSCredentialInfo.Tests.ps1 create mode 100644 test/testRepositoriesWithCredentialInfo.xml diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml index 7b47f3878..8baea53f1 100644 --- a/src/PSGet.Format.ps1xml +++ b/src/PSGet.Format.ps1xml @@ -1,19 +1,19 @@ - + PSResourceInfo Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - + - - - - - - - + + + + + + + @@ -23,42 +23,66 @@ Repository Description - + PSIncludedResourceInfoTable - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSIncludedResourceInfo + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSIncludedResourceInfo - - - - - - - - - - - - - - - - - - - Name - $_.ParentResource.Version - $_.ParentResource.PrereleaseLabel - $_.ParentResource.Name - $_.ParentResource.Repository - - - + + + + + + + + + + + + + + + + + + + Name + $_.ParentResource.Version + $_.ParentResource.PrereleaseLabel + $_.ParentResource.Name + $_.ParentResource.Repository + + + + + + + PSRepositoryInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo + + + + + + + + + + + + Name + Url + Trusted + Priority + + + diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index d126df242..e7a3d7726 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -9,12 +9,14 @@ using NuGet.Protocol.Core.Types; using NuGet.Versioning; using System; +using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; using System.Management.Automation; using System.Net; using System.Net.Http; +using System.Security; using System.Threading; using Dbg = System.Diagnostics.Debug; @@ -139,7 +141,7 @@ public IEnumerable FindByResourceName( // detect if Script repository needs to be added and/or Module repository needs to be skipped Uri psGalleryScriptsUrl = new Uri("http://www.powershellgallery.com/api/v2/items/psscript/"); - PSRepositoryInfo psGalleryScripts = new PSRepositoryInfo(_psGalleryScriptsRepoName, psGalleryScriptsUrl, repositoriesToSearch[i].Priority, false); + PSRepositoryInfo psGalleryScripts = new PSRepositoryInfo(_psGalleryScriptsRepoName, psGalleryScriptsUrl, repositoriesToSearch[i].Priority, trusted: false, credentialInfo: null); if (_type == ResourceType.None) { _cmdletPassedIn.WriteVerbose("Null Type provided, so add PSGalleryScripts repository"); @@ -159,7 +161,7 @@ public IEnumerable FindByResourceName( // 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); + PSRepositoryInfo poshTestGalleryScripts = new PSRepositoryInfo(_poshTestGalleryScriptsRepoName, poshTestGalleryScriptsUrl, repositoriesToSearch[i].Priority, trusted: false, credentialInfo: null); if (_type == ResourceType.None) { _cmdletPassedIn.WriteVerbose("Null Type provided, so add PoshTestGalleryScripts repository"); @@ -180,7 +182,8 @@ public IEnumerable FindByResourceName( _cmdletPassedIn.WriteVerbose(string.Format("Searching in repository {0}", repositoriesToSearch[i].Name)); foreach (var pkg in SearchFromRepository( repositoryName: repositoriesToSearch[i].Name, - repositoryUrl: repositoriesToSearch[i].Url)) + repositoryUrl: repositoriesToSearch[i].Url, + repositoryCredentialInfo: repositoriesToSearch[i].CredentialInfo)) { yield return pkg; } @@ -193,7 +196,8 @@ public IEnumerable FindByResourceName( private IEnumerable SearchFromRepository( string repositoryName, - Uri repositoryUrl) + Uri repositoryUrl, + PSCredentialInfo repositoryCredentialInfo) { PackageSearchResource resourceSearch; PackageMetadataResource resourceMetadata; @@ -229,12 +233,25 @@ private IEnumerable SearchFromRepository( // HTTP, HTTPS, FTP Uri schemes (only other Uri schemes allowed by RepositorySettings.Read() API) PackageSource source = new PackageSource(repositoryUrl.ToString()); + + // Explicitly passed in Credential takes precedence over repository CredentialInfo if (_credential != null) { string password = new NetworkCredential(string.Empty, _credential.Password).Password; source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl.ToString(), _credential.UserName, password, true, null); _cmdletPassedIn.WriteVerbose("credential successfully set for repository: " + repositoryName); } + else if (repositoryCredentialInfo != null) + { + PSCredential repoCredential = Utils.GetRepositoryCredentialFromSecretManagement( + repositoryName, + repositoryCredentialInfo, + _cmdletPassedIn); + + string password = new NetworkCredential(string.Empty, repoCredential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl.ToString(), repoCredential.UserName, password, true, null); + _cmdletPassedIn.WriteVerbose("credential successfully read from vault and set for repository: " + repositoryName); + } // GetCoreV3() API is able to handle V2 and V3 repository endpoints var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 64c42dddd..5094b1f02 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -226,7 +226,9 @@ private List ProcessRepositories( List pkgsInstalled = InstallPackage( pkgsFromRepoToInstall, + repoName, repo.Url.AbsoluteUri, + repo.CredentialInfo, credential, isLocalRepo); @@ -303,7 +305,9 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable InstallPackage( IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) + string repoName, string repoUrl, + PSCredentialInfo repoCredentialInfo, PSCredential credential, bool isLocalRepo) { @@ -398,11 +402,23 @@ private List InstallPackage( /* Download from a non-local repository */ // Set up NuGet API resource for download PackageSource source = new PackageSource(repoUrl); + + // Explicitly passed in Credential takes precedence over repository CredentialInfo if (credential != null) { string password = new NetworkCredential(string.Empty, credential.Password).Password; source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, credential.UserName, password, true, null); } + else if (repoCredentialInfo != null) + { + PSCredential repoCredential = Utils.GetRepositoryCredentialFromSecretManagement( + repoName, + repoCredentialInfo, + _cmdletPassedIn); + + string password = new NetworkCredential(string.Empty, repoCredential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, repoCredential.UserName, password, true, null); + } var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); SourceRepository repository = new SourceRepository(source, provider); diff --git a/src/code/PSCredentialInfo.cs b/src/code/PSCredentialInfo.cs new file mode 100644 index 000000000..11ec0f198 --- /dev/null +++ b/src/code/PSCredentialInfo.cs @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a repository's authentication credential. + /// + public sealed class PSCredentialInfo + { + #region Constructor + + /// + /// Initializes a new instance of the PSCredentialInfo class with + /// vaultName and secretName of type string, and + /// (optionally) credential of type PSCredential. + /// + /// + /// + /// + public PSCredentialInfo(string vaultName, string secretName, PSCredential credential = null) + { + VaultName = vaultName; + SecretName = secretName; + Credential = credential; + } + + /// + /// Initializes a new instance of the PSCredentialInfo class with + /// vaultName and secretName of type string, and + /// (optionally) credential of type PSCredential from a PSObject. + /// + /// + public PSCredentialInfo(PSObject psObject) + { + if (psObject == null) + { + throw new ArgumentNullException(nameof(psObject)); + } + + VaultName = (string) psObject.Properties[PSCredentialInfo.VaultNameAttribute]?.Value; + SecretName = (string) psObject.Properties[PSCredentialInfo.SecretNameAttribute]?.Value; + Credential = (PSCredential) psObject.Properties[PSCredentialInfo.CredentialAttribute]?.Value; + } + + #endregion + + #region Members + + private string _vaultName; + /// + /// the Name of the SecretManagement Vault + /// + public string VaultName { + get + { + return _vaultName; + } + + private set + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException($"Invalid CredentialInfo, {PSCredentialInfo.VaultNameAttribute} must be a non-empty string"); + } + + _vaultName = value; + } + } + + private string _secretName; + /// + /// the Name of the Secret + /// + public string SecretName { + get + { + return _secretName; + } + + private set + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException($"Invalid CredentialInfo, {PSCredentialInfo.SecretNameAttribute} must be a non-empty string"); + } + + _secretName = value; + } + } + + /// + /// optional Credential object to save in a SecretManagement Vault + /// for authenticating to repositories + /// + public PSCredential Credential { get; private set; } + + internal static readonly string VaultNameAttribute = nameof(VaultName); + internal static readonly string SecretNameAttribute = nameof(SecretName); + internal static readonly string CredentialAttribute = nameof(Credential); + + #endregion + } +} diff --git a/src/code/PSRepositoryInfo.cs b/src/code/PSRepositoryInfo.cs index b1d99eb08..294559c72 100644 --- a/src/code/PSRepositoryInfo.cs +++ b/src/code/PSRepositoryInfo.cs @@ -13,12 +13,13 @@ public sealed class PSRepositoryInfo { #region Constructor - public PSRepositoryInfo(string name, Uri url, int priority, bool trusted) + public PSRepositoryInfo(string name, Uri url, int priority, bool trusted, PSCredentialInfo credentialInfo) { Name = name; Url = url; Priority = priority; Trusted = trusted; + CredentialInfo = credentialInfo; } #endregion @@ -37,6 +38,7 @@ public PSRepositoryInfo(string name, Uri url, int priority, bool trusted) /// /// whether the repository is trusted + /// public bool Trusted { get; } /// @@ -45,6 +47,11 @@ public PSRepositoryInfo(string name, Uri url, int priority, bool trusted) [ValidateRange(0, 50)] public int Priority { get; } + /// + /// the credential information for repository authentication + /// + public PSCredentialInfo CredentialInfo { get; } + #endregion } } diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 821f05688..4ac0e9861 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -84,6 +84,12 @@ class RegisterPSResourceRepository : PSCmdlet [ValidateRange(0, 50)] public int Priority { get; set; } = defaultPriority; + /// + /// Specifies vault and secret names as PSCredentialInfo for the repository. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public PSCredentialInfo CredentialInfo { get; set; } + /// /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. /// @@ -137,7 +143,7 @@ protected override void ProcessRecord() try { - items.Add(NameParameterSetHelper(Name, _url, Priority, Trusted)); + items.Add(NameParameterSetHelper(Name, _url, Priority, Trusted, CredentialInfo)); } catch (Exception e) { @@ -194,7 +200,7 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted) + private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition repoName = repoName.Trim(' '); @@ -208,16 +214,42 @@ private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl throw new ArgumentException("Invalid url, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); } + if (repoCredentialInfo != null) + { + bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, this); + + if (repoCredentialInfo.Credential != null) + { + if (!isSecretManagementModuleAvailable) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException($"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."), + "RepositoryCredentialSecretManagementUnavailableModule", + ErrorCategory.ResourceUnavailable, + this)); + } + else + { + Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, this); + } + } + + if (!isSecretManagementModuleAvailable) + { + WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); + } + } + WriteVerbose("All required values to add to repository provided, calling internal Add() API now"); if (!ShouldProcess(repoName, "Register repository to repository store")) { return null; } - return RepositorySettings.Add(repoName, repoUrl, repoPriority, repoTrusted); + return RepositorySettings.Add(repoName, repoUrl, repoPriority, repoTrusted, repoCredentialInfo); } - private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted) + private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) { @@ -225,14 +257,14 @@ private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, in throw new ArgumentException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"); } - return AddToRepositoryStoreHelper(repoName, repoUrl, repoPriority, repoTrusted); + return AddToRepositoryStoreHelper(repoName, repoUrl, repoPriority, repoTrusted, repoCredentialInfo); } private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repoTrusted) { Uri psGalleryUri = new Uri(PSGalleryRepoURL); WriteVerbose("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); - return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted); + return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted, repoCredentialInfo: null); } private List RepositoriesParameterSetHelper() @@ -242,11 +274,11 @@ private List RepositoriesParameterSetHelper() { if (repo.ContainsKey(PSGalleryRepoName)) { - if (repo.ContainsKey("Name") || repo.ContainsKey("Url")) + if (repo.ContainsKey("Name") || repo.ContainsKey("Url") || repo.ContainsKey("CredentialInfo")) { WriteError(new ErrorRecord( - new PSInvalidOperationException("Repository hashtable cannot contain PSGallery key with -Name and/or -URL key value pairs"), - "NotProvideNameUrlForPSGalleryRepositoriesParameterSetRegistration", + new PSInvalidOperationException("Repository hashtable cannot contain PSGallery key with -Name, -URL and/or -CredentialInfo key value pairs"), + "NotProvideNameUrlCredentialInfoForPSGalleryRepositoriesParameterSetRegistration", ErrorCategory.InvalidArgument, this)); continue; @@ -322,13 +354,25 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } + PSCredentialInfo repoCredentialInfo = null; + if (repo.ContainsKey("CredentialInfo") && + !Utils.TryCreateValidPSCredentialInfo(credentialInfoCandidate: (PSObject) repo["CredentialInfo"], + cmdletPassedIn: this, + repoCredentialInfo: out repoCredentialInfo, + errorRecord: out ErrorRecord errorRecord1)) + { + WriteError(errorRecord1); + return null; + } + try { WriteVerbose(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); return NameParameterSetHelper(repo["Name"].ToString(), repoURL, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : defaultPriority, - repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : defaultTrusted); + repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : defaultTrusted, + repoCredentialInfo); } catch (Exception e) { diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index a38f45856..5ca3f6e64 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -60,7 +60,7 @@ public static void CheckRepositoryStore() // Add PSGallery to the newly created store Uri psGalleryUri = new Uri(PSGalleryRepoURL); - Add(PSGalleryRepoName, psGalleryUri, defaultPriority, defaultTrusted); + Add(PSGalleryRepoName, psGalleryUri, defaultPriority, defaultTrusted, repoCredentialInfo: null); } // Open file (which should exist now), if cannot/is corrupted then throw error @@ -79,7 +79,7 @@ public static void CheckRepositoryStore() /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store /// /// - public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriority, bool repoTrusted) + public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { try { @@ -103,6 +103,12 @@ public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriorit new XAttribute("Trusted", repoTrusted) ); + if (repoCredentialInfo != null) + { + newElement.Add(new XAttribute(PSCredentialInfo.VaultNameAttribute, repoCredentialInfo.VaultName)); + newElement.Add(new XAttribute(PSCredentialInfo.SecretNameAttribute, repoCredentialInfo.SecretName)); + } + root.Add(newElement); // Close the file @@ -113,14 +119,14 @@ public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriorit throw new PSInvalidOperationException(String.Format("Adding to repository store failed: {0}", e.Message)); } - return new PSRepositoryInfo(repoName, repoURL, repoPriority, repoTrusted); + return new PSRepositoryInfo(repoName, repoURL, repoPriority, repoTrusted, repoCredentialInfo); } /// - /// Updates a repository name, URL, priority, or installation policy + /// Updates a repository name, URL, priority, installation policy, or credential information /// Returns: void /// - public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted) + public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo) { PSRepositoryInfo updatedRepo; try @@ -158,16 +164,50 @@ public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPrio node.Attribute("Trusted").Value = repoTrusted.ToString(); } + // A null CredentialInfo value passed in signifies that CredentialInfo was not attempted to be set. + // Set VaultName and SecretName attributes if non-null value passed in for repoCredentialInfo + if (repoCredentialInfo != null) + { + if (node.Attribute(PSCredentialInfo.VaultNameAttribute) == null) + { + node.Add(new XAttribute(PSCredentialInfo.VaultNameAttribute, repoCredentialInfo.VaultName)); + } + else + { + node.Attribute(PSCredentialInfo.VaultNameAttribute).Value = repoCredentialInfo.VaultName; + } + + if (node.Attribute(PSCredentialInfo.SecretNameAttribute) == null) + { + node.Add(new XAttribute(PSCredentialInfo.SecretNameAttribute, repoCredentialInfo.SecretName)); + } + else + { + node.Attribute(PSCredentialInfo.SecretNameAttribute).Value = repoCredentialInfo.SecretName; + } + } + // Create Uri from node Url attribute to create PSRepositoryInfo item to return. if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) { throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted URL for repo {0}", repoName)); } + // Create CredentialInfo based on new values or whether it was empty to begin with + PSCredentialInfo thisCredentialInfo = null; + if (node.Attribute(PSCredentialInfo.VaultNameAttribute)?.Value != null && + node.Attribute(PSCredentialInfo.SecretNameAttribute)?.Value != null) + { + thisCredentialInfo = new PSCredentialInfo( + node.Attribute(PSCredentialInfo.VaultNameAttribute).Value, + node.Attribute(PSCredentialInfo.SecretNameAttribute).Value); + } + updatedRepo = new PSRepositoryInfo(repoName, thisUrl, Int32.Parse(node.Attribute("Priority").Value), - Boolean.Parse(node.Attribute("Trusted").Value)); + Boolean.Parse(node.Attribute("Trusted").Value), + thisCredentialInfo); // Close the file root.Save(FullRepositoryPath); @@ -212,11 +252,17 @@ public static List Remove(string[] repoNames, out string[] err continue; } + PSCredentialInfo repoCredentialInfo = null; + if (node.Attribute("VaultName") != null & node.Attribute("SecretName") != null) + { + repoCredentialInfo = new PSCredentialInfo(node.Attribute("VaultName").Value, node.Attribute("SecretName").Value); + } removedRepos.Add( new PSRepositoryInfo(repo, new Uri(node.Attribute("Url").Value), Int32.Parse(node.Attribute("Priority").Value), - Boolean.Parse(node.Attribute("Trusted").Value))); + Boolean.Parse(node.Attribute("Trusted").Value), + repoCredentialInfo)); // Remove item from file node.Remove(); } @@ -256,15 +302,47 @@ public static List Read(string[] repoNames, out string[] error continue; } + PSCredentialInfo thisCredentialInfo; + string credentialInfoErrorMessage = $"Repository {repo.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; + // both keys are present + if (repo.Attribute(PSCredentialInfo.VaultNameAttribute) != null && repo.Attribute(PSCredentialInfo.SecretNameAttribute) != null) + { + try + { + // both values are non-empty + // = valid credentialInfo + thisCredentialInfo = new PSCredentialInfo(repo.Attribute(PSCredentialInfo.VaultNameAttribute).Value, repo.Attribute(PSCredentialInfo.SecretNameAttribute).Value); + } + catch (Exception) + { + thisCredentialInfo = null; + tempErrorList.Add(credentialInfoErrorMessage); + continue; + } + } + // both keys are missing + else if (repo.Attribute(PSCredentialInfo.VaultNameAttribute) == null && repo.Attribute(PSCredentialInfo.SecretNameAttribute) == null) + { + // = valid credentialInfo + thisCredentialInfo = null; + } + // one of the keys is missing + else + { + thisCredentialInfo = null; + tempErrorList.Add(credentialInfoErrorMessage); + continue; + } + PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(repo.Attribute("Name").Value, thisUrl, Int32.Parse(repo.Attribute("Priority").Value), - Boolean.Parse(repo.Attribute("Trusted").Value)); + Boolean.Parse(repo.Attribute("Trusted").Value), + thisCredentialInfo); foundRepos.Add(currentRepoItem); } } - else { foreach (string repo in repoNames) @@ -282,10 +360,43 @@ public static List Read(string[] repoNames, out string[] error continue; } + PSCredentialInfo thisCredentialInfo; + string credentialInfoErrorMessage = $"Repository {node.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; + // both keys are present + if (node.Attribute(PSCredentialInfo.VaultNameAttribute) != null && node.Attribute(PSCredentialInfo.SecretNameAttribute) != null) + { + try + { + // both values are non-empty + // = valid credentialInfo + thisCredentialInfo = new PSCredentialInfo(node.Attribute(PSCredentialInfo.VaultNameAttribute).Value, node.Attribute(PSCredentialInfo.SecretNameAttribute).Value); + } + catch (Exception) + { + thisCredentialInfo = null; + tempErrorList.Add(credentialInfoErrorMessage); + continue; + } + } + // both keys are missing + else if (node.Attribute(PSCredentialInfo.VaultNameAttribute) == null && node.Attribute(PSCredentialInfo.SecretNameAttribute) == null) + { + // = valid credentialInfo + thisCredentialInfo = null; + } + // one of the keys is missing + else + { + thisCredentialInfo = null; + tempErrorList.Add(credentialInfoErrorMessage); + continue; + } + PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(node.Attribute("Name").Value, thisUrl, Int32.Parse(node.Attribute("Priority").Value), - Boolean.Parse(node.Attribute("Trusted").Value)); + Boolean.Parse(node.Attribute("Trusted").Value), + thisCredentialInfo); foundRepos.Add(currentRepoItem); } diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index a2144e3e1..2ee10e5ae 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -26,6 +26,7 @@ public sealed class SetPSResourceRepository : PSCmdlet private const string RepositoriesParameterSet = "RepositoriesParameterSet"; private const int DefaultPriority = -1; private Uri _url; + #endregion #region Parameters @@ -82,7 +83,13 @@ public SwitchParameter Trusted public int Priority { get; set; } = DefaultPriority; /// - /// When specified, displays the succcessfully registered repository and its information + /// Specifies vault and secret names as PSCredentialInfo for the repository. + /// + [Parameter(ParameterSetName = NameParameterSet)] + public PSCredentialInfo CredentialInfo { get; set; } + + /// + /// When specified, displays the successfully registered repository and its information /// [Parameter] public SwitchParameter PassThru { get; set; } @@ -114,7 +121,7 @@ protected override void ProcessRecord() case NameParameterSet: try { - items.Add(UpdateRepositoryStoreHelper(Name, _url, Priority, Trusted)); + items.Add(UpdateRepositoryStoreHelper(Name, _url, Priority, Trusted, CredentialInfo)); } catch (Exception e) { @@ -155,7 +162,7 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted) + private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { if (repoUrl != null && !(repoUrl.Scheme == Uri.UriSchemeHttp || repoUrl.Scheme == Uri.UriSchemeHttps || repoUrl.Scheme == Uri.UriSchemeFtp || repoUrl.Scheme == Uri.UriSchemeFile)) { @@ -173,17 +180,49 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr // check PSGallery URL is not trying to be set if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUrl != null) { - throw new ArgumentException("The PSGallery repository has a pre-defined URL. Setting the -URL parmeter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); + throw new ArgumentException("The PSGallery repository has a pre-defined URL. Setting the -URL parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); + } + + // check PSGallery CredentialInfo is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) + { + throw new ArgumentException("The PSGallery repository does not require authentication. Setting the -CredentialInfo parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); } // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) bool? _trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); - // determine if either 1 of 3 values are attempting to be set: URL, Priority, Trusted. + if (repoCredentialInfo != null) + { + bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, this); + + if (repoCredentialInfo.Credential != null) + { + if (!isSecretManagementModuleAvailable) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException($"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."), + "RepositoryCredentialSecretManagementUnavailableModule", + ErrorCategory.ResourceUnavailable, + this)); + } + else + { + Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, this); + } + } + + if (!isSecretManagementModuleAvailable) + { + WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); + } + } + + // determine if either 1 of 4 values are attempting to be set: URL, Priority, Trusted, CredentialInfo. // if none are (i.e only Name parameter was provided, write error) - if(repoUrl == null && repoPriority == DefaultPriority && _trustedNullable == null) + if (repoUrl == null && repoPriority == DefaultPriority && _trustedNullable == null && repoCredentialInfo == null) { - throw new ArgumentException("Either URL, Priority or Trusted parameters must be requested to be set"); + throw new ArgumentException("Either URL, Priority, Trusted or CredentialInfo parameters must be requested to be set"); } WriteVerbose("All required values to set repository provided, calling internal Update() API now"); @@ -191,8 +230,7 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr { return null; } - - return RepositorySettings.Update(repoName, repoUrl, repoPriority, _trustedNullable); + return RepositorySettings.Update(repoName, repoUrl, repoPriority, _trustedNullable, repoCredentialInfo); } private List RepositoriesParameterSetHelper() @@ -248,17 +286,30 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) bool repoTrusted = false; isSet = false; - if(repo.ContainsKey("Trusted")) + if (repo.ContainsKey("Trusted")) { repoTrusted = (bool) repo["Trusted"]; isSet = true; } + + PSCredentialInfo repoCredentialInfo = null; + if (repo.ContainsKey("CredentialInfo") && + !Utils.TryCreateValidPSCredentialInfo(credentialInfoCandidate: (PSObject) repo["CredentialInfo"], + cmdletPassedIn: this, + repoCredentialInfo: out repoCredentialInfo, + errorRecord: out ErrorRecord errorRecord1)) + { + WriteError(errorRecord1); + return null; + } + try { return UpdateRepositoryStoreHelper(repo["Name"].ToString(), repoURL, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, - repoTrusted); + repoTrusted, + repoCredentialInfo); } catch (Exception e) { diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 2b5e5b9aa..30e8765c2 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,665 +1,1072 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using NuGet.Versioning; -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Runtime.InteropServices; - -namespace Microsoft.PowerShell.PowerShellGet.UtilClasses -{ - internal static class Utils - { - #region String fields - - public static readonly string[] EmptyStrArray = Array.Empty(); - - #endregion - - #region String methods - - public static string TrimQuotes(string name) - { - return name.Trim('\'', '"'); - } - - public static string QuoteName(string name) - { - bool quotesNeeded = false; - foreach (var c in name) - { - if (Char.IsWhiteSpace(c)) - { - quotesNeeded = true; - break; - } - } - - if (!quotesNeeded) - { - return name; - } - - return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; - } - - /// - /// Converts an ArrayList of object types to a string array. - /// - public static string[] GetStringArray(ArrayList list) - { - if (list == null) { return null; } - - var strArray = new string[list.Count]; - for (int i=0; i < list.Count; i++) - { - strArray[i] = list[i] as string; - } - - return strArray; - } - - public static string[] ProcessNameWildcards( - string[] pkgNames, - out string[] errorMsgs, - out bool isContainWildcard) - { - List namesWithSupportedWildcards = new List(); - List errorMsgsList = new List(); - - if (pkgNames == null) - { - isContainWildcard = true; - errorMsgs = errorMsgsList.ToArray(); - return new string[] {"*"}; - } - - isContainWildcard = false; - foreach (string name in pkgNames) - { - if (WildcardPattern.ContainsWildcardCharacters(name)) - { - if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) - { - isContainWildcard = true; - errorMsgs = new string[] {}; - return new string[] {"*"}; - } - - if (name.Contains("?") || name.Contains("[")) - { - errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); - continue; - } - - isContainWildcard = true; - namesWithSupportedWildcards.Add(name); - } - else - { - namesWithSupportedWildcards.Add(name); - } - } - - errorMsgs = errorMsgsList.ToArray(); - return namesWithSupportedWildcards.ToArray(); - } - - #endregion - - #region Version methods - - public static string GetNormalizedVersionString( - string versionString, - string prerelease) - { - // versionString may be like 1.2.0.0 or 1.2.0 - // prerelease may be null or "alpha1" - // possible passed in examples: - // versionString: "1.2.0" prerelease: "alpha1" - // versionString: "1.2.0" prerelease: "" <- doubtful though - // versionString: "1.2.0.0" prerelease: "alpha1" - // versionString: "1.2.0.0" prerelease: "" - - if (String.IsNullOrEmpty(prerelease)) - { - return versionString; - } - - int numVersionDigits = versionString.Split('.').Count(); - - if (numVersionDigits == 3) - { - // versionString: "1.2.0" prerelease: "alpha1" - return versionString + "-" + prerelease; - } - else if (numVersionDigits == 4) - { - // versionString: "1.2.0.0" prerelease: "alpha1" - return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; - } - - return versionString; - } - - public static bool TryParseVersionOrVersionRange( - string version, - out VersionRange versionRange) - { - versionRange = null; - if (version == null) { return false; } - - if (version.Trim().Equals("*")) - { - versionRange = VersionRange.All; - return true; - } - - // parse as NuGetVersion - if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) - { - versionRange = new VersionRange( - minVersion: nugetVersion, - includeMinVersion: true, - maxVersion: nugetVersion, - includeMaxVersion: true, - floatRange: null, - originalString: version); - return true; - } - - // parse as Version range - return VersionRange.TryParse(version, out versionRange); - } - - public static bool GetVersionForInstallPath( - string installedPkgPath, - bool isModule, - PSCmdlet cmdletPassedIn, - out NuGetVersion pkgNuGetVersion) - { - // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file - // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. - // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current - // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. - - // for Modules, installedPkgPath will look like this: - // ./PowerShell/Modules/test_module/3.0.0 - // for Scripts, installedPkgPath will look like this: - // ./PowerShell/Scripts/test_script.ps1 - string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); - - string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); - if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - cmdletPassedIn.WriteVerbose(String.Format( - "The {0} file found at location: {1} cannot be parsed due to {2}", - isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", - packageInfoXMLFilePath, - errorMsg)); - pkgNuGetVersion = null; - return false; - } - - string version = psGetInfo.Version.ToString(); - string prereleaseLabel = psGetInfo.PrereleaseLabel; - - if (!NuGetVersion.TryParse( - value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), - version: out pkgNuGetVersion)) - { - cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); - return false; - } - - return true; - } - - #endregion - - #region Url methods - - public static bool TryCreateValidUrl( - string uriString, - PSCmdlet cmdletPassedIn, - out Uri uriResult, - out ErrorRecord errorRecord) - { - errorRecord = null; - if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) - { - return true; - } - - Exception ex; - try - { - // This is needed for a relative path urlstring. Does not throw error for an absolute path. - var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; - if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) - { - return true; - } - - ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); - } - catch (Exception e) - { - ex = e; - } - - errorRecord = new ErrorRecord( - new PSArgumentException( - $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", - ex), - "InvalidUri", - ErrorCategory.InvalidArgument, - cmdletPassedIn); - - return false; - } - - #endregion - - #region Path methods - - public static string[] GetSubDirectories(string dirPath) - { - try - { - return Directory.GetDirectories(dirPath); - } - catch - { - return EmptyStrArray; - } - } - - public static string[] GetDirectoryFiles(string dirPath) - { - try - { - return Directory.GetFiles(dirPath); - } - catch - { - return EmptyStrArray; - } - } - - public static string GetInstalledPackageName(string pkgPath) - { - if (string.IsNullOrEmpty(pkgPath)) - { - return string.Empty; - } - - if (File.Exists(pkgPath)) - { - // ex: ./PowerShell/Scripts/TestScript.ps1 - return Path.GetFileNameWithoutExtension(pkgPath); - } - - // expecting the full version module path - // ex: ./PowerShell/Modules/TestModule/1.0.0 - return new DirectoryInfo(pkgPath).Parent.Name; - } - - public static List GetAllResourcePaths( - PSCmdlet psCmdlet, - ScopeType? scope = null) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - List resourcePaths = new List(); - - // Path search order is PSModulePath paths first, then default paths. - if (scope is null) - { - string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); - resourcePaths.AddRange(psModulePath.Split(Path.PathSeparator).ToList()); - } - - if (scope is null || scope.Value is ScopeType.CurrentUser) - { - resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); - } - - if (scope is null || scope.Value is ScopeType.AllUsers) - { - resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); - resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); - } - - // resourcePaths should now contain, eg: - // ./PowerShell/Scripts - // ./PowerShell/Modules - // add all module directories or script files - List pathsToSearch = new List(); - foreach (string path in resourcePaths) - { - psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); - - if (path.EndsWith("Scripts")) - { - try - { - pathsToSearch.AddRange(GetDirectoryFiles(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); - } - } - else - { - try - { - pathsToSearch.AddRange(GetSubDirectories(path)); - } - catch (Exception e) - { - psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); - } - } - } - - // resourcePaths should now contain eg: - // ./PowerShell/Scripts/Test-Script.ps1 - // ./PowerShell/Modules/TestModule - // need to use .ToList() to cast the IEnumerable to type List - pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); - - return pathsToSearch; - } - - // Find all potential installation paths given a scope - public static List GetAllInstallationPaths( - PSCmdlet psCmdlet, - ScopeType scope) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - // The default user scope is CurrentUser - var installationPaths = new List(); - if (scope == ScopeType.AllUsers) - { - installationPaths.Add(Path.Combine(programFilesPath, "Modules")); - installationPaths.Add(Path.Combine(programFilesPath, "Scripts")); - } - else - { - installationPaths.Add(Path.Combine(myDocumentsPath, "Modules")); - installationPaths.Add(Path.Combine(myDocumentsPath, "Scripts")); - } - - installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); - installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); - - return installationPaths; - } - - private readonly static Version PSVersion6 = new Version(6, 0); - private static void GetStandardPlatformPaths( - PSCmdlet psCmdlet, - out string myDocumentsPath, - out string programFilesPath) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; - myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); - programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); - } - else - { - // paths are the same for both Linux and macOS - myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); - programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); - } - } - - #endregion - - #region Manifest methods - - public static bool TryParseModuleManifest( - string moduleFileInfo, - PSCmdlet cmdletPassedIn, - out Hashtable parsedMetadataHashtable) - { - parsedMetadataHashtable = new Hashtable(); - bool successfullyParsed = false; - - // A script will already have the metadata parsed into the parsedMetadatahash, - // a module will still need the module manifest to be parsed. - if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) - { - // Parse the module manifest - var ast = Parser.ParseFile( - moduleFileInfo, - out Token[] tokens, - out ParseError[] errors); - - if (errors.Length > 0) - { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - return successfullyParsed; - } - else - { - var data = ast.Find(a => a is HashtableAst, false); - if (data != null) - { - parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); - successfullyParsed = true; - } - else - { - var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - } - } - } - - return successfullyParsed; - } - - #endregion - - #region Misc methods - - public static void WriteVerboseOnCmdlet( - PSCmdlet cmdlet, - string message) - { - try - { - cmdlet.InvokeCommand.InvokeScript( - script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { message }); - } - catch { } - } - - #endregion - - #region Directory and File - - /// - /// Deletes a directory and its contents. - /// Attempts to restore the directory and contents if deletion fails. - /// - public static void DeleteDirectoryWithRestore(string dirPath) - { - string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - - try - { - // Create temporary directory for restore operation if needed. - CopyDirContents(dirPath, tempDirPath, overwrite: true); - - try - { - DeleteDirectory(dirPath); - } - catch (Exception ex) - { - // Delete failed. Attempt to restore the saved directory content. - try - { - RestoreDirContents(tempDirPath, dirPath); - } - catch (Exception exx) - { - throw new PSInvalidOperationException( - $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", - ex); - } - - throw new PSInvalidOperationException( - $"Cannot remove package path {dirPath}. The previous package contents have been restored.", - ex); - } - } - finally - { - if (Directory.Exists(tempDirPath)) - { - DeleteDirectory(tempDirPath); - } - } - } - - /// - /// Deletes a directory and its contents - /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell - /// on OneDrive with 'access denied' error. - /// Later versions of .NET, with PowerShellCore, do not have this bug. - /// - public static void DeleteDirectory(string dirPath) - { - foreach (var dirFilePath in Directory.GetFiles(dirPath)) - { - if (File.GetAttributes(dirFilePath).HasFlag(FileAttributes.ReadOnly)) - { - File.SetAttributes(dirFilePath, (File.GetAttributes(dirFilePath) & ~FileAttributes.ReadOnly)); - } - - File.Delete(dirFilePath); - } - - foreach (var dirSubPath in Directory.GetDirectories(dirPath)) - { - DeleteDirectory(dirSubPath); - } - - Directory.Delete(dirPath); - } - - /// - /// Moves files from source to destination locations. - /// This is a workaround for .NET File.Move(), which fails over different file volumes. - /// - public static void MoveFiles( - string sourceFilePath, - string destFilePath, - bool overwrite = true) - { - File.Copy(sourceFilePath, destFilePath, overwrite); - File.Delete(sourceFilePath); - } - - /// - /// Moves the directory, including contents, from source to destination locations. - /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. - /// - public static void MoveDirectory( - string sourceDirPath, - string destDirPath, - bool overwrite = true) - { - CopyDirContents(sourceDirPath, destDirPath, overwrite); - DeleteDirectory(sourceDirPath); - } - - private static void CopyDirContents( - string sourceDirPath, - string destDirPath, - bool overwrite) - { - if (Directory.Exists(destDirPath)) - { - if (!overwrite) - { - throw new PSInvalidOperationException( - $"Cannot move directory because destination directory already exists: '{destDirPath}'"); - } - - DeleteDirectory(destDirPath); - } - - Directory.CreateDirectory(destDirPath); - - foreach (var filePath in Directory.GetFiles(sourceDirPath)) - { - var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); - File.Copy(filePath, destFilePath); - } - - foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) - { - var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); - CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); - } - } - - private static void RestoreDirContents( - string sourceDirPath, - string destDirPath) - { - if (!Directory.Exists(destDirPath)) - { - Directory.CreateDirectory(destDirPath); - } - - foreach (string filePath in Directory.GetFiles(sourceDirPath)) - { - string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); - if (!File.Exists(destFilePath)) - { - File.Copy(filePath, destFilePath); - } - } - - foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) - { - string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); - RestoreDirContents(srcSubDirPath, destSubDirPath); - } - } - - #endregion - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using NuGet.Versioning; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Net; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Management.Automation.Runspaces; +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + #region Utils + + internal static class Utils + { + #region String fields + + public static readonly string[] EmptyStrArray = Array.Empty(); + + #endregion + + #region String methods + + public static string TrimQuotes(string name) + { + return name.Trim('\'', '"'); + } + + public static string QuoteName(string name) + { + bool quotesNeeded = false; + foreach (var c in name) + { + if (Char.IsWhiteSpace(c)) + { + quotesNeeded = true; + break; + } + } + + if (!quotesNeeded) + { + return name; + } + + return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; + } + + /// + /// Converts an ArrayList of object types to a string array. + /// + public static string[] GetStringArray(ArrayList list) + { + if (list == null) { return null; } + + var strArray = new string[list.Count]; + for (int i=0; i < list.Count; i++) + { + strArray[i] = list[i] as string; + } + + return strArray; + } + + public static string[] ProcessNameWildcards( + string[] pkgNames, + out string[] errorMsgs, + out bool isContainWildcard) + { + List namesWithSupportedWildcards = new List(); + List errorMsgsList = new List(); + + if (pkgNames == null) + { + isContainWildcard = true; + errorMsgs = errorMsgsList.ToArray(); + return new string[] {"*"}; + } + + isContainWildcard = false; + foreach (string name in pkgNames) + { + if (WildcardPattern.ContainsWildcardCharacters(name)) + { + if (String.Equals(name, "*", StringComparison.InvariantCultureIgnoreCase)) + { + isContainWildcard = true; + errorMsgs = new string[] {}; + return new string[] {"*"}; + } + + if (name.Contains("?") || name.Contains("[")) + { + errorMsgsList.Add(String.Format("-Name with wildcards '?' and '[' are not supported for this cmdlet so Name entry: {0} will be discarded.", name)); + continue; + } + + isContainWildcard = true; + namesWithSupportedWildcards.Add(name); + } + else + { + namesWithSupportedWildcards.Add(name); + } + } + + errorMsgs = errorMsgsList.ToArray(); + return namesWithSupportedWildcards.ToArray(); + } + + #endregion + + #region Version methods + + public static string GetNormalizedVersionString( + string versionString, + string prerelease) + { + // versionString may be like 1.2.0.0 or 1.2.0 + // prerelease may be null or "alpha1" + // possible passed in examples: + // versionString: "1.2.0" prerelease: "alpha1" + // versionString: "1.2.0" prerelease: "" <- doubtful though + // versionString: "1.2.0.0" prerelease: "alpha1" + // versionString: "1.2.0.0" prerelease: "" + + if (String.IsNullOrEmpty(prerelease)) + { + return versionString; + } + + int numVersionDigits = versionString.Split('.').Count(); + + if (numVersionDigits == 3) + { + // versionString: "1.2.0" prerelease: "alpha1" + return versionString + "-" + prerelease; + } + else if (numVersionDigits == 4) + { + // versionString: "1.2.0.0" prerelease: "alpha1" + return versionString.Substring(0, versionString.LastIndexOf('.')) + "-" + prerelease; + } + + return versionString; + } + + public static bool TryParseVersionOrVersionRange( + string version, + out VersionRange versionRange) + { + versionRange = null; + if (version == null) { return false; } + + if (version.Trim().Equals("*")) + { + versionRange = VersionRange.All; + return true; + } + + // parse as NuGetVersion + if (NuGetVersion.TryParse(version, out NuGetVersion nugetVersion)) + { + versionRange = new VersionRange( + minVersion: nugetVersion, + includeMinVersion: true, + maxVersion: nugetVersion, + includeMaxVersion: true, + floatRange: null, + originalString: version); + return true; + } + + // parse as Version range + return VersionRange.TryParse(version, out versionRange); + } + + public static bool GetVersionForInstallPath( + string installedPkgPath, + bool isModule, + PSCmdlet cmdletPassedIn, + out NuGetVersion pkgNuGetVersion) + { + // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file + // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. + // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current + // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. + + // for Modules, installedPkgPath will look like this: + // ./PowerShell/Modules/test_module/3.0.0 + // for Scripts, installedPkgPath will look like this: + // ./PowerShell/Scripts/test_script.ps1 + string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); + + string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); + if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + cmdletPassedIn.WriteVerbose(String.Format( + "The {0} file found at location: {1} cannot be parsed due to {2}", + isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", + packageInfoXMLFilePath, + errorMsg)); + pkgNuGetVersion = null; + return false; + } + + string version = psGetInfo.Version.ToString(); + string prereleaseLabel = psGetInfo.PrereleaseLabel; + + if (!NuGetVersion.TryParse( + value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), + version: out pkgNuGetVersion)) + { + cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); + return false; + } + + return true; + } + + #endregion + + #region Url methods + + public static bool TryCreateValidUrl( + string uriString, + PSCmdlet cmdletPassedIn, + out Uri uriResult, + out ErrorRecord errorRecord) + { + errorRecord = null; + if (Uri.TryCreate(uriString, UriKind.Absolute, out uriResult)) + { + return true; + } + + Exception ex; + try + { + // This is needed for a relative path urlstring. Does not throw error for an absolute path. + var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; + if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) + { + return true; + } + + ex = new PSArgumentException($"Invalid Uri file path: {uriString}"); + } + catch (Exception e) + { + ex = e; + } + + errorRecord = new ErrorRecord( + new PSArgumentException( + $"The provided Uri is not valid: {uriString}. It must be of Uri Scheme: HTTP, HTTPS, FTP or a file path", + ex), + "InvalidUri", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; + } + + #endregion + + #region PSCredentialInfo methods + + public static bool TryCreateValidPSCredentialInfo( + PSObject credentialInfoCandidate, + PSCmdlet cmdletPassedIn, + out PSCredentialInfo repoCredentialInfo, + out ErrorRecord errorRecord) + { + repoCredentialInfo = null; + errorRecord = null; + + try + { + if (!string.IsNullOrEmpty((string) credentialInfoCandidate.Properties[PSCredentialInfo.VaultNameAttribute]?.Value) + && !string.IsNullOrEmpty((string) credentialInfoCandidate.Properties[PSCredentialInfo.SecretNameAttribute]?.Value)) + { + PSCredential credential = null; + if (credentialInfoCandidate.Properties[PSCredentialInfo.CredentialAttribute] != null) + { + try + { + credential = (PSCredential) credentialInfoCandidate.Properties[PSCredentialInfo.CredentialAttribute].Value; + } + catch (Exception e) + { + errorRecord = new ErrorRecord( + new PSArgumentException($"Invalid CredentialInfo {PSCredentialInfo.CredentialAttribute}", e), + "InvalidCredentialInfo", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; + } + } + + repoCredentialInfo = new PSCredentialInfo( + (string) credentialInfoCandidate.Properties[PSCredentialInfo.VaultNameAttribute].Value, + (string) credentialInfoCandidate.Properties[PSCredentialInfo.SecretNameAttribute].Value, + credential + ); + + return true; + } + else + { + errorRecord = new ErrorRecord( + new PSArgumentException($"Invalid CredentialInfo, must include non-empty {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute}, and optionally a {PSCredentialInfo.CredentialAttribute}"), + "InvalidCredentialInfo", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; + } + } + catch (Exception e) + { + errorRecord = new ErrorRecord( + new PSArgumentException("Invalid CredentialInfo values", e), + "InvalidCredentialInfo", + ErrorCategory.InvalidArgument, + cmdletPassedIn); + + return false; + } + } + + public static PSCredential GetRepositoryCredentialFromSecretManagement( + string repositoryName, + PSCredentialInfo repositoryCredentialInfo, + PSCmdlet cmdletPassedIn) + { + if (!IsSecretManagementVaultAccessible(repositoryName, repositoryCredentialInfo, cmdletPassedIn)) + { + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException($"Cannot access Microsoft.PowerShell.SecretManagement vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication."), + "RepositoryCredentialSecretManagementInaccessibleVault", + ErrorCategory.ResourceUnavailable, + cmdletPassedIn)); + return null; + } + + var results = PowerShellInvoker.InvokeScriptWithHost( + cmdlet: cmdletPassedIn, + script: @" + param ( + [string] $VaultName, + [string] $SecretName + ) + $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru + if ($null -eq $module) { + return + } + & $module ""Get-Secret"" -Name $SecretName -Vault $VaultName + ", + args: new object[] { repositoryCredentialInfo.VaultName, repositoryCredentialInfo.SecretName }, + out Exception terminatingError); + + var secretValue = (results.Count == 1) ? results[0] : null; + if (secretValue == null) + { + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Microsoft.PowerShell.SecretManagement\\Get-Secret encountered an error while reading secret \"{repositoryCredentialInfo.SecretName}\" from vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.", + innerException: terminatingError), + "RepositoryCredentialCannotGetSecretFromVault", + ErrorCategory.InvalidOperation, + cmdletPassedIn)); + } + + if (secretValue is PSCredential secretCredential) + { + return secretCredential; + } + + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSNotSupportedException($"Secret \"{repositoryCredentialInfo.SecretName}\" from vault \"{repositoryCredentialInfo.VaultName}\" has an invalid type. The only supported type is PSCredential."), + "RepositoryCredentialInvalidSecretType", + ErrorCategory.InvalidType, + cmdletPassedIn)); + + return null; + } + + public static void SaveRepositoryCredentialToSecretManagementVault( + string repositoryName, + PSCredentialInfo repositoryCredentialInfo, + PSCmdlet cmdletPassedIn) + { + if (!IsSecretManagementVaultAccessible(repositoryName, repositoryCredentialInfo, cmdletPassedIn)) + { + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException($"Cannot access Microsoft.PowerShell.SecretManagement vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication."), + "RepositoryCredentialSecretManagementInaccessibleVault", + ErrorCategory.ResourceUnavailable, + cmdletPassedIn)); + return; + } + + PowerShellInvoker.InvokeScriptWithHost( + cmdlet: cmdletPassedIn, + script: @" + param ( + [string] $VaultName, + [string] $SecretName, + [object] $SecretValue + ) + $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru + if ($null -eq $module) { + return + } + & $module ""Set-Secret"" -Name $SecretName -Vault $VaultName -Secret $SecretValue + ", + args: new object[] { repositoryCredentialInfo.VaultName, repositoryCredentialInfo.SecretName, repositoryCredentialInfo.Credential }, + out Exception terminatingError); + + if (terminatingError != null) + { + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Microsoft.PowerShell.SecretManagement\\Set-Secret encountered an error while adding secret \"{repositoryCredentialInfo.SecretName}\" to vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.", + innerException: terminatingError), + "RepositoryCredentialCannotAddSecretToVault", + ErrorCategory.InvalidOperation, + cmdletPassedIn)); + } + } + + public static bool IsSecretManagementModuleAvailable( + string repositoryName, + PSCmdlet cmdletPassedIn) + { + var results = PowerShellInvoker.InvokeScriptWithHost( + cmdlet: cmdletPassedIn, + script: @" + $module = Microsoft.PowerShell.Core\Get-Module -Name Microsoft.PowerShell.SecretManagement -ErrorAction Ignore + if ($null -eq $module) { + $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru -ErrorAction Ignore + } + if ($null -eq $module) { + return 1 + } + return 0 + ", + args: new object[] {}, + out Exception terminatingError); + + if (terminatingError != null) + { + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Cannot validate Microsoft.PowerShell.SecretManagement module setup for PSResourceRepository ({repositoryName}) authentication.", + innerException: terminatingError), + "RepositoryCredentialSecretManagementInvalidModule", + ErrorCategory.InvalidOperation, + cmdletPassedIn)); + } + + int result = (results.Count > 0) ? results[0] : 1; + return result == 0; + } + + public static bool IsSecretManagementVaultAccessible( + string repositoryName, + PSCredentialInfo repositoryCredentialInfo, + PSCmdlet cmdletPassedIn) + { + var results = PowerShellInvoker.InvokeScriptWithHost( + cmdlet: cmdletPassedIn, + script: @" + param ( + [string] $VaultName + ) + $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru + if ($null -eq $module) { + return + } + & $module ""Test-SecretVault"" -Name $VaultName + ", + args: new object[] { repositoryCredentialInfo.VaultName }, + out Exception terminatingError); + + if (terminatingError != null) + { + cmdletPassedIn.ThrowTerminatingError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Microsoft.PowerShell.SecretManagement\\Test-SecretVault encountered an error while validating the vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.", + innerException: terminatingError), + "RepositoryCredentialSecretManagementInvalidVault", + ErrorCategory.InvalidOperation, + cmdletPassedIn)); + } + + bool result = (results.Count > 0) ? results[0] : false; + return result; + } + + #endregion + + #region Path methods + + public static string[] GetSubDirectories(string dirPath) + { + try + { + return Directory.GetDirectories(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string[] GetDirectoryFiles(string dirPath) + { + try + { + return Directory.GetFiles(dirPath); + } + catch + { + return EmptyStrArray; + } + } + + public static string GetInstalledPackageName(string pkgPath) + { + if (string.IsNullOrEmpty(pkgPath)) + { + return string.Empty; + } + + if (File.Exists(pkgPath)) + { + // ex: ./PowerShell/Scripts/TestScript.ps1 + return Path.GetFileNameWithoutExtension(pkgPath); + } + + // expecting the full version module path + // ex: ./PowerShell/Modules/TestModule/1.0.0 + return new DirectoryInfo(pkgPath).Parent.Name; + } + + public static List GetAllResourcePaths( + PSCmdlet psCmdlet, + ScopeType? scope = null) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + + List resourcePaths = new List(); + + // Path search order is PSModulePath paths first, then default paths. + if (scope is null) + { + string psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); + resourcePaths.AddRange(psModulePath.Split(Path.PathSeparator).ToList()); + } + + if (scope is null || scope.Value is ScopeType.CurrentUser) + { + resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); + resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + } + + if (scope is null || scope.Value is ScopeType.AllUsers) + { + resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); + resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + + // resourcePaths should now contain, eg: + // ./PowerShell/Scripts + // ./PowerShell/Modules + // add all module directories or script files + List pathsToSearch = new List(); + foreach (string path in resourcePaths) + { + psCmdlet.WriteVerbose(string.Format("Retrieving directories in the path '{0}'", path)); + + if (path.EndsWith("Scripts")) + { + try + { + pathsToSearch.AddRange(GetDirectoryFiles(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving files from '{0}': '{1}'", path, e.Message)); + } + } + else + { + try + { + pathsToSearch.AddRange(GetSubDirectories(path)); + } + catch (Exception e) + { + psCmdlet.WriteVerbose(string.Format("Error retrieving directories from '{0}': '{1}'", path, e.Message)); + } + } + } + + // resourcePaths should now contain eg: + // ./PowerShell/Scripts/Test-Script.ps1 + // ./PowerShell/Modules/TestModule + // need to use .ToList() to cast the IEnumerable to type List + pathsToSearch = pathsToSearch.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + pathsToSearch.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); + + return pathsToSearch; + } + + // Find all potential installation paths given a scope + public static List GetAllInstallationPaths( + PSCmdlet psCmdlet, + ScopeType scope) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); + + // The default user scope is CurrentUser + var installationPaths = new List(); + if (scope == ScopeType.AllUsers) + { + installationPaths.Add(Path.Combine(programFilesPath, "Modules")); + installationPaths.Add(Path.Combine(programFilesPath, "Scripts")); + } + else + { + installationPaths.Add(Path.Combine(myDocumentsPath, "Modules")); + installationPaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + } + + installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); + + return installationPaths; + } + + private readonly static Version PSVersion6 = new Version(6, 0); + private static void GetStandardPlatformPaths( + PSCmdlet psCmdlet, + out string myDocumentsPath, + out string programFilesPath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; + myDocumentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); + programFilesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); + } + else + { + // paths are the same for both Linux and macOS + myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "powershell"); + programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); + } + } + + #endregion + + #region Manifest methods + + public static bool TryParseModuleManifest( + string moduleFileInfo, + PSCmdlet cmdletPassedIn, + out Hashtable parsedMetadataHashtable) + { + parsedMetadataHashtable = new Hashtable(); + bool successfullyParsed = false; + + // A script will already have the metadata parsed into the parsedMetadatahash, + // a module will still need the module manifest to be parsed. + if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) + { + // Parse the module manifest + var ast = Parser.ParseFile( + moduleFileInfo, + out Token[] tokens, + out ParseError[] errors); + + if (errors.Length > 0) + { + var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + return successfullyParsed; + } + else + { + var data = ast.Find(a => a is HashtableAst, false); + if (data != null) + { + parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); + successfullyParsed = true; + } + else + { + var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); + var ex = new ArgumentException(message); + var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); + cmdletPassedIn.WriteError(psdataParseError); + } + } + } + + return successfullyParsed; + } + + #endregion + + #region Misc methods + + public static void WriteVerboseOnCmdlet( + PSCmdlet cmdlet, + string message) + { + try + { + cmdlet.InvokeCommand.InvokeScript( + script: $"param ([string] $message) Write-Verbose -Verbose -Message $message", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { message }); + } + catch { } + } + + #endregion + + #region Directory and File + + /// + /// Deletes a directory and its contents. + /// Attempts to restore the directory and contents if deletion fails. + /// + public static void DeleteDirectoryWithRestore(string dirPath) + { + string tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + + try + { + // Create temporary directory for restore operation if needed. + CopyDirContents(dirPath, tempDirPath, overwrite: true); + + try + { + DeleteDirectory(dirPath); + } + catch (Exception ex) + { + // Delete failed. Attempt to restore the saved directory content. + try + { + RestoreDirContents(tempDirPath, dirPath); + } + catch (Exception exx) + { + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. An attempt to restore the old package has failed with error: {exx.Message}", + ex); + } + + throw new PSInvalidOperationException( + $"Cannot remove package path {dirPath}. The previous package contents have been restored.", + ex); + } + } + finally + { + if (Directory.Exists(tempDirPath)) + { + DeleteDirectory(tempDirPath); + } + } + } + + /// + /// Deletes a directory and its contents + /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell + /// on OneDrive with 'access denied' error. + /// Later versions of .NET, with PowerShellCore, do not have this bug. + /// + public static void DeleteDirectory(string dirPath) + { + foreach (var dirFilePath in Directory.GetFiles(dirPath)) + { + if (File.GetAttributes(dirFilePath).HasFlag(FileAttributes.ReadOnly)) + { + File.SetAttributes(dirFilePath, (File.GetAttributes(dirFilePath) & ~FileAttributes.ReadOnly)); + } + + File.Delete(dirFilePath); + } + + foreach (var dirSubPath in Directory.GetDirectories(dirPath)) + { + DeleteDirectory(dirSubPath); + } + + Directory.Delete(dirPath); + } + + /// + /// Moves files from source to destination locations. + /// This is a workaround for .NET File.Move(), which fails over different file volumes. + /// + public static void MoveFiles( + string sourceFilePath, + string destFilePath, + bool overwrite = true) + { + File.Copy(sourceFilePath, destFilePath, overwrite); + File.Delete(sourceFilePath); + } + + /// + /// Moves the directory, including contents, from source to destination locations. + /// This is a workaround for .NET Directory.Move(), which fails over different file volumes. + /// + public static void MoveDirectory( + string sourceDirPath, + string destDirPath, + bool overwrite = true) + { + CopyDirContents(sourceDirPath, destDirPath, overwrite); + DeleteDirectory(sourceDirPath); + } + + private static void CopyDirContents( + string sourceDirPath, + string destDirPath, + bool overwrite) + { + if (Directory.Exists(destDirPath)) + { + if (!overwrite) + { + throw new PSInvalidOperationException( + $"Cannot move directory because destination directory already exists: '{destDirPath}'"); + } + + DeleteDirectory(destDirPath); + } + + Directory.CreateDirectory(destDirPath); + + foreach (var filePath in Directory.GetFiles(sourceDirPath)) + { + var destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + File.Copy(filePath, destFilePath); + } + + foreach (var srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + var destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + CopyDirContents(srcSubDirPath, destSubDirPath, overwrite); + } + } + + private static void RestoreDirContents( + string sourceDirPath, + string destDirPath) + { + if (!Directory.Exists(destDirPath)) + { + Directory.CreateDirectory(destDirPath); + } + + foreach (string filePath in Directory.GetFiles(sourceDirPath)) + { + string destFilePath = Path.Combine(destDirPath, Path.GetFileName(filePath)); + if (!File.Exists(destFilePath)) + { + File.Copy(filePath, destFilePath); + } + } + + foreach (string srcSubDirPath in Directory.GetDirectories(sourceDirPath)) + { + string destSubDirPath = Path.Combine(destDirPath, Path.GetFileName(srcSubDirPath)); + RestoreDirContents(srcSubDirPath, destSubDirPath); + } + } + + #endregion + } + + #endregion + + #region PowerShellInvoker + + internal static class PowerShellInvoker + { + #region Members + + private static bool _isHostDefault = false; + private const string DefaultHost = "Default Host"; + + private static Runspace _runspace; + + #endregion Members + + #region Methods + + public static Collection InvokeScriptWithHost( + PSCmdlet cmdlet, + string script, + object[] args, + out Exception terminatingError) + { + return InvokeScriptWithHost( + cmdlet, + script, + args, + out terminatingError); + } + + public static Collection InvokeScriptWithHost( + PSCmdlet cmdlet, + string script, + object[] args, + out Exception terminatingError) + { + Collection returnCollection = new Collection(); + terminatingError = null; + + // Create the runspace if it + // doesn't exist + // is not in a workable state + // has a default host (no UI) when a non-default host is available + if (_runspace == null || + _runspace.RunspaceStateInfo.State != RunspaceState.Opened || + _isHostDefault && !cmdlet.Host.Name.Equals(DefaultHost, StringComparison.InvariantCultureIgnoreCase)) + { + if (_runspace != null) + { + _runspace.Dispose(); + } + + _isHostDefault = cmdlet.Host.Name.Equals(DefaultHost, StringComparison.InvariantCultureIgnoreCase); + + var iss = InitialSessionState.CreateDefault2(); + // We are running trusted script. + iss.LanguageMode = PSLanguageMode.FullLanguage; + // Import the current PowerShellGet module. + var modPathObjects = cmdlet.InvokeCommand.InvokeScript( + script: "(Get-Module -Name PowerShellGet).Path"); + string modPath = (modPathObjects.Count > 0 && + modPathObjects[0].BaseObject is string modPathStr) + ? modPathStr : string.Empty; + if (!string.IsNullOrEmpty(modPath)) + { + iss.ImportPSModule(new string[] { modPath }); + } + + try + { + _runspace = RunspaceFactory.CreateRunspace(cmdlet.Host, iss); + _runspace.Open(); + } + catch (Exception ex) + { + terminatingError = ex; + return returnCollection; + } + } + + using (var ps = System.Management.Automation.PowerShell.Create()) + { + ps.Runspace = _runspace; + + var cmd = new Command( + command: script, + isScript: true, + useLocalScope: true); + cmd.MergeMyResults( + myResult: PipelineResultTypes.Error | PipelineResultTypes.Warning | PipelineResultTypes.Verbose | PipelineResultTypes.Debug | PipelineResultTypes.Information, + toResult: PipelineResultTypes.Output); + ps.Commands.AddCommand(cmd); + foreach (var arg in args) + { + ps.Commands.AddArgument(arg); + } + + try + { + // Invoke the script. + var results = ps.Invoke(); + + // Extract expected output types from results pipeline. + foreach (var psItem in results) + { + if (psItem == null || psItem.BaseObject == null) { continue; } + + switch (psItem.BaseObject) + { + case ErrorRecord error: + cmdlet.WriteError(error); + break; + + case WarningRecord warning: + cmdlet.WriteWarning(warning.Message); + break; + + case VerboseRecord verbose: + cmdlet.WriteVerbose(verbose.Message); + break; + + case DebugRecord debug: + cmdlet.WriteDebug(debug.Message); + break; + + case InformationRecord info: + cmdlet.WriteInformation(info); + break; + + case T result: + returnCollection.Add(result); + break; + + case T[] resultArray: + foreach (var item in resultArray) + { + returnCollection.Add(item); + } + break; + } + } + } + catch (Exception ex) + { + terminatingError = ex; + } + } + + return returnCollection; + } + + #endregion Methods + } + + #endregion +} diff --git a/test/GetPSResourceRepository.Tests.ps1 b/test/GetPSResourceRepository.Tests.ps1 index 6d5e2e8f9..0e8777323 100644 --- a/test/GetPSResourceRepository.Tests.ps1 +++ b/test/GetPSResourceRepository.Tests.ps1 @@ -3,7 +3,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force -Describe "Test Register-PSResourceRepository" { +Describe "Test Get-PSResourceRepository" { BeforeEach { $TestRepoName1 = "testRepository" $TestRepoName2 = "testRepository2" @@ -86,6 +86,19 @@ Describe "Test Register-PSResourceRepository" { } } + It "given invalid and valid CredentialInfo, get valid ones and write error for non valid ones" { + Get-NewPSResourceRepositoryFileWithCredentialInfo + + $res = Get-PSResourceRepository -Name "localtestrepo*" -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" + + # should have successfully got the other valid/registered repositories with no error + foreach ($entry in $res) { + $entry.Name | Should -BeIn "localtestrepo1","localtestrepo2" + } + } + It "throw error and get no repositories when provided null Name" { # $errorMsg = "Cannot validate argument on parameter 'Name'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again." {Get-PSResourceRepository -Name $null -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" diff --git a/test/PSCredentialInfo.Tests.ps1 b/test/PSCredentialInfo.Tests.ps1 new file mode 100644 index 000000000..18775ef03 --- /dev/null +++ b/test/PSCredentialInfo.Tests.ps1 @@ -0,0 +1,82 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Create PSCredentialInfo with VaultName and SecretName" -tags 'CI' { + + It "Verifies VaultName is not empty" { + { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("", "testsecret") } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" + } + + It "Verifies SecretName is not empty" { + { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "") } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" + } + + It "Creates PSCredentialInfo successfully if VaultName and SecretName are non-empty" { + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + } +} + +Describe "Create PSCredentialInfo with VaultName, SecretName, and Credential" -tags 'CI' { + + It "Creates PSCredentialInfo successfully if Credential is null" { + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $null) + + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + } + + It "Creates PSCredentialInfo successfully if Credential is non-null and of type PSCredential" { + $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString "password" -AsPlainText -Force)) + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $credential) + + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + } +} + +Describe "Create PSCredentialInfo from a PSObject" -tags 'CI' { + + It "Throws if VaultName is null" { + $customObject = New-Object PSObject + { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo $customObject } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" + } + + It "Throws if SecretName is null" { + $customObject = New-Object PSObject + $customObject | Add-Member -Name "VaultName" -Value "testvault" -MemberType NoteProperty + { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo $customObject } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" + } + + It "Creates PSCredentialInfo successfully from PSObject with VaultName and SecretName" { + $properties = [PSCustomObject]@{ + VaultName = "testvault" + SecretName = "testsecret" + } + + $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties + + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + } + + It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and Credential" { + $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString "password" -AsPlainText -Force)) + $properties = [PSCustomObject]@{ + VaultName = "testvault" + SecretName = "testsecret" + Credential = [PSCredential] $credential + } + + $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties + + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.Credential.UserName | Should -Be "username" + $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" + + } +} diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index 6b83bd5d4..b0620b4d9 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -214,6 +214,25 @@ function Get-RevertPSResourceRepositoryFile { } } +function Get-NewPSResourceRepositoryFileWithCredentialInfo { + # register our own repositories with desired priority + $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PowerShellGet" + $originalXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" + $tempXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "temp.xml" + + if (Test-Path -Path $originalXmlFilePath) { + Copy-Item -Path $originalXmlFilePath -Destination $tempXmlFilePath + Remove-Item -Path $originalXmlFilePath -Force -ErrorAction Ignore + } + + if (! (Test-Path -Path $powerShellGetPath)) { + $null = New-Item -Path $powerShellGetPath -ItemType Directory -Verbose + } + + $fileToCopy = Join-Path -Path $PSScriptRoot -ChildPath "testRepositoriesWithCredentialInfo.xml" + Copy-Item -Path $fileToCopy -Destination $originalXmlFilePath -Force -Verbose +} + function Register-LocalRepos { $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" $null = New-Item $repoURLAddress -ItemType Directory -Force diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index d5a96b45b..695f540ea 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -11,14 +11,14 @@ Describe "Test Publish-PSResource" { $tmpRepoPath = Join-Path -Path $TestDrive -ChildPath "tmpRepoPath" New-Item $tmpRepoPath -Itemtype directory -Force $testRepository = "testRepository" - Register-PSResourceRepository -Name $testRepository -URL $tmpRepoPath -Priority 1 -ErrorAction SilentlyContinue - $script:repositoryPath = (get-psresourcerepository "testRepository").Url.AbsolutePath + Register-PSResourceRepository -Name $testRepository -URL $tmpRepoPath -Priority 1 -ErrorAction SilentlyContinue + $script:repositoryPath = [IO.Path]::GetFullPath((get-psresourcerepository "testRepository").Url.AbsolutePath) $tmpRepoPath2 = Join-Path -Path $TestDrive -ChildPath "tmpRepoPath2" New-Item $tmpRepoPath2 -Itemtype directory -Force $testRepository2 = "testRepository2" Register-PSResourceRepository -Name $testRepository2 -URL $tmpRepoPath2 -ErrorAction SilentlyContinue - $script:repositoryPath2 = (get-psresourcerepository "testRepository2").Url.AbsolutePath + $script:repositoryPath2 = [IO.Path]::GetFullPath((get-psresourcerepository "testRepository2").Url.AbsolutePath) # Create module $script:tmpModulesPath = Join-Path -Path $TestDrive -ChildPath "tmpModulesPath" @@ -38,7 +38,7 @@ Describe "Test Publish-PSResource" { } # Create temp destination path - $script:destinationPath = Join-Path -Path $TestDrive -ChildPath "tmpDestinationPath" + $script:destinationPath = [IO.Path]::GetFullPath((Join-Path -Path $TestDrive -ChildPath "tmpDestinationPath")) New-Item $script:destinationPath -ItemType directory -Force } AfterAll { @@ -112,7 +112,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -SkipDependenciesCheck $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath).FullName | select-object -Last 1 | Should -Be $expectedPath + (Get-ChildItem $script:repositoryPath).FullName | select-object -Last 1 | Should -Be $expectedPath } <# The following tests are related to passing in parameters to customize a nuspec. @@ -266,17 +266,14 @@ Describe "Test Publish-PSResource" { $version = "1.0.0" New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" - $tmpPath = Join-Path -Path $TestDrive -ChildPath "testtmppath" - New-Item $tmpPath -Itemtype directory -Force - - Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 -DestinationPath $tmpPath + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 -DestinationPath $script:destinationPath $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath - $expectedPath = Join-Path -Path $tmpPath -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $tmpPath).FullName | Should -Be $expectedPath + $expectedPath = Join-Path -Path $script:destinationPath -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:destinationPath).FullName | Should -Be $expectedPath } It "Publish a module and clean up properly when file in module is readonly" { diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index 712204ec9..7fd83f084 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -10,20 +10,30 @@ Describe "Test Register-PSResourceRepository" { $TestRepoName1 = "testRepository" $TestRepoName2 = "testRepository2" $TestRepoName3 = "testRepository3" + $TestRepoName4 = "testRepository4" $relativeCurrentPath = Get-Location Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" - $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + $tmpDir4Path = Join-Path -Path $TestDrive -ChildPath "tmpDir4" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path, $tmpDir4Path) Get-NewTestDirs($tmpDirPaths) + + $relativeCurrentPath = Get-Location + + $credentialInfo1 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") + $secureString = ConvertTo-SecureString "testpassword" -AsPlainText -Force + $credential = New-Object pscredential ("testusername", $secureString) + $credentialInfo2 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $credential) } AfterEach { Get-RevertPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" - $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + $tmpDir4Path = Join-Path -Path $TestDrive -ChildPath "tmpDir4" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path, $tmpDir4Path) Get-RemoveTestDirs($tmpDirPaths) } @@ -51,6 +61,16 @@ Describe "Test Register-PSResourceRepository" { $res.Priority | Should -Be 20 } + It "register repository given Name, URL, Trusted, Priority, CredentialInfo (NameParameterSet)" { + $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo1 -PassThru + $res.Name | Should -Be $TestRepoName1 + $res.URL.LocalPath | Should -Contain $tmpDir1Path + $res.Trusted | Should -Be True + $res.Priority | Should -Be 20 + $res.CredentialInfo.VaultName | Should -Be "testvault" + $res.CredentialInfo.SecretName | Should -Be "testsecret" + } + It "register repository with PSGallery parameter (PSGalleryParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName $res = Register-PSResourceRepository -PSGallery -PassThru @@ -82,7 +102,8 @@ Describe "Test Register-PSResourceRepository" { $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir1Path} $hashtable2 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} $hashtable3 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} - $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3 + $hashtable4 = @{Name = $TestRepoName4; URL = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} + $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 Register-PSResourceRepository -Repositories $arrayOfHashtables $res = Get-PSResourceRepository -Name $TestRepoName1 @@ -99,6 +120,14 @@ Describe "Test Register-PSResourceRepository" { $res3.URL.LocalPath | Should -Contain $tmpDir3Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 20 + + $res4 = Get-PSResourceRepository -Name $TestRepoName4 + $res4.URL.LocalPath | Should -Contain $tmpDir4Path + $res4.Trusted | Should -Be True + $res4.Priority | Should -Be 30 + $res4.CredentialInfo.VaultName | Should -Be "testvault" + $res4.CredentialInfo.SecretName | Should -Be "testsecret" + $res4.CredentialInfo.Credential | Should -BeNullOrEmpty } It "register repositories with Repositories parameter, psgallery style repository (RepositoriesParameterSet)" { @@ -117,7 +146,8 @@ Describe "Test Register-PSResourceRepository" { $hashtable2 = @{Name = $TestRepoName1; URL = $tmpDir1Path} $hashtable3 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} $hashtable4 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} - $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 + $hashtable5 = @{Name = $TestRepoName4; URL = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} + $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4, $hashtable5 Register-PSResourceRepository -Repositories $arrayOfHashtables @@ -140,6 +170,14 @@ Describe "Test Register-PSResourceRepository" { $res4.URL.LocalPath | Should -Contain $tmpDir3Path $res4.Trusted | Should -Be True $res4.Priority | Should -Be 20 + + $res5 = Get-PSResourceRepository -Name $TestRepoName4 + $res5.URL.LocalPath | Should -Contain $tmpDir4Path + $res5.Trusted | Should -Be True + $res5.Priority | Should -Be 30 + $res5.CredentialInfo.VaultName | Should -Be "testvault" + $res5.CredentialInfo.SecretName | Should -Be "testsecret" + $res5.CredentialInfo.Credential | Should -BeNullOrEmpty } It "not register repository when Name is provided but URL is not" { @@ -150,7 +188,7 @@ Describe "Test Register-PSResourceRepository" { {Register-PSResourceRepository -Name "" -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } - It "not register rpeository when Name is null but URL is provided" { + It "not register repository when Name is null but URL is provided" { {Register-PSResourceRepository -Name $null -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } @@ -163,13 +201,15 @@ Describe "Test Register-PSResourceRepository" { } # this error message comes from the parameter cmdlet tags (earliest point of detection) - It "not register PSGallery when PSGallery parameter provided with Name or URL" { + It "not register PSGallery when PSGallery parameter provided with Name, URL or CredentialInfo" { {Register-PSResourceRepository -PSGallery -Name $PSGalleryName -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" {Register-PSResourceRepository -PSGallery -URL $PSGalleryURL -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + {Register-PSResourceRepository -PSGallery -CredentialInfo $credentialInfo1 -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } $testCases = @{Type = "Name key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; Name=$PSGalleryName}}, - @{Type = "URL key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; URL=$PSGalleryURL}} + @{Type = "URL key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; URL=$PSGalleryURL}}, + @{Type = "CredentialInfo key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; CredentialInfo = $credentialInfo1}} It "not register incorrectly formatted PSGallery type repo among correct ones when incorrect type is " -TestCases $testCases { param($Type, $IncorrectHashTable) @@ -182,7 +222,7 @@ Describe "Test Register-PSResourceRepository" { Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUrlForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUrlCredentialInfoForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 @@ -194,10 +234,10 @@ Describe "Test Register-PSResourceRepository" { $res3.Name | Should -Be $TestRepoName3 } - $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = "PSGallery"; URL = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-URL not specified"; IncorrectHashTable = @{Name = "testRepository"}; ErrorId = "NullURLForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = "testRepository"; URL="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = $PSGalleryName; URL = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-URL not specified"; IncorrectHashTable = @{Name = $TestRepoName1}; ErrorId = "NullURLForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = $TestRepoName1; URL="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { param($Type, $IncorrectHashTable, $ErrorId) @@ -240,4 +280,19 @@ Describe "Test Register-PSResourceRepository" { $res.Name | Should -Be "localFileShareTestRepo" $res.URL.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" } + + It "prints a warning if CredentialInfo is passed in without SecretManagement module setup" { + $output = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo1 3>&1 + $output | Should -Match "Microsoft.PowerShell.SecretManagement module cannot be found" + + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res | Should -Not -BeNullOrEmpty + } + + It "throws error if CredentialInfo is passed in with Credential property without SecretManagement module setup" { + { Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + + $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore + $res | Should -BeNullOrEmpty + } } diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index 74f107ecc..ba38d53f7 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -9,20 +9,30 @@ Describe "Test Set-PSResourceRepository" { $PSGalleryURL = Get-PSGalleryLocation $TestRepoName1 = "testRepository" $TestRepoName2 = "testRepository2" + $TestRepoName3 = "testRepository3" $relativeCurrentPath = Get-Location Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" - $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + $tmpDir4Path = Join-Path -Path $TestDrive -ChildPath "tmpDir4" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path, $tmpDir4Path) Get-NewTestDirs($tmpDirPaths) + + $relativeCurrentPath = Get-Location + + $credentialInfo1 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") + $secureString = ConvertTo-SecureString "testpassword" -AsPlainText -Force + $credential = New-Object pscredential ("testusername", $secureString) + $credentialInfo2 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $credential) } AfterEach { Get-RevertPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" $tmpDir3Path = Join-Path -Path $TestDrive -ChildPath "tmpDir3" - $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path) + $tmpDir4Path = Join-Path -Path $TestDrive -ChildPath "tmpDir4" + $tmpDirPaths = @($tmpDir1Path, $tmpDir2Path, $tmpDir3Path, $tmpDir4Path) Get-RemoveTestDirs($tmpDirPaths) } @@ -34,6 +44,7 @@ Describe "Test Set-PSResourceRepository" { $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False + $res.CredentialInfo | Should -BeNullOrEmpty } It "set repository given Name and Priority parameters" { @@ -44,6 +55,7 @@ Describe "Test Set-PSResourceRepository" { $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False + $res.CredentialInfo | Should -BeNullOrEmpty } It "set repository given Name and Trusted parameters" { @@ -54,6 +66,20 @@ Describe "Test Set-PSResourceRepository" { $res.URL.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be True + $res.CredentialInfo | Should -BeNullOrEmpty + } + + It "set repository given Name and CredentialInfo parameters" { + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -CredentialInfo $credentialInfo1 + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 + $res.URL.LocalPath | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be False + $res.CredentialInfo.VaultName | Should -Be "testvault" + $res.CredentialInfo.SecretName | Should -Be "testsecret" + $res.CredentialInfo.Credential | Should -BeNullOrEmpty } It "not set repository and write error given just Name parameter" { @@ -103,12 +129,14 @@ Describe "Test Set-PSResourceRepository" { Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName3 -URL $tmpDir3Path Register-PSResourceRepository -PSGallery $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir2Path}; $hashtable2 = @{Name = $TestRepoName2; Priority = 25}; - $hashtable3 = @{Name = $PSGalleryName; Trusted = $True}; - $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3 + $hashtable3 = @{Name = $TestRepoName3; CredentialInfo = [PSCustomObject] @{ VaultName = "testvault"; SecretName = "testsecret" }}; + $hashtable4 = @{Name = $PSGalleryName; Trusted = $True}; + $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 Set-PSResourceRepository -Repositories $arrayOfHashtables $res = Get-PSResourceRepository -Name $TestRepoName1 @@ -116,18 +144,30 @@ Describe "Test Set-PSResourceRepository" { $res.URL.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False + $res.CredentialInfo | Should -BeNullOrEmpty $res2 = Get-PSResourceRepository -Name $TestRepoName2 $res2.Name | Should -Be $TestRepoName2 $res2.URL.LocalPath | Should -Contain $tmpDir2Path $res2.Priority | Should -Be 25 $res2.Trusted | Should -Be False + $res2.CredentialInfo | Should -BeNullOrEmpty - $res3 = Get-PSResourceRepository -Name $PSGalleryName - $res3.Name | Should -Be $PSGalleryName - $res3.URL | Should -Contain $PSGalleryURL + $res3 = Get-PSResourceRepository -Name $TestRepoName3 + $res3.Name | Should -Be $TestRepoName3 + $res3.URL.LocalPath | Should -Contain $tmpDir3Path $res3.Priority | Should -Be 50 - $res3.Trusted | Should -Be True + $res3.Trusted | Should -Be False + $res3.CredentialInfo.VaultName | Should -Be "testvault" + $res3.CredentialInfo.SecretName | Should -Be "testsecret" + $res3.CredentialInfo.Credential | Should -BeNullOrEmpty + + $res4 = Get-PSResourceRepository -Name $PSGalleryName + $res4.Name | Should -Be $PSGalleryName + $res4.URL | Should -Contain $PSGalleryURL + $res4.Priority | Should -Be 50 + $res4.Trusted | Should -Be True + $res4.CredentialInfo | Should -BeNullOrEmpty } It "not set and throw error for trying to set PSGallery URL (NameParameterSet)" { @@ -136,6 +176,12 @@ Describe "Test Set-PSResourceRepository" { {Set-PSResourceRepository -Name $PSGalleryName -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } + It "not set and throw error for trying to set PSGallery CredentialInfo (NameParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -PSGallery + {Set-PSResourceRepository -Name $PSGalleryName -CredentialInfo $credentialInfo1 -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + } + It "not set repository and throw error for trying to set PSGallery URL (RepositoriesParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -PSGallery @@ -166,6 +212,27 @@ Describe "Test Set-PSResourceRepository" { $res.Priority | Should -Be 50 } + It "not set repository and throw error for trying to set PSGallery CredentialInfo (RepositoriesParameterSet)" { + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -PSGallery + + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + + $hashtable1 = @{Name = $PSGalleryName; CredentialInfo = $credentialInfo1} + $hashtable2 = @{Name = $TestRepoName1; Priority = 25} + $arrayOfHashtables = $hashtable1, $hashtable2 + + Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.URL.LocalPath | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 25 + $res.Trusted | Should -Be False + $res.CredentialInfo | Should -BeNullOrEmpty + } + It "should set repository with local file share NuGet based Uri" { Register-PSResourceRepository -Name "localFileShareTestRepo" -URL $tmpDir1Path Set-PSResourceRepository -Name "localFileShareTestRepo" -URL "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" @@ -182,4 +249,23 @@ Describe "Test Set-PSResourceRepository" { $res.Priority | Should -Be 50 $res.Trusted | Should -Be False } + + It "prints a warning if CredentialInfo is passed in without SecretManagement module setup" { + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + $output = Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -CredentialInfo $credentialInfo1 3>&1 + $output | Should -Match "Microsoft.PowerShell.SecretManagement module cannot be found" + + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res | Should -Not -BeNullOrEmpty + } + + It "throws error if CredentialInfo is passed in with Credential property without SecretManagement module setup" { + { + Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -CredentialInfo $credentialInfo2 + } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + + $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore + $res.CredentialInfo | Should -BeNullOrEmpty + } } diff --git a/test/UnregisterPSResourceRepository.Tests.ps1 b/test/UnregisterPSResourceRepository.Tests.ps1 index 5b9cc9fd0..870da4717 100644 --- a/test/UnregisterPSResourceRepository.Tests.ps1 +++ b/test/UnregisterPSResourceRepository.Tests.ps1 @@ -3,7 +3,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force -Describe "Test Register-PSResourceRepository" { +Describe "Test Unregister-PSResourceRepository" { BeforeEach { $TestGalleryName = Get-PoshTestGalleryName $TestGalleryUrl = Get-PoshTestGalleryLocation diff --git a/test/testRepositoriesWithCredentialInfo.xml b/test/testRepositoriesWithCredentialInfo.xml new file mode 100644 index 000000000..2797e7bf4 --- /dev/null +++ b/test/testRepositoriesWithCredentialInfo.xml @@ -0,0 +1,7 @@ + + + + + + + From 2ccb34047a51cff9d3f5e15cab0d60ecb0cfb371 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 19 Jan 2022 14:35:41 -0500 Subject: [PATCH 121/276] rename PSResourceInfo PrereleaseLabel property and variables to Prerelease (#591) --- help/Get-PSResource.md | 2 +- src/PSGet.Format.ps1xml | 4 ++-- src/code/InstallHelper.cs | 6 +++--- src/code/InstallPSResource.cs | 4 ++-- src/code/PSResourceInfo.cs | 24 ++++++++++++------------ src/code/SavePSResource.cs | 12 ++++++------ src/code/UninstallPSResource.cs | 4 ++-- src/code/Utils.cs | 4 ++-- test/FindPSResource.Tests.ps1 | 2 +- test/GetInstalledPSResource.Tests.ps1 | 4 ++-- test/PSGetTestUtils.psm1 | 2 +- test/UpdatePSResource.Tests.ps1 | 2 +- 12 files changed, 35 insertions(+), 35 deletions(-) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index c52afbc2b..42239d789 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -135,7 +135,7 @@ PSResourceInfo : { Name PackageManagementProvider PowerShellGetFormatVersion - PrereleaseLabel + Prerelease ProjectUri PublishedDate ReleaseNotes diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml index 8baea53f1..24599c165 100644 --- a/src/PSGet.Format.ps1xml +++ b/src/PSGet.Format.ps1xml @@ -19,7 +19,7 @@ Name Version - PrereleaseLabel + Prerelease Repository Description @@ -53,7 +53,7 @@ Name $_.ParentResource.Version - $_.ParentResource.PrereleaseLabel + $_.ParentResource.Prerelease $_.ParentResource.Name $_.ParentResource.Repository diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 5094b1f02..e7d3dea58 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -347,7 +347,7 @@ private List InstallPackage( string createFullVersion = pkg.Version.ToString(); if (pkg.IsPrerelease) { - createFullVersion = pkg.Version.ToString() + "-" + pkg.PrereleaseLabel; + createFullVersion = pkg.Version.ToString() + "-" + pkg.Prerelease; } if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) @@ -449,11 +449,11 @@ private List InstallPackage( // pkgIdentity.Version.Version gets the version without metadata or release labels. string newVersion = pkgIdentity.Version.ToNormalizedString(); - string normalizedVersionNoPrereleaseLabel = newVersion; + string normalizedVersionNoPrerelease = newVersion; if (pkgIdentity.Version.IsPrerelease) { // eg: 2.0.2 - normalizedVersionNoPrereleaseLabel = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); + normalizedVersionNoPrerelease = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); } string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 88fbde63d..ac7688270 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -90,7 +90,7 @@ class InstallPSResource : PSCmdlet /// /// Prevents installing a package that contains cmdlets that already exist on the machine. /// - [Parameter] + [Parameter] public SwitchParameter NoClobber { get; set; } /// @@ -166,7 +166,7 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.Prerelease); if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index 483662a1a..5b434c055 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -247,7 +247,7 @@ public sealed class PSResourceInfo public string Name { get; } public string PackageManagementProvider { get; } public string PowerShellGetFormatVersion { get; } - public string PrereleaseLabel { get; } + public string Prerelease { get; } public Uri ProjectUri { get; } public DateTime? PublishedDate { get; } public string ReleaseNotes { get; } @@ -280,7 +280,7 @@ private PSResourceInfo( string name, string packageManagementProvider, string powershellGetFormatVersion, - string prereleaseLabel, + string prerelease, Uri projectUri, DateTime? publishedDate, string releaseNotes, @@ -306,7 +306,7 @@ private PSResourceInfo( Name = name ?? string.Empty; PackageManagementProvider = packageManagementProvider ?? string.Empty; PowerShellGetFormatVersion = powershellGetFormatVersion ?? string.Empty; - PrereleaseLabel = prereleaseLabel ?? string.Empty; + Prerelease = prerelease ?? string.Empty; ProjectUri = projectUri; PublishedDate = publishedDate; ReleaseNotes = releaseNotes ?? string.Empty; @@ -394,7 +394,7 @@ public static bool TryRead( filePath)); var additionalMetadata = GetProperty>(nameof(PSResourceInfo.AdditionalMetadata), psObjectInfo); - Version version = GetVersionInfo(psObjectInfo, additionalMetadata, out string prereleaseLabel); + Version version = GetVersionInfo(psObjectInfo, additionalMetadata, out string prerelease); psGetInfo = new PSResourceInfo( additionalMetadata: additionalMetadata, @@ -412,7 +412,7 @@ public static bool TryRead( name: GetStringProperty(nameof(PSResourceInfo.Name), psObjectInfo), packageManagementProvider: GetStringProperty(nameof(PSResourceInfo.PackageManagementProvider), psObjectInfo), powershellGetFormatVersion: GetStringProperty(nameof(PSResourceInfo.PowerShellGetFormatVersion), psObjectInfo), - prereleaseLabel: prereleaseLabel, + prerelease: prerelease, projectUri: GetProperty(nameof(PSResourceInfo.ProjectUri), psObjectInfo), publishedDate: GetProperty(nameof(PSResourceInfo.PublishedDate), psObjectInfo), releaseNotes: GetStringProperty(nameof(PSResourceInfo.ReleaseNotes), psObjectInfo), @@ -449,10 +449,10 @@ private static string GetStringProperty( private static Version GetVersionInfo( PSObject psObjectInfo, Dictionary additionalMetadata, - out string prereleaseLabel) + out string prerelease) { string versionString = GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); - prereleaseLabel = String.Empty; + prerelease = String.Empty; if (!String.IsNullOrEmpty(versionString) || additionalMetadata.TryGetValue("NormalizedVersion", out versionString)) @@ -472,7 +472,7 @@ private static Version GetVersionInfo( // versionStringParsed.Length > 1 (because string contained '-' so couldn't be 0) // versionString: "1.2.0-alpha1" pkgVersion = versionStringParsed[0]; - prereleaseLabel = versionStringParsed[1]; + prerelease = versionStringParsed[1]; } } @@ -480,7 +480,7 @@ private static Version GetVersionInfo( // parse the pkgVersion parsed out above into a System.Version object if (!Version.TryParse(pkgVersion, out Version parsedVersion)) { - prereleaseLabel = String.Empty; + prerelease = String.Empty; return null; } else @@ -491,7 +491,7 @@ private static Version GetVersionInfo( // version could not be parsed as string, it was written to XML file as a System.Version object // V3 code briefly did so, I believe so we provide support for it - prereleaseLabel = String.Empty; + prerelease = String.Empty; return GetProperty(nameof(PSResourceInfo.Version), psObjectInfo); } @@ -536,7 +536,7 @@ public static bool TryConvert( name: ParseMetadataName(metadataToParse), packageManagementProvider: null, powershellGetFormatVersion: null, - prereleaseLabel: ParsePrerelease(metadataToParse), + prerelease: ParsePrerelease(metadataToParse), projectUri: ParseMetadataProjectUri(metadataToParse), publishedDate: ParseMetadataPublishedDate(metadataToParse), releaseNotes: null, @@ -887,7 +887,7 @@ private PSObject ConvertToCustomObject() { // 1.0.0-alpha1 // 1.0.0.0 - string NormalizedVersion = IsPrerelease ? ConcatenateVersionWithPrerelease(Version.ToString(), PrereleaseLabel) : Version.ToString(); + string NormalizedVersion = IsPrerelease ? ConcatenateVersionWithPrerelease(Version.ToString(), Prerelease) : Version.ToString(); var additionalMetadata = new PSObject(); diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 97dd07ac9..a7e17e3ab 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -131,11 +131,11 @@ public string Path [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } - /// - /// Suppresses progress information. - /// - [Parameter(ParameterSetName = NameParameterSet)] - [Parameter(ParameterSetName = InputObjectParameterSet)] + /// + /// Suppresses progress information. + /// + [Parameter(ParameterSetName = NameParameterSet)] + [Parameter(ParameterSetName = InputObjectParameterSet)] public SwitchParameter Quiet { get; set; } #endregion @@ -183,7 +183,7 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.PrereleaseLabel); + string normalizedVersionString = Utils.GetNormalizedVersionString(InputObject.Version.ToString(), InputObject.Prerelease); if (!Utils.TryParseVersionOrVersionRange(normalizedVersionString, out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", normalizedVersionString, InputObject.Name); diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 05aa4e886..e52e6c622 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -113,8 +113,8 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - string inputObjectPrereleaseLabel = InputObject.PrereleaseLabel; - string inputObjectVersion = String.IsNullOrEmpty(inputObjectPrereleaseLabel) ? InputObject.Version.ToString() : Utils.GetNormalizedVersionString(versionString: InputObject.Version.ToString(), prerelease: inputObjectPrereleaseLabel); + string inputObjectPrerelease = InputObject.Prerelease; + string inputObjectVersion = String.IsNullOrEmpty(inputObjectPrerelease) ? InputObject.Version.ToString() : Utils.GetNormalizedVersionString(versionString: InputObject.Version.ToString(), prerelease: inputObjectPrerelease); if (!Utils.TryParseVersionOrVersionRange( version: inputObjectVersion, versionRange: out _versionRange)) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 30e8765c2..95bea6bc9 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -213,10 +213,10 @@ public static bool GetVersionForInstallPath( } string version = psGetInfo.Version.ToString(); - string prereleaseLabel = psGetInfo.PrereleaseLabel; + string prerelease = psGetInfo.Prerelease; if (!NuGetVersion.TryParse( - value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), + value: String.IsNullOrEmpty(prerelease) ? version : GetNormalizedVersionString(version, prerelease), version: out pkgNuGetVersion)) { cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 20290a610..602a6c823 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -215,7 +215,7 @@ Describe 'Test Find-PSResource for Module' { $resPrerelease = Find-PSResource -Name $testModuleName -Prerelease -Repository $TestGalleryName $resPrerelease.Version | Should -Be "5.2.5.0" - $resPrerelease.PrereleaseLabel | Should -Be "alpha001" + $resPrerelease.Prerelease | Should -Be "alpha001" } It "find resources, including Prerelease version resources, when given Prerelease parameter" { diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 63d44e241..986f25c59 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -117,7 +117,7 @@ $testCases = $res = Get-PSResource -Name $testModuleName -Version "5.2.5-alpha001" $res.Name | Should -Be $testModuleName $res.Version | Should -Be "5.2.5" - $res.PrereleaseLabel | Should -Be "alpha001" + $res.Prerelease | Should -Be "alpha001" } It "Get prerelease version script when version with correct prerelease label is specified" { @@ -127,6 +127,6 @@ $testCases = $res = Get-PSResource -Name $testScriptName -Version "3.0.0-alpha001" $res.Name | Should -Be $testScriptName $res.Version | Should -Be "3.0.0" - $res.PrereleaseLabel | Should -Be "alpha001" + $res.Prerelease | Should -Be "alpha001" } } diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index b0620b4d9..be7d7253a 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -574,7 +574,7 @@ function CheckForExpectedPSGetInfo $psGetInfo.Description | Should -BeLike 'This module provides a convenient way for a user to store*' $psGetInfo.IconUri | Should -BeNullOrEmpty $psGetInfo.IsPrerelease | Should -Be $True - $psGetInfo.PrereleaseLabel | Should -Be "preview2" + $psGetInfo.Prerelease | Should -Be "preview2" $psGetInfo.Includes.Cmdlet | Should -HaveCount 10 $psGetInfo.Includes.Cmdlet[0] | Should -BeExactly 'Register-SecretVault' $psGetInfo.InstalledDate.Year | Should -BeExactly 2021 diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index cb11a8b59..bd081d970 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -147,7 +147,7 @@ Describe 'Test Update-PSResource' { { if ([System.Version]$pkg.Version -gt [System.Version]"1.0.2.0") { - $pkg.PrereleaseLabel | Should -Be "alpha1" + $pkg.Prerelease | Should -Be "alpha1" $isPkgUpdated = $true } } From 83594b6b6ffa04fca55c221deb4e664cb32d0e72 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:06:43 -0800 Subject: [PATCH 122/276] Implement RequiredResourceFile and RequiredResource parameters (#592) --- src/code/InstallPSResource.cs | 234 +++++++++++++++++++++++++++-- src/code/InstallPkgParams.cs | 105 +++++++++++++ src/code/Utils.cs | 60 ++++++++ test/InstallPSResource.Tests.ps1 | 81 ++++++++++ test/TestRequiredResourceFile.json | 13 ++ 5 files changed, 477 insertions(+), 16 deletions(-) create mode 100644 src/code/InstallPkgParams.cs create mode 100644 test/TestRequiredResourceFile.json diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index ac7688270..687d89a7c 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -2,11 +2,15 @@ // Licensed under the MIT License. using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using Newtonsoft.Json; using NuGet.Versioning; using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Management.Automation; +using Microsoft.PowerShell.Commands; using Dbg = System.Diagnostics.Debug; @@ -113,6 +117,63 @@ class InstallPSResource : PSCmdlet [ValidateNotNullOrEmpty] public PSResourceInfo InputObject { get; set; } + /// + /// Installs resources based on input from a JSON file. + /// + [Parameter(ParameterSetName = RequiredResourceFileParameterSet)] + [ValidateNotNullOrEmpty] + public String RequiredResourceFile + { + get + { + return _requiredResourceFile; + } + set + { + string resolvedPath = string.Empty; + if (!string.IsNullOrWhiteSpace(value)) + { + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + } + + if (!File.Exists(resolvedPath)) + { + var exMessage = String.Format("The RequiredResourceFile does not exist. Please try specifying a path to a valid .json file"); + var ex = new ArgumentException(exMessage); + var RequiredResourceFileDoesNotExist = new ErrorRecord(ex, "RequiredResourceFileDoesNotExist", ErrorCategory.ObjectNotFound, null); + + ThrowTerminatingError(RequiredResourceFileDoesNotExist); + } + + _requiredResourceFile = resolvedPath; + } + } + + /// + /// Installs resources in a hashtable or JSON string format. + /// + [Parameter(ParameterSetName = RequiredResourceParameterSet)] + public Object RequiredResource // takes either string (json) or hashtable + { + get { return _requiredResourceHash != null ? _requiredResourceHash : (Object)_requiredResourceJson; } + + set + { + if (value is String jsonResource) + { + _requiredResourceJson = jsonResource; + } + else if (value is Hashtable hashResource) + { + _requiredResourceHash = hashResource; + } + else + { + throw new ParameterBindingException("Object is not a JSON or Hashtable"); + } + } + } + #endregion #region Members @@ -122,6 +183,9 @@ class InstallPSResource : PSCmdlet private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet"; private const string RequiredResourceParameterSet = "RequiredResourceParameterSet"; List _pathsToInstallPkg; + private string _requiredResourceFile; + private string _requiredResourceJson; + private Hashtable _requiredResourceHash; VersionRange _versionRange; InstallHelper _installHelper; @@ -161,8 +225,11 @@ protected override void ProcessRecord() ProcessInstallHelper( pkgNames: Name, + pkgVersion: _versionRange, pkgPrerelease: Prerelease, - pkgRepository: Repository); + pkgRepository: Repository, + pkgCredential: Credential, + reqResourceParams: null); break; case InputObjectParameterSet: @@ -177,24 +244,95 @@ protected override void ProcessRecord() ProcessInstallHelper( pkgNames: new string[] { InputObject.Name }, + pkgVersion: _versionRange, pkgPrerelease: InputObject.IsPrerelease, - pkgRepository: new string[]{ InputObject.Repository }); + pkgRepository: new string[]{ InputObject.Repository }, + pkgCredential: Credential, + reqResourceParams: null); break; case RequiredResourceFileParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("RequiredResourceFileParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "CommandParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); + /* json file contents should look like: + { + "Pester": { + "allowPrerelease": true, + "version": "[4.4.2,4.7.0]", + "repository": "PSGallery", + "credential": null + } + } + */ + + string requiredResourceFileStream = string.Empty; + using (StreamReader sr = new StreamReader(_requiredResourceFile)) + { + requiredResourceFileStream = sr.ReadToEnd(); + } + + Hashtable pkgsInJsonFile = null; + try + { + pkgsInJsonFile = Utils.ConvertJsonToHashtable(this, requiredResourceFileStream); + } + catch (Exception) + { + var exMessage = String.Format("Argument for parameter -RequiredResourceFile is not in proper json format. Make sure argument is either a valid json file."); + var ex = new ArgumentException(exMessage); + var RequiredResourceFileNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceFileNotInProperJsonFormat", ErrorCategory.InvalidData, null); + + ThrowTerminatingError(RequiredResourceFileNotInProperJsonFormat); + } + + RequiredResourceHelper(pkgsInJsonFile); break; case RequiredResourceParameterSet: - ThrowTerminatingError(new ErrorRecord( - new PSNotImplementedException("RequiredResourceParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."), - "CommandParameterSetNotImplementedYet", - ErrorCategory.NotImplemented, - this)); + if (!string.IsNullOrWhiteSpace(_requiredResourceJson)) + { + /* json would look like: + { + "Pester": { + "allowPrerelease": true, + "version": "[4.4.2,4.7.0]", + "repository": "PSGallery", + "credential": null + } + } + */ + + Hashtable pkgsHash = null; + try + { + pkgsHash = Utils.ConvertJsonToHashtable(this, _requiredResourceJson); + } + catch (Exception) + { + var exMessage = String.Format("Argument for parameter -RequiredResource is not in proper json format. Make sure argument is either a valid json file."); + var ex = new ArgumentException(exMessage); + var RequiredResourceFileNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceFileNotInProperJsonFormat", ErrorCategory.InvalidData, null); + + ThrowTerminatingError(RequiredResourceFileNotInProperJsonFormat); + } + + RequiredResourceHelper(pkgsHash); + } + + if (_requiredResourceHash != null) + { + /* hashtable would look like: + @{ + "Configuration" = @{ version = "[4.4.2,4.7.0]" } + "Pester" = @{ + version = "[4.4.2,4.7.0]" + repository = PSGallery + credential = $cred + prerelease = $true + } + } + */ + + RequiredResourceHelper(_requiredResourceHash); + } break; default: @@ -202,12 +340,76 @@ protected override void ProcessRecord() break; } } - + #endregion #region Methods - private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository) + private void RequiredResourceHelper(Hashtable reqResourceHash) + { + var pkgNames = reqResourceHash.Keys; + + foreach (string pkgName in pkgNames) + { + var pkgParamInfo = reqResourceHash[pkgName]; + + // Format should now be a hashtable, whether the original input format was json or hashtable + if (!(pkgParamInfo is Hashtable pkgInstallInfo)) + { + return; + } + + InstallPkgParams pkgParams = new InstallPkgParams(); + var pkgParamNames = pkgInstallInfo.Keys; + + PSCredential pkgCredential = Credential; + foreach (string paramName in pkgParamNames) + { + if (string.Equals(paramName, "credential", StringComparison.InvariantCultureIgnoreCase)) + { + WriteVerbose("Credential specified for required resource"); + pkgCredential = pkgInstallInfo[paramName] as PSCredential; + } + + pkgParams.SetProperty(paramName, pkgInstallInfo[paramName] as string, out ErrorRecord IncorrectVersionFormat); + + if (IncorrectVersionFormat != null) + { + ThrowTerminatingError(IncorrectVersionFormat); + } + } + + if (pkgParams.Scope == ScopeType.AllUsers) + { + _pathsToInstallPkg = Utils.GetAllInstallationPaths(this, pkgParams.Scope); + } + + VersionRange pkgVersion; + // If no Version specified, install latest version for the package. + // Otherwise validate Version can be parsed out successfully. + if (pkgInstallInfo["version"] == null || string.IsNullOrWhiteSpace(pkgInstallInfo["version"].ToString())) + { + pkgVersion = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(pkgInstallInfo["version"].ToString(), out pkgVersion)) + { + var exMessage = "Argument for Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(IncorrectVersionFormat); + } + + ProcessInstallHelper( + pkgNames: new string[] { pkgName }, + pkgVersion: pkgVersion, + pkgPrerelease: pkgParams.Prerelease, + pkgRepository: new string[] { pkgParams.Repository }, + pkgCredential: pkgCredential, + reqResourceParams: pkgParams); + } + } + + private void ProcessInstallHelper(string[] pkgNames, VersionRange pkgVersion, bool pkgPrerelease, string[] pkgRepository, PSCredential pkgCredential, InstallPkgParams reqResourceParams) { var inputNameToInstall = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard); if (nameContainsWildcard) @@ -244,7 +446,7 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[ var installedPkgs = _installHelper.InstallPackages( names: pkgNames, - versionRange: _versionRange, + versionRange: pkgVersion, prerelease: pkgPrerelease, repository: pkgRepository, acceptLicense: AcceptLicense, @@ -253,7 +455,7 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[ force: false, trustRepository: TrustRepository, noClobber: NoClobber, - credential: Credential, + credential: pkgCredential, asNupkg: false, includeXML: true, skipDependencyCheck: SkipDependencyCheck, diff --git a/src/code/InstallPkgParams.cs b/src/code/InstallPkgParams.cs new file mode 100644 index 000000000..20000a512 --- /dev/null +++ b/src/code/InstallPkgParams.cs @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using NuGet.Versioning; +using System; +using System.Collections; +using System.Management.Automation; + +public class InstallPkgParams +{ + public string Name { get; set; } + public VersionRange Version { get; set; } + public string Repository { get; set; } + public bool AcceptLicense { get; set; } + public bool Prerelease { get; set; } + public ScopeType Scope { get; set; } + public bool Quiet { get; set; } + public bool Reinstall { get; set; } + public bool Force { get; set; } + public bool TrustRepository { get; set; } + public bool NoClobber { get; set; } + public bool SkipDependencyCheck { get; set; } + + + + #region Private methods + + public void SetProperty(string propertyName, string propertyValue, out ErrorRecord IncorrectVersionFormat) + { + IncorrectVersionFormat = null; + switch (propertyName.ToLower()) + { + case "name": + Name = propertyValue.Trim(); + break; + + case "version": + // If no Version specified, install latest version for the package. + // Otherwise validate Version can be parsed out successfully. + VersionRange versionTmp = VersionRange.None; + if (string.IsNullOrWhiteSpace(propertyValue)) + { + Version = VersionRange.All; + } + else if (!Utils.TryParseVersionOrVersionRange(propertyValue, out versionTmp)) + { + var exMessage = "Argument for Version parameter is not in the proper format."; + var ex = new ArgumentException(exMessage); + IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null); + } + Version = versionTmp; + break; + + case "repository": + Repository = propertyValue.Trim(); + break; + + case "acceptlicense": + bool.TryParse(propertyValue, out bool acceptLicenseTmp); + AcceptLicense = acceptLicenseTmp; + break; + + case "prerelease": + bool.TryParse(propertyValue, out bool prereleaseTmp); + Prerelease = prereleaseTmp; + break; + + case "scope": + ScopeType scope = (ScopeType)Enum.Parse(typeof(ScopeType), propertyValue, ignoreCase: true); + Scope = scope; + break; + + case "quiet": + bool.TryParse(propertyValue, out bool quietTmp); + Quiet = quietTmp; + break; + + case "reinstall": + bool.TryParse(propertyValue, out bool reinstallTmp); + Reinstall = reinstallTmp; + break; + + case "trustrepository": + bool.TryParse(propertyValue, out bool trustRepositoryTmp); + TrustRepository = trustRepositoryTmp; + break; + + case "noclobber": + bool.TryParse(propertyValue, out bool noClobberTmp); + NoClobber = noClobberTmp; + break; + + case "skipdependencycheck": + bool.TryParse(propertyValue, out bool skipDependencyCheckTmp); + SkipDependencyCheck = skipDependencyCheckTmp; + break; + + default: + // write error + break; + } + } + #endregion +} \ No newline at end of file diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 95bea6bc9..54fd85e72 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -25,6 +25,47 @@ internal static class Utils public static readonly string[] EmptyStrArray = Array.Empty(); + private const string ConvertJsonToHashtableScript = @" + param ( + [string] $json + ) + + function ConvertToHash + { + param ( + [pscustomobject] $object + ) + + $output = @{} + $object | Microsoft.PowerShell.Utility\Get-Member -MemberType NoteProperty | ForEach-Object { + $name = $_.Name + $value = $object.($name) + + if ($value -is [object[]]) + { + $array = @() + $value | ForEach-Object { + $array += (ConvertToHash $_) + } + $output.($name) = $array + } + elseif ($value -is [pscustomobject]) + { + $output.($name) = (ConvertToHash $value) + } + else + { + $output.($name) = $value + } + } + + $output + } + + $customObject = Microsoft.PowerShell.Utility\ConvertFrom-Json -InputObject $json + return ConvertToHash $customObject + "; + #endregion #region String methods @@ -754,6 +795,25 @@ public static void WriteVerboseOnCmdlet( catch { } } + /// + /// Convert a json string into a hashtable object. + /// This uses custom script to perform the PSObject -> Hashtable + /// conversion, so that this works with WindowsPowerShell. + /// + public static Hashtable ConvertJsonToHashtable( + PSCmdlet cmdlet, + string json) + { + Collection results = cmdlet.InvokeCommand.InvokeScript( + script: ConvertJsonToHashtableScript, + useNewScope: true, + writeToPipeline: PipelineResultTypes.Error, + input: null, + args: new object[] { json }); + + return (results.Count == 1 && results[0] != null) ? (Hashtable)results[0].BaseObject : null; + } + #endregion #region Directory and File diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index b5cf93604..bf73e0fb2 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -11,6 +11,7 @@ Describe 'Test Install-PSResource for Module' { $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "TestModule" + $RequiredResourceJSONFileName = "TestRequiredResourceFile.json" Get-NewPSResourceRepositoryFile Register-LocalRepos } @@ -317,6 +318,86 @@ Describe 'Test Install-PSResource for Module' { $res.Name | Should -Be "TestModule" $res.Version | Should -Be "1.3.0.0" } + + It "Install modules using -RequiredResource with hashtable" { + $rrHash = @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = $TestGalleryName + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = $TestGalleryName + prerelease = "true" + } + + TestModule99 = @{ + } + } + + Install-PSResource -RequiredResource $rrHash + + $res1 = Get-Module "TestModule" -ListAvailable + $res1.Name | Should -Be "TestModule" + $res1.Version | Should -Be "1.3.0" + + $res2 = Get-Module "TestModulePrerelease" -ListAvailable + $res2.Name | Should -Be "TestModulePrerelease" + $res2.Version | Should -Be "0.0.1" + + $res3 = Get-Module "TestModule99" -ListAvailable + $res3.Name | Should -Be "TestModule99" + $res3.Version | Should -Be "0.0.5" + } + + It "Install modules using -RequiredResource with JSON string" { + $rrJSON = "{ + 'TestModule': { + 'version': '[0.0.1,1.3.0]', + 'repository': 'PoshTestGallery' + }, + 'TestModulePrerelease': { + 'version': '[0.0.0,0.0.5]', + 'repository': 'PoshTestGallery', + 'prerelease': 'true' + }, + 'TestModule99': { + } + }" + + Install-PSResource -RequiredResource $rrJSON + + $res1 = Get-Module "TestModule" -ListAvailable + $res1.Name | Should -Be "TestModule" + $res1.Version | Should -Be "1.3.0" + + $res2 = Get-Module "TestModulePrerelease" -ListAvailable + $res2.Name | Should -Be "TestModulePrerelease" + $res2.Version | Should -Be "0.0.1" + + $res3 = Get-Module "TestModule99" -ListAvailable + $res3.Name | Should -Be "TestModule99" + $res3.Version | Should -Be "0.0.5" + } + + It "Install modules using -RequiredResourceFile with JSON file" { + $rrFileJSON = ".\$RequiredResourceJSONFileName" + + Install-PSResource -RequiredResourceFile $rrFileJSON -Verbose + + $res1 = Get-Module "TestModule" -ListAvailable + $res1.Name | Should -Be "TestModule" + $res1.Version | Should -Be "1.2.0" + + $res2 = Get-Module "TestModulePrerelease" -ListAvailable + $res2.Name | Should -Be "TestModulePrerelease" + $res2.Version | Should -Be "0.0.1" + + $res3 = Get-Module "TestModule99" -ListAvailable + $res3.Name | Should -Be "TestModule99" + $res3.Version | Should -Be "0.0.5" + } } <# Temporarily commented until -Tag is implemented for this Describe block diff --git a/test/TestRequiredResourceFile.json b/test/TestRequiredResourceFile.json new file mode 100644 index 000000000..1a790c79b --- /dev/null +++ b/test/TestRequiredResourceFile.json @@ -0,0 +1,13 @@ +{ + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PoshTestGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PoshTestGallery", + "prerelease": "true" + }, + "TestModule99": { + } +} From 2f811e3936d4207e67dad793c89c2a12df9aefb1 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 27 Jan 2022 09:11:23 -0800 Subject: [PATCH 123/276] Update release build image (#600) --- .ci/ci_auto.yml | 4 ++-- .ci/ci_release.yml | 4 ++-- .ci/release.yml | 2 +- doBuild.ps1 | 20 +++++++++++++++++++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 658f10aae..78090b56d 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -32,7 +32,7 @@ stages: pool: name: 1ES demands: - - ImageOverride -equals MMS2019 + - ImageOverride -equals PSMMS2019-Secure steps: @@ -275,7 +275,7 @@ stages: pool: name: 1ES demands: - - ImageOverride -equals MMS2019 + - ImageOverride -equals PSMMS2019-Secure steps: - checkout: self diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index ce6a61901..e3865843d 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -21,7 +21,7 @@ stages: pool: name: 1ES demands: - - ImageOverride -equals MMS2019 + - ImageOverride -equals PSMMS2019-Secure steps: @@ -281,7 +281,7 @@ stages: pool: name: 1ES demands: - - ImageOverride -equals MMS2019 + - ImageOverride -equals PSMMS2019-Secure steps: - checkout: self diff --git a/.ci/release.yml b/.ci/release.yml index 6c8527990..3d73c0795 100644 --- a/.ci/release.yml +++ b/.ci/release.yml @@ -7,7 +7,7 @@ jobs: pool: name: 1ES demands: - - ImageOverride -equals MMS2019 + - ImageOverride -equals PSMMS2019-Secure displayName: ${{ parameters.displayName }} steps: diff --git a/doBuild.ps1 b/doBuild.ps1 index a2a3f7044..98f1edc08 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -50,10 +50,28 @@ function DoBuild # Build code and place it in the staging location Push-Location "${SrcPath}/code" try { + # Get dotnet.exe command path. + $dotnetCommand = Get-Command -Name 'dotnet' -ErrorAction Ignore + + # Check for dotnet for Windows (we only build on Windows platforms). + if ($null -eq $dotnetCommand) { + Write-Verbose -Verbose -Message "dotnet.exe cannot be found in current path. Looking in ProgramFiles path." + $dotnetCommandPath = Join-Path -Path $env:ProgramFiles -ChildPath "dotnet\dotnet.exe" + $dotnetCommand = Get-Command -Name $dotnetCommandPath -ErrorAction Ignore + if ($null -eq $dotnetCommand) { + throw "Dotnet.exe cannot be found: $dotnetCommandPath is unavailable for build." + } + } + + Write-Verbose -Verbose -Message "dotnet.exe command found in path: $($dotnetCommand.Path)" + + # Check dotnet version + Write-Verbose -Verbose -Message "DotNet version: $(& ($dotnetCommand) --version)" + # Build source Write-Verbose -Verbose -Message "Building with configuration: $BuildConfiguration, framework: $BuildFramework" Write-Verbose -Verbose -Message "Build location: PSScriptRoot: $PSScriptRoot, PWD: $pwd" - dotnet publish --configuration $BuildConfiguration --framework $BuildFramework --output $BuildSrcPath -warnaserror + & ($dotnetCommand) publish --configuration $BuildConfiguration --framework $BuildFramework --output $BuildSrcPath -warnaserror if ($LASTEXITCODE -ne 0) { throw "Build failed with exit code: $LASTEXITCODE" } From 37fc0281bcf84731681c7693e38794a9dfea67cb Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 27 Jan 2022 09:41:45 -0800 Subject: [PATCH 124/276] Fix Write-Error on build failure. (#601) --- doBuild.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doBuild.ps1 b/doBuild.ps1 index 98f1edc08..e5ba66e44 100644 --- a/doBuild.ps1 +++ b/doBuild.ps1 @@ -125,8 +125,8 @@ function DoBuild } } catch { - # Write-Error "dotnet build failed with error: $_" Write-Verbose -Verbose -Message "dotnet build failed with error: $_" + Write-Error "dotnet build failed with error: $_" } finally { Pop-Location From 1269e4ed58b9b9948919f4bbc718226b17040da1 Mon Sep 17 00:00:00 2001 From: Freddie Sackur Date: Thu, 3 Feb 2022 21:58:38 +0000 Subject: [PATCH 125/276] Rename params: *url to *uri (#551) Rename params *url to *uri --- build.ps1 | 2 +- help/Get-PSResourceRepository.md | 8 +- help/Register-PSResourceRepository.md | 24 ++-- help/Set-PSResourceRepository.md | 24 ++-- help/Unregister-PSResourceRepository.md | 6 +- src/PSGet.Format.ps1xml | 4 +- src/PowerShellGet.psd1 | 2 +- src/code/FindHelper.cs | 40 +++--- src/code/InstallHelper.cs | 58 ++++---- src/code/PSRepositoryInfo.cs | 8 +- src/code/PSResourceInfo.cs | 6 +- src/code/PublishPSResource.cs | 90 ++++++------- src/code/RegisterPSResourceRepository.cs | 46 +++---- src/code/RepositorySettings.cs | 46 +++---- src/code/SetPSResourceRepository.cs | 50 +++---- src/code/Utils.cs | 24 ++-- test/GetPSResourceRepository.Tests.ps1 | 22 +-- test/PSGetTestUtils.psm1 | 24 ++-- test/PublishPSResource.Tests.ps1 | 46 +++---- test/RegisterPSResourceRepository.Tests.ps1 | 126 +++++++++--------- test/SetPSResourceRepository.Tests.ps1 | 94 ++++++------- test/UnregisterPSResourceRepository.Tests.ps1 | 16 +-- test/testRepositories.xml | 6 +- test/testRepositoriesWithCredentialInfo.xml | 8 +- 24 files changed, 390 insertions(+), 390 deletions(-) diff --git a/build.ps1 b/build.ps1 index 26ea93c7b..df7e6d957 100644 --- a/build.ps1 +++ b/build.ps1 @@ -40,7 +40,7 @@ param ( [string] $BuildFramework = "netstandard2.0" ) -if ( ! ( Get-Module -ErrorAction SilentlyContinue PSPackageProject) ) { +if ( -not (Get-Module -ErrorAction SilentlyContinue PSPackageProject) -and -not (Import-Module -PassThru -ErrorAction SilentlyContinue PSPackageProject -MinimumVersion 0.1.18) ) { Install-Module -Name PSPackageProject -MinimumVersion 0.1.18 -Force } diff --git a/help/Get-PSResourceRepository.md b/help/Get-PSResourceRepository.md index 35c32e0f3..87689c67d 100644 --- a/help/Get-PSResourceRepository.md +++ b/help/Get-PSResourceRepository.md @@ -24,7 +24,7 @@ The Get-PSResourceRepository cmdlet searches for the PowerShell resource reposit ### Example 1 ``` PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 ``` @@ -34,7 +34,7 @@ This example runs the command with the 'Name' parameter being set to "PSGallery" ### Example 2 ``` PS C:\> Get-PSResourceRepository -Name "*Gallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 PSGallery https://www.powershellgallery.com/api/v2 False 50 @@ -46,7 +46,7 @@ This example runs the command with the 'Name' parameter being set to "*Gallery" ### Example 3 ``` PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 PSGallery https://www.powershellgallery.com/api/v2 False 50 @@ -58,7 +58,7 @@ This example runs the command with the 'Name' parameter being set to an array of ### Example 4 ``` PS C:\> Get-PSResourceRepository -Name "*" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 PSGallery https://www.powershellgallery.com/api/v2 False 50 diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index bf90cb349..9fb3e02e1 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -14,7 +14,7 @@ Registers a repository for PowerShell resources. ### NameParameterSet (Default) ``` -Register-PSResourceRepository [-Name] [-URL] [-Trusted] [-Priority ] [-PassThru] +Register-PSResourceRepository [-Name] [-Uri] [-Trusted] [-Priority ] [-PassThru] [-WhatIf] [-Confirm] [] ``` @@ -36,32 +36,32 @@ The Register-PSResourceRepository cmdlet registers a repository for PowerShell r These examples assume that the repository we attempt to register is not already registered on the user's machine. ### Example 1 ``` -PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -URL "https://www.powershellgallery.com/api/v2" +PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 ``` -This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `URL` value for it. +This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. ### Example 2 ``` PS C:\> Register-PSResourceRepository -PSGallery PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 ``` -This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-URL` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for URL. +This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. ### Example 3 ``` -PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; URL = "c:/code/testdir"},@{PSGallery = $True} +PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} PS C:\> Register-PSResourceRepository -Repositories $arrayOfHashtables PS C:\> Get-PSResourceRepository - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 psgettestlocal file:///c:/code/testdir False 50 @@ -149,9 +149,9 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -URL +### -Uri Specifies the location of the repository to be registered. -URL can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. +Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. ```yaml Type: String @@ -225,8 +225,8 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## NOTES Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. -Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'URL' parameters). +Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). -URL string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File +Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File ## RELATED LINKS diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index b65cabe1a..f5dd6e52f 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -14,7 +14,7 @@ Sets information for a registered repository. ### NameParameterSet (Default) ``` -Set-PSResourceRepository [-Name] [-URL ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository [-Name] [-Uri ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet @@ -30,43 +30,43 @@ These examples are run independently of each other and assume the repositories u ### Example 1 ```powershell PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -URL "c:/code/testdir" -PassThru - Name Url Trusted Priority +PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery file:///c:/code/testdir False 50 ``` -This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-URL` value of this repository by running the Set-PSResourceRepository cmdlet with the `-URL` parameter and a valid Uri scheme url. We run the Get-PSResourceRepository cmdlet again to ensure that the `-URL` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. +This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. ### Example 2 ```powershell PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 True 25 ``` -This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-URL` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. +This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. ### Example 3 ```powershell PS C:\> Get-PSResourceRepository -Name "*" - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 -PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True},@{Name = "PoshTestGallery"; URL = "c:/code/testdir"} +PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} PS C:\> Set-PSResourceRepository -Repositories $arrayOfHashtables -PassThru - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 True 50 PoshTestGallery file:///c:/code/testdir False 50 @@ -121,7 +121,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -URL +### -Uri Specifies the location of the repository to be set. ```yaml diff --git a/help/Unregister-PSResourceRepository.md b/help/Unregister-PSResourceRepository.md index 764a5eb28..0f60bff71 100644 --- a/help/Unregister-PSResourceRepository.md +++ b/help/Unregister-PSResourceRepository.md @@ -36,7 +36,7 @@ In this example, we assume the repository "PoshTestGallery" has been previously ### Example 2 ``` PS C:\> Get-PSResourceRepository - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 PSGallery https://www.powershellgallery.com/api/v2 False 50 @@ -44,7 +44,7 @@ PS C:\> Get-PSResourceRepository PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" PS C:\> Get-PSResourceRepository - Name Url Trusted Priority + Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 False 50 @@ -75,7 +75,7 @@ Passes the resource installed to the console. ```yaml Type: SwitchParameter Parameter Sets: (All) -Aliases: +Aliases: Required: False Position: Named diff --git a/src/PSGet.Format.ps1xml b/src/PSGet.Format.ps1xml index 24599c165..8d2ee44e6 100644 --- a/src/PSGet.Format.ps1xml +++ b/src/PSGet.Format.ps1xml @@ -69,7 +69,7 @@ - + @@ -77,7 +77,7 @@ Name - Url + Uri Trusted Priority diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 4a48d4cde..dcc368d03 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -46,5 +46,5 @@ See change log (CHANGELOG.md) at https://github.com/PowerShell/PowerShellGet } } - HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' + HelpInfoUri = 'http://go.microsoft.com/fwlink/?linkid=855963' } diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index e7a3d7726..916e5a793 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -41,10 +41,10 @@ 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 _psGalleryUri = "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 readonly string _poshTestGalleryUri = "https://www.poshtestgallery.com/api/v2"; private bool _isADOFeedRepository; private bool _repositoryNameContainsWildcard; @@ -134,14 +134,14 @@ public IEnumerable FindByResourceName( // 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].Url.AbsoluteUri, _psGalleryURL, StringComparison.InvariantCultureIgnoreCase)) + if (String.Equals(repositoriesToSearch[i].Uri.AbsoluteUri, _psGalleryUri, StringComparison.InvariantCultureIgnoreCase)) { // 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 - Uri psGalleryScriptsUrl = new Uri("http://www.powershellgallery.com/api/v2/items/psscript/"); - PSRepositoryInfo psGalleryScripts = new PSRepositoryInfo(_psGalleryScriptsRepoName, psGalleryScriptsUrl, repositoriesToSearch[i].Priority, trusted: false, credentialInfo: null); + Uri psGalleryScriptsUri = new Uri("http://www.powershellgallery.com/api/v2/items/psscript/"); + PSRepositoryInfo psGalleryScripts = new PSRepositoryInfo(_psGalleryScriptsRepoName, psGalleryScriptsUri, repositoriesToSearch[i].Priority, trusted: false, credentialInfo: null); if (_type == ResourceType.None) { _cmdletPassedIn.WriteVerbose("Null Type provided, so add PSGalleryScripts repository"); @@ -153,15 +153,15 @@ public IEnumerable FindByResourceName( repositoriesToSearch.Insert(i + 1, psGalleryScripts); repositoriesToSearch.RemoveAt(i); // remove PSGallery } - } - else if (String.Equals(repositoriesToSearch[i].Url.AbsoluteUri, _poshTestGalleryURL, StringComparison.InvariantCultureIgnoreCase)) + } + else if (String.Equals(repositoriesToSearch[i].Uri.AbsoluteUri, _poshTestGalleryUri, 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, trusted: false, credentialInfo: null); + Uri poshTestGalleryScriptsUri = new Uri("https://www.poshtestgallery.com/api/v2/items/psscript/"); + PSRepositoryInfo poshTestGalleryScripts = new PSRepositoryInfo(_poshTestGalleryScriptsRepoName, poshTestGalleryScriptsUri, repositoriesToSearch[i].Priority, trusted: false, credentialInfo: null); if (_type == ResourceType.None) { _cmdletPassedIn.WriteVerbose("Null Type provided, so add PoshTestGalleryScripts repository"); @@ -182,7 +182,7 @@ public IEnumerable FindByResourceName( _cmdletPassedIn.WriteVerbose(string.Format("Searching in repository {0}", repositoriesToSearch[i].Name)); foreach (var pkg in SearchFromRepository( repositoryName: repositoriesToSearch[i].Name, - repositoryUrl: repositoriesToSearch[i].Url, + repositoryUri: repositoriesToSearch[i].Uri, repositoryCredentialInfo: repositoriesToSearch[i].CredentialInfo)) { yield return pkg; @@ -196,7 +196,7 @@ public IEnumerable FindByResourceName( private IEnumerable SearchFromRepository( string repositoryName, - Uri repositoryUrl, + Uri repositoryUri, PSCredentialInfo repositoryCredentialInfo) { PackageSearchResource resourceSearch; @@ -205,9 +205,9 @@ private IEnumerable SearchFromRepository( SourceCacheContext context; // file based Uri scheme - if (repositoryUrl.Scheme == Uri.UriSchemeFile) + if (repositoryUri.Scheme == Uri.UriSchemeFile) { - FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(repositoryUrl.ToString()); + FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(repositoryUri.ToString()); resourceSearch = new LocalPackageSearchResource(localResource); resourceMetadata = new LocalPackageMetadataResource(localResource); filter = new SearchFilter(_prerelease); @@ -226,19 +226,19 @@ private IEnumerable SearchFromRepository( } // check if ADOFeed- for which searching for Name with wildcard has a different logic flow - if (repositoryUrl.ToString().Contains("pkgs.")) + if (repositoryUri.ToString().Contains("pkgs.")) { _isADOFeedRepository = true; } // HTTP, HTTPS, FTP Uri schemes (only other Uri schemes allowed by RepositorySettings.Read() API) - PackageSource source = new PackageSource(repositoryUrl.ToString()); + PackageSource source = new PackageSource(repositoryUri.ToString()); // Explicitly passed in Credential takes precedence over repository CredentialInfo if (_credential != null) { string password = new NetworkCredential(string.Empty, _credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl.ToString(), _credential.UserName, password, true, null); + source.Credentials = PackageSourceCredential.FromUserInput(repositoryUri.ToString(), _credential.UserName, password, true, null); _cmdletPassedIn.WriteVerbose("credential successfully set for repository: " + repositoryName); } else if (repositoryCredentialInfo != null) @@ -249,7 +249,7 @@ private IEnumerable SearchFromRepository( _cmdletPassedIn); string password = new NetworkCredential(string.Empty, repoCredential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repositoryUrl.ToString(), repoCredential.UserName, password, true, null); + source.Credentials = PackageSourceCredential.FromUserInput(repositoryUri.ToString(), repoCredential.UserName, password, true, null); _cmdletPassedIn.WriteVerbose("credential successfully read from vault and set for repository: " + repositoryName); } @@ -278,8 +278,8 @@ private IEnumerable SearchFromRepository( context = new SourceCacheContext(); foreach(PSResourceInfo pkg in SearchAcrossNamesInRepository( - repositoryName: String.Equals(repositoryUrl.AbsoluteUri, _psGalleryURL, StringComparison.InvariantCultureIgnoreCase) ? _psGalleryRepoName : - (String.Equals(repositoryUrl.AbsoluteUri, _poshTestGalleryURL, StringComparison.InvariantCultureIgnoreCase) ? _poshTestGalleryRepoName : repositoryName), + repositoryName: String.Equals(repositoryUri.AbsoluteUri, _psGalleryUri, StringComparison.InvariantCultureIgnoreCase) ? _psGalleryRepoName : + (String.Equals(repositoryUri.AbsoluteUri, _poshTestGalleryUri, StringComparison.InvariantCultureIgnoreCase) ? _poshTestGalleryRepoName : repositoryName), pkgSearchResource: resourceSearch, pkgMetadataResource: resourceMetadata, searchFilter: filter, @@ -467,7 +467,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( _pkgsLeftToFind.Remove(pkgName); } } - + } // if repository names did contain wildcard, we want to do an exhaustive search across all the repositories diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index e7d3dea58..a35fb1edc 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -59,7 +59,7 @@ internal class InstallHelper : PSCmdlet public InstallHelper(PSCmdlet cmdletPassedIn) { CancellationTokenSource source = new CancellationTokenSource(); - _cancellationToken = source.Token; + _cancellationToken = source.Token; _cmdletPassedIn = cmdletPassedIn; } @@ -183,7 +183,7 @@ private List ProcessRepositories( _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); // If it can't find the pkg in one repository, it'll look for it in the next repo in the list - var isLocalRepo = repo.Url.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); + var isLocalRepo = repo.Uri.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); // Finds parent packages and dependencies IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( @@ -227,7 +227,7 @@ private List ProcessRepositories( List pkgsInstalled = InstallPackage( pkgsFromRepoToInstall, repoName, - repo.Url.AbsoluteUri, + repo.Uri.AbsoluteUri, repo.CredentialInfo, credential, isLocalRepo); @@ -306,7 +306,7 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable InstallPackage( IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) string repoName, - string repoUrl, + string repoUri, PSCredentialInfo repoCredentialInfo, PSCredential credential, bool isLocalRepo) @@ -326,7 +326,7 @@ private List InstallPackage( var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator // with a mask (bitwise complement of desired attributes combination). - // TODO: check the attributes and if it's read only then set it + // TODO: check the attributes and if it's read only then set it // attribute may be inherited from the parent // TODO: are there Linux accommodations we need to consider here? dir.Attributes &= ~FileAttributes.ReadOnly; @@ -368,8 +368,8 @@ private List InstallPackage( if (isLocalRepo) { /* Download from a local repository -- this is slightly different process than from a server */ - var localResource = new FindLocalPackagesResourceV2(repoUrl); - var resource = new LocalDownloadResource(repoUrl, localResource); + var localResource = new FindLocalPackagesResourceV2(repoUri); + var resource = new LocalDownloadResource(repoUri, localResource); // Actually downloading the .nupkg from a local repo var result = resource.GetDownloadResourceResultAsync( @@ -378,7 +378,7 @@ private List InstallPackage( globalPackagesFolder: tempInstallPath, logger: NullLogger.Instance, token: _cancellationToken).GetAwaiter().GetResult(); - + // Create the package extraction context PackageExtractionContext packageExtractionContext = new PackageExtractionContext( packageSaveMode: PackageSaveMode.Nupkg, @@ -401,13 +401,13 @@ private List InstallPackage( { /* Download from a non-local repository */ // Set up NuGet API resource for download - PackageSource source = new PackageSource(repoUrl); + PackageSource source = new PackageSource(repoUri); // Explicitly passed in Credential takes precedence over repository CredentialInfo if (credential != null) { string password = new NetworkCredential(string.Empty, credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, credential.UserName, password, true, null); + source.Credentials = PackageSourceCredential.FromUserInput(repoUri, credential.UserName, password, true, null); } else if (repoCredentialInfo != null) { @@ -417,7 +417,7 @@ private List InstallPackage( _cmdletPassedIn); string password = new NetworkCredential(string.Empty, repoCredential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repoUrl, repoCredential.UserName, password, true, null); + source.Credentials = PackageSourceCredential.FromUserInput(repoUri, repoCredential.UserName, password, true, null); } var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); SourceRepository repository = new SourceRepository(source, provider); @@ -447,7 +447,7 @@ private List InstallPackage( _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); - // pkgIdentity.Version.Version gets the version without metadata or release labels. + // pkgIdentity.Version.Version gets the version without metadata or release labels. string newVersion = pkgIdentity.Version.ToNormalizedString(); string normalizedVersionNoPrerelease = newVersion; if (pkgIdentity.Version.IsPrerelease) @@ -455,7 +455,7 @@ private List InstallPackage( // eg: 2.0.2 normalizedVersionNoPrerelease = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); } - + string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); string moduleManifestVersion = string.Empty; @@ -485,7 +485,7 @@ private List InstallPackage( } else { - // PSModules: + // PSModules: /// ./Modules /// ./Scripts /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list @@ -535,9 +535,9 @@ private List InstallPackage( { CreateMetadataXMLFile(tempDirNameVersion, installPath, pkg, isModule); } - + MoveFilesIntoInstallPath( - pkg, + pkg, isModule, isLocalRepo, tempDirNameVersion, @@ -546,7 +546,7 @@ private List InstallPackage( newVersion, moduleManifestVersion, scriptPath); - + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkg.Name, installPath)); pkgsSuccessfullyInstalled.Add(pkg); } @@ -566,7 +566,7 @@ private List InstallPackage( { // Delete the temp directory and all its contents _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); - + if (Directory.Exists(tempInstallPath)) { if (!TryDeleteDirectory(tempInstallPath, out ErrorRecord errorMsg)) @@ -671,7 +671,7 @@ private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) List listOfCmdlets = new List(); foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) { - listOfCmdlets.Add(cmdletName as string); + listOfCmdlets.Add(cmdletName as string); } @@ -692,8 +692,8 @@ private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) } if (duplicateCmdlets.Any() || duplicateCmds.Any()) - { - + { + duplicateCmdlets.AddRange(duplicateCmds); var errMessage = string.Format( @@ -807,14 +807,14 @@ private bool TryDeleteDirectory( } private void MoveFilesIntoInstallPath( - PSResourceInfo pkgInfo, - bool isModule, - bool isLocalRepo, - string dirNameVersion, - string tempInstallPath, - string installPath, - string newVersion, - string moduleManifestVersion, + PSResourceInfo pkgInfo, + bool isModule, + bool isLocalRepo, + string dirNameVersion, + string tempInstallPath, + string installPath, + string newVersion, + string moduleManifestVersion, string scriptPath) { // Creating the proper installation path depending on whether pkg is a module or script diff --git a/src/code/PSRepositoryInfo.cs b/src/code/PSRepositoryInfo.cs index 294559c72..d5fbebb25 100644 --- a/src/code/PSRepositoryInfo.cs +++ b/src/code/PSRepositoryInfo.cs @@ -13,10 +13,10 @@ public sealed class PSRepositoryInfo { #region Constructor - public PSRepositoryInfo(string name, Uri url, int priority, bool trusted, PSCredentialInfo credentialInfo) + public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCredentialInfo credentialInfo) { Name = name; - Url = url; + Uri = uri; Priority = priority; Trusted = trusted; CredentialInfo = credentialInfo; @@ -32,9 +32,9 @@ public PSRepositoryInfo(string name, Uri url, int priority, bool trusted, PSCred public string Name { get; } /// - /// the Url for the repository + /// the Uri for the repository /// - public Uri Url { get; } + public Uri Uri { get; } /// /// whether the repository is trusted diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index 5b434c055..6d1523cc4 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -218,10 +218,10 @@ public sealed class PSCommandResourceInfo public PSCommandResourceInfo(string name, PSResourceInfo parentResource) { Name = name; - ParentResource = parentResource; + ParentResource = parentResource; } - #endregion + #endregion } #endregion @@ -512,7 +512,7 @@ public static bool TryConvert( } try - { + { var typeInfo = ParseMetadataType(metadataToParse, repositoryName, type, out ArrayList commandNames, out ArrayList dscResourceNames); var resourceHashtable = new Hashtable(); resourceHashtable.Add(nameof(PSResourceInfo.Includes.Command), new PSObject(commandNames)); diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 8428020a8..b4acd8455 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -121,7 +121,7 @@ public string DestinationPath [Parameter] [ValidateNotNullOrEmpty] public SwitchParameter SkipDependenciesCheck { get; set; } - + /// /// Specifies a proxy server for the request, rather than a direct connection to the internet resource. /// @@ -227,7 +227,7 @@ protected override void ProcessRecord() return; } - // remove '.ps1' extension from file name + // remove '.ps1' extension from file name _pkgName = pkgFileOrDir.Name.Remove(pkgFileOrDir.Name.Length - 4); } else @@ -235,7 +235,7 @@ protected override void ProcessRecord() _pkgName = pkgFileOrDir.Name; resourceFilePath = System.IO.Path.Combine(_path, _pkgName + ".psd1"); - // Validate that there's a module manifest + // Validate that there's a module manifest if (!File.Exists(resourceFilePath)) { var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", resourceFilePath); @@ -246,7 +246,7 @@ protected override void ProcessRecord() return; } - // validate that the module manifest has correct data + // validate that the module manifest has correct data if (!IsValidModuleManifest(resourceFilePath)) { return; @@ -268,7 +268,7 @@ protected override void ProcessRecord() WriteError(ErrorCreatingTempDir); return; - } + } } try @@ -315,15 +315,15 @@ protected override void ProcessRecord() return; } - string repositoryUrl = repository.Url.AbsoluteUri; + string repositoryUri = repository.Uri.AbsoluteUri; // Check if dependencies already exist within the repo if: - // 1) the resource to publish has dependencies and + // 1) the resource to publish has dependencies and // 2) the -SkipDependenciesCheck flag is not passed in if (dependencies != null && !SkipDependenciesCheck) { // If error gets thrown, exit process record - if (!CheckDependenciesExist(dependencies, repositoryUrl)) + if (!CheckDependenciesExist(dependencies, repositoryUri)) { return; } @@ -401,7 +401,7 @@ protected override void ProcessRecord() } // This call does not throw any exceptions, but it will write unsuccessful responses to the console - PushNupkg(outputNupkgDir, repository.Name, repositoryUrl); + PushNupkg(outputNupkgDir, repository.Name, repositoryUri); } finally @@ -423,7 +423,7 @@ private bool IsValidModuleManifest(string moduleManifestPath) { // use PowerShell cmdlet Test-ModuleManifest // TODO: Test-ModuleManifest will throw an error if RequiredModules specifies a module that does not exist - // locally on the machine. Consider adding a -Syntax param to Test-ModuleManifest so that it only checks that + // locally on the machine. Consider adding a -Syntax param to Test-ModuleManifest so that it only checks that // the syntax is correct. In build/release pipelines for example, the modules listed under RequiredModules may // not be locally available, but we still want to allow the user to publish. var results = pwsh.AddCommand("Test-ModuleManifest").AddParameter("Path", moduleManifestPath).Invoke(); @@ -433,7 +433,7 @@ private bool IsValidModuleManifest(string moduleManifestPath) var message = string.Empty; if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Author)) { - message = "No author was provided in the module manifest. The module manifest must specify a version, author and description."; + message = "No author was provided in the module manifest. The module manifest must specify a version, author and description."; } else if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Description)) { @@ -493,7 +493,7 @@ private string CreateNuspec( XmlElement metadataElement = doc.CreateElement("metadata", nameSpaceUri); Dictionary metadataElementsDictionary = new Dictionary(); - + // id is mandatory metadataElementsDictionary.Add("id", _pkgName); @@ -506,11 +506,11 @@ private string CreateNuspec( { version = parsedMetadataHash["version"].ToString(); } - else + else { // no version is specified for the nuspec var message = "There is no package version specified. Please specify a version before publishing."; - var ex = new ArgumentException(message); + var ex = new ArgumentException(message); var NoVersionFound = new ErrorRecord(ex, "NoVersionFound", ErrorCategory.InvalidArgument, null); WriteError(NoVersionFound); @@ -527,7 +527,7 @@ private string CreateNuspec( { if (psData.ContainsKey("Prerelease") && psData["Prerelease"] is string preReleaseVersion) { - version = string.Format(@"{0}-{1}", version, preReleaseVersion); + version = string.Format(@"{0}-{1}", version, preReleaseVersion); } if (psData.ContainsKey("Tags") && psData["Tags"] is Array manifestTags) { @@ -546,7 +546,7 @@ private string CreateNuspec( { metadataElementsDictionary.Add("version", _pkgVersion.ToNormalizedString()); } - + if (parsedMetadataHash.ContainsKey("author")) { metadataElementsDictionary.Add("authors", parsedMetadataHash["author"].ToString().Trim()); @@ -560,8 +560,8 @@ private string CreateNuspec( // defaults to false var requireLicenseAcceptance = parsedMetadataHash.ContainsKey("requirelicenseacceptance") ? parsedMetadataHash["requirelicenseacceptance"].ToString().ToLower().Trim() : "false"; - metadataElementsDictionary.Add("requireLicenseAcceptance", requireLicenseAcceptance); - + metadataElementsDictionary.Add("requireLicenseAcceptance", requireLicenseAcceptance); + if (parsedMetadataHash.ContainsKey("description")) { metadataElementsDictionary.Add("description", parsedMetadataHash["description"].ToString().Trim()); @@ -629,7 +629,7 @@ private string CreateNuspec( */ - + foreach (var key in metadataElementsDictionary.Keys) { if (metadataElementsDictionary.TryGetValue(key, out string elementInnerText)) @@ -663,7 +663,7 @@ private string CreateNuspec( } metadataElement.AppendChild(dependenciesElement); } - + packageElement.AppendChild(metadataElement); doc.AppendChild(packageElement); @@ -693,8 +693,8 @@ private Hashtable ParseRequiredModules(Hashtable parsedMetadataHash) var dependenciesHash = new Hashtable(); if (LanguagePrimitives.TryConvertTo(requiredModules, out Hashtable[] moduleList)) { - // instead of returning an array of hashtables, - // loop through the array and add each element of + // instead of returning an array of hashtables, + // loop through the array and add each element of foreach (Hashtable hash in moduleList) { dependenciesHash.Add(hash["ModuleName"], hash["ModuleVersion"]); @@ -720,7 +720,7 @@ .GUID abf490023 - 9128 - 4323 - sdf9a - jf209888ajkl .AUTHOR Jane Doe .COMPANYNAME Microsoft .COPYRIGHT - .TAGS Windows MacOS + .TAGS Windows MacOS #> <# @@ -736,8 +736,8 @@ Example cmdlet here // We're retrieving all the comments within a script and grabbing all the key/value pairs // because there's no standard way to create metadata for a script. Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); - - // parse comments out + + // parse comments out Parser.ParseFile( filePath, out System.Management.Automation.Language.Token[] tokens, @@ -758,12 +758,12 @@ Example cmdlet here { if (token.Kind == TokenKind.Comment) { - // expecting only one or two comments + // expecting only one or two comments var commentText = token.Text; parsedComments.AddRange(commentText.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries) ); } } - + foreach (var line in parsedComments) { if (line.StartsWith(".")) @@ -777,14 +777,14 @@ Example cmdlet here } } } - + return parsedMetadataHash; } - - private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUrl) + + private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUri) { - // Check to see that all dependencies are in the repository - // Searches for each dependency in the repository the pkg is being pushed to, + // Check to see that all dependencies are in the repository + // Searches for each dependency in the repository the pkg is being pushed to, // If the dependency is not there, error foreach (var dependency in dependencies.Keys) { @@ -792,7 +792,7 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUrl var depName = new[] { (string)dependency }; var depVersion = (string)dependencies[dependency]; var type = new[] { "module", "script" }; - var repository = new[] { repositoryUrl }; + var repository = new[] { repositoryUri }; // Search for and return the dependency if it's in the repository. // TODO: When find is complete, uncomment beginFindHelper method below (resourceNameParameterHelper) @@ -801,7 +801,7 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUrl List dependencyFound = null; if (dependencyFound == null || !dependencyFound.Any()) { - var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryUrl); + var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryUri); var ex = new ArgumentException(message); // System.ArgumentException vs PSArgumentException var dependencyNotFound = new ErrorRecord(ex, "DependencyNotFound", ErrorCategory.ObjectNotFound, null); @@ -842,17 +842,17 @@ private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFil return success; } - private void PushNupkg(string outputNupkgDir, string repoName, string repoUrl) + private void PushNupkg(string outputNupkgDir, string repoName, string repoUri) { - // Push the nupkg to the appropriate repository - // Pkg version is parsed from .ps1 file or .psd1 file + // Push the nupkg to the appropriate repository + // Pkg version is parsed from .ps1 file or .psd1 file var fullNupkgFile = System.IO.Path.Combine(outputNupkgDir, _pkgName + "." + _pkgVersion.ToNormalizedString() + ".nupkg"); // The PSGallery uses the v2 protocol still and publishes to a slightly different endpoint: - // "https://www.powershellgallery.com/api/v2/package" - // Until the PSGallery is moved onto the NuGet v3 server protocol, we'll modify the repository url + // "https://www.powershellgallery.com/api/v2/package" + // Until the PSGallery is moved onto the NuGet v3 server protocol, we'll modify the repository uri // to accommodate for the approprate publish location. - string publishLocation = repoUrl.EndsWith("/v2", StringComparison.OrdinalIgnoreCase) ? repoUrl + "/package" : repoUrl; + string publishLocation = repoUri.EndsWith("/v2", StringComparison.OrdinalIgnoreCase) ? repoUri + "/package" : repoUri; var settings = NuGet.Configuration.Settings.LoadDefaultSettings(null, null, null); ILogger log = new NuGetLogger(); @@ -870,7 +870,7 @@ private void PushNupkg(string outputNupkgDir, string repoName, string repoUrl) timeoutSeconds: 0, disableBuffering: false, noSymbols: false, - noServiceEndpoint: false, // enable server endpoint + noServiceEndpoint: false, // enable server endpoint skipDuplicate: false, // if true-- if a package and version already exists, skip it and continue with the next package in the push, if any. logger: log // nuget logger ).GetAwaiter().GetResult(); @@ -879,7 +879,7 @@ private void PushNupkg(string outputNupkgDir, string repoName, string repoUrl) { // look in PS repo for how httpRequestExceptions are handled - // Unfortunately there is no response message are no status codes provided with the exception and no + // Unfortunately there is no response message are no status codes provided with the exception and no var ex = new ArgumentException(String.Format("Repository '{0}': {1}", repoName, e.Message)); if (e.Message.Contains("401")) { @@ -925,12 +925,12 @@ private void PushNupkg(string outputNupkgDir, string repoName, string repoUrl) if (success) { - WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUrl)); + WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUri)); } else { - WriteVerbose(string.Format("Not able to publish resource to '{0}'", repoUrl)); - } + WriteVerbose(string.Format("Not able to publish resource to '{0}'", repoUri)); + } } } diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 4ac0e9861..9ca9434d1 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -27,13 +27,13 @@ class RegisterPSResourceRepository : PSCmdlet #region Members private readonly string PSGalleryRepoName = "PSGallery"; - private readonly string PSGalleryRepoURL = "https://www.powershellgallery.com/api/v2"; + private readonly string PSGalleryRepoUri = "https://www.powershellgallery.com/api/v2"; private const int defaultPriority = 50; private const bool defaultTrusted = false; private const string NameParameterSet = "NameParameterSet"; private const string PSGalleryParameterSet = "PSGalleryParameterSet"; private const string RepositoriesParameterSet = "RepositoriesParameterSet"; - private Uri _url; + private Uri _uri; #endregion @@ -51,7 +51,7 @@ class RegisterPSResourceRepository : PSCmdlet /// [Parameter(Mandatory = true, Position = 1, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] - public string URL { get; set; } + public string Uri { get; set; } /// /// When specified, registers PSGallery repository. @@ -123,7 +123,7 @@ protected override void BeginProcessing() ErrorCategory.NotImplemented, this)); } - + RepositorySettings.CheckRepositoryStore(); } protected override void ProcessRecord() @@ -133,9 +133,9 @@ protected override void ProcessRecord() switch (ParameterSetName) { case NameParameterSet: - if (!Utils.TryCreateValidUrl(uriString: URL, + if (!Utils.TryCreateValidUri(uriString: Uri, cmdletPassedIn: this, - uriResult: out _url, + uriResult: out _uri, errorRecord: out ErrorRecord errorRecord)) { ThrowTerminatingError(errorRecord); @@ -143,7 +143,7 @@ protected override void ProcessRecord() try { - items.Add(NameParameterSetHelper(Name, _url, Priority, Trusted, CredentialInfo)); + items.Add(NameParameterSetHelper(Name, _uri, Priority, Trusted, CredentialInfo)); } catch (Exception e) { @@ -200,7 +200,7 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) + private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition repoName = repoName.Trim(' '); @@ -209,9 +209,9 @@ private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); } - if (repoUrl == null || !(repoUrl.Scheme == Uri.UriSchemeHttp || repoUrl.Scheme == Uri.UriSchemeHttps || repoUrl.Scheme == Uri.UriSchemeFtp || repoUrl.Scheme == Uri.UriSchemeFile)) + if (repoUri == null || !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) { - throw new ArgumentException("Invalid url, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); + throw new ArgumentException("Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); } if (repoCredentialInfo != null) @@ -246,10 +246,10 @@ private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUrl return null; } - return RepositorySettings.Add(repoName, repoUrl, repoPriority, repoTrusted, repoCredentialInfo); + return RepositorySettings.Add(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); } - private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) + private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) { @@ -257,12 +257,12 @@ private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUrl, in throw new ArgumentException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"); } - return AddToRepositoryStoreHelper(repoName, repoUrl, repoPriority, repoTrusted, repoCredentialInfo); + return AddToRepositoryStoreHelper(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); } private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repoTrusted) { - Uri psGalleryUri = new Uri(PSGalleryRepoURL); + Uri psGalleryUri = new Uri(PSGalleryRepoUri); WriteVerbose("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted, repoCredentialInfo: null); } @@ -274,11 +274,11 @@ private List RepositoriesParameterSetHelper() { if (repo.ContainsKey(PSGalleryRepoName)) { - if (repo.ContainsKey("Name") || repo.ContainsKey("Url") || repo.ContainsKey("CredentialInfo")) + if (repo.ContainsKey("Name") || repo.ContainsKey("Uri") || repo.ContainsKey("CredentialInfo")) { WriteError(new ErrorRecord( - new PSInvalidOperationException("Repository hashtable cannot contain PSGallery key with -Name, -URL and/or -CredentialInfo key value pairs"), - "NotProvideNameUrlCredentialInfoForPSGalleryRepositoriesParameterSetRegistration", + new PSInvalidOperationException("Repository hashtable cannot contain PSGallery key with -Name, -Uri and/or -CredentialInfo key value pairs"), + "NotProvideNameUriCredentialInfoForPSGalleryRepositoriesParameterSetRegistration", ErrorCategory.InvalidArgument, this)); continue; @@ -335,19 +335,19 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } - if (!repo.ContainsKey("Url") || String.IsNullOrEmpty(repo["Url"].ToString())) + if (!repo.ContainsKey("Uri") || String.IsNullOrEmpty(repo["Uri"].ToString())) { WriteError(new ErrorRecord( - new PSInvalidOperationException("Repository url cannot be null"), - "NullURLForRepositoriesParameterSetRegistration", + new PSInvalidOperationException("Repository Uri cannot be null"), + "NullUriForRepositoriesParameterSetRegistration", ErrorCategory.InvalidArgument, this)); return null; } - if (!Utils.TryCreateValidUrl(uriString: repo["Url"].ToString(), + if (!Utils.TryCreateValidUri(uriString: repo["Uri"].ToString(), cmdletPassedIn: this, - uriResult: out Uri repoURL, + uriResult: out Uri repoUri, errorRecord: out ErrorRecord errorRecord)) { WriteError(errorRecord); @@ -369,7 +369,7 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) { WriteVerbose(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); return NameParameterSetHelper(repo["Name"].ToString(), - repoURL, + repoUri, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : defaultPriority, repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : defaultTrusted, repoCredentialInfo); diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 5ca3f6e64..b622bbe8e 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -23,7 +23,7 @@ internal static class RepositorySettings // File name for a user's repository store file is 'PSResourceRepository.xml' // The repository store file's location is currently only at '%LOCALAPPDATA%\PowerShellGet' for the user account. private const string PSGalleryRepoName = "PSGallery"; - private const string PSGalleryRepoURL = "https://www.powershellgallery.com/api/v2"; + private const string PSGalleryRepoUri = "https://www.powershellgallery.com/api/v2"; private const int defaultPriority = 50; private const bool defaultTrusted = false; private const string RepositoryFileName = "PSResourceRepository.xml"; @@ -59,7 +59,7 @@ public static void CheckRepositoryStore() } // Add PSGallery to the newly created store - Uri psGalleryUri = new Uri(PSGalleryRepoURL); + Uri psGalleryUri = new Uri(PSGalleryRepoUri); Add(PSGalleryRepoName, psGalleryUri, defaultPriority, defaultTrusted, repoCredentialInfo: null); } @@ -79,7 +79,7 @@ public static void CheckRepositoryStore() /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store /// /// - public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) + public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { try { @@ -98,7 +98,7 @@ public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriorit XElement newElement = new XElement( "Repository", new XAttribute("Name", repoName), - new XAttribute("Url", repoURL), + new XAttribute("Uri", repoUri), new XAttribute("Priority", repoPriority), new XAttribute("Trusted", repoTrusted) ); @@ -119,14 +119,14 @@ public static PSRepositoryInfo Add(string repoName, Uri repoURL, int repoPriorit throw new PSInvalidOperationException(String.Format("Adding to repository store failed: {0}", e.Message)); } - return new PSRepositoryInfo(repoName, repoURL, repoPriority, repoTrusted, repoCredentialInfo); + return new PSRepositoryInfo(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); } /// - /// Updates a repository name, URL, priority, installation policy, or credential information + /// Updates a repository name, Uri, priority, installation policy, or credential information /// Returns: void /// - public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo) + public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo) { PSRepositoryInfo updatedRepo; try @@ -143,11 +143,11 @@ public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPrio // Get root of XDocument (XElement) var root = doc.Root; - // A null URL value passed in signifies the URL was not attempted to be set. - // So only set Url attribute if non-null value passed in for repoUrl - if (repoURL != null) + // A null Uri value passed in signifies the Uri was not attempted to be set. + // So only set Uri attribute if non-null value passed in for repoUri + if (repoUri != null) { - node.Attribute("Url").Value = repoURL.AbsoluteUri; + node.Attribute("Uri").Value = repoUri.AbsoluteUri; } // A negative Priority value passed in signifies the Priority value was not attempted to be set. @@ -187,10 +187,10 @@ public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPrio } } - // Create Uri from node Url attribute to create PSRepositoryInfo item to return. - if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) + // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. + if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted URL for repo {0}", repoName)); + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); } // Create CredentialInfo based on new values or whether it was empty to begin with @@ -204,7 +204,7 @@ public static PSRepositoryInfo Update(string repoName, Uri repoURL, int repoPrio } updatedRepo = new PSRepositoryInfo(repoName, - thisUrl, + thisUri, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); @@ -259,7 +259,7 @@ public static List Remove(string[] repoNames, out string[] err } removedRepos.Add( new PSRepositoryInfo(repo, - new Uri(node.Attribute("Url").Value), + new Uri(node.Attribute("Uri").Value), Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), repoCredentialInfo)); @@ -270,7 +270,7 @@ public static List Remove(string[] repoNames, out string[] err // Close the file root.Save(FullRepositoryPath); errorList = tempErrorList.ToArray(); - + return removedRepos; } @@ -296,9 +296,9 @@ public static List Read(string[] repoNames, out string[] error // iterate through the doc foreach (XElement repo in doc.Descendants("Repository")) { - if (!Uri.TryCreate(repo.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) + if (!Uri.TryCreate(repo.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) { - tempErrorList.Add(String.Format("Unable to read incorrectly formatted URL for repo {0}", repo.Attribute("Name").Value)); + tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repo.Attribute("Name").Value)); continue; } @@ -335,7 +335,7 @@ public static List Read(string[] repoNames, out string[] error } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(repo.Attribute("Name").Value, - thisUrl, + thisUri, Int32.Parse(repo.Attribute("Priority").Value), Boolean.Parse(repo.Attribute("Trusted").Value), thisCredentialInfo); @@ -353,10 +353,10 @@ public static List Read(string[] repoNames, out string[] error foreach (var node in doc.Descendants("Repository").Where(e => nameWildCardPattern.IsMatch(e.Attribute("Name").Value))) { repoMatch = true; - if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out Uri thisUrl)) + if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) { //debug statement - tempErrorList.Add(String.Format("Unable to read incorrectly formatted URL for repo {0}", node.Attribute("Name").Value)); + tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", node.Attribute("Name").Value)); continue; } @@ -393,7 +393,7 @@ public static List Read(string[] repoNames, out string[] error } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(node.Attribute("Name").Value, - thisUrl, + thisUri, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 2ee10e5ae..1adcd83ae 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -25,7 +25,7 @@ public sealed class SetPSResourceRepository : PSCmdlet private const string NameParameterSet = "NameParameterSet"; private const string RepositoriesParameterSet = "RepositoriesParameterSet"; private const int DefaultPriority = -1; - private Uri _url; + private Uri _uri; #endregion @@ -44,7 +44,7 @@ public sealed class SetPSResourceRepository : PSCmdlet /// [Parameter(ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] - public string URL { get; set; } + public string Uri { get; set; } /// /// Specifies a hashtable of repositories and is used to register multiple repositories at once. @@ -105,10 +105,10 @@ protected override void BeginProcessing() protected override void ProcessRecord() { - if (MyInvocation.BoundParameters.ContainsKey(nameof(URL))) + if (MyInvocation.BoundParameters.ContainsKey(nameof(Uri))) { - bool isUrlValid = Utils.TryCreateValidUrl(URL, this, out _url, out ErrorRecord errorRecord); - if (!isUrlValid) + bool isUriValid = Utils.TryCreateValidUri(Uri, this, out _uri, out ErrorRecord errorRecord); + if (!isUriValid) { ThrowTerminatingError(errorRecord); } @@ -121,7 +121,7 @@ protected override void ProcessRecord() case NameParameterSet: try { - items.Add(UpdateRepositoryStoreHelper(Name, _url, Priority, Trusted, CredentialInfo)); + items.Add(UpdateRepositoryStoreHelper(Name, _uri, Priority, Trusted, CredentialInfo)); } catch (Exception e) { @@ -162,11 +162,11 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUrl, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) + private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { - if (repoUrl != null && !(repoUrl.Scheme == Uri.UriSchemeHttp || repoUrl.Scheme == Uri.UriSchemeHttps || repoUrl.Scheme == Uri.UriSchemeFtp || repoUrl.Scheme == Uri.UriSchemeFile)) + if (repoUri != null && !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) { - throw new ArgumentException("Invalid url, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); + throw new ArgumentException("Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); } // check repoName can't contain * or just be whitespace @@ -177,16 +177,16 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); } - // check PSGallery URL is not trying to be set - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUrl != null) + // check PSGallery Uri is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUri != null) { - throw new ArgumentException("The PSGallery repository has a pre-defined URL. Setting the -URL parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); + throw new ArgumentException("The PSGallery repository has a pre-defined Uri. Setting the -Uri parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); } // check PSGallery CredentialInfo is not trying to be set if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) { - throw new ArgumentException("The PSGallery repository does not require authentication. Setting the -CredentialInfo parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); + throw new ArgumentException("The PSGallery repository does not require authentication. Setting the -CredentialInfo parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); } // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) @@ -218,11 +218,11 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr } } - // determine if either 1 of 4 values are attempting to be set: URL, Priority, Trusted, CredentialInfo. + // determine if either 1 of 4 values are attempting to be set: Uri, Priority, Trusted, CredentialInfo. // if none are (i.e only Name parameter was provided, write error) - if (repoUrl == null && repoPriority == DefaultPriority && _trustedNullable == null && repoCredentialInfo == null) + if (repoUri == null && repoPriority == DefaultPriority && _trustedNullable == null && repoCredentialInfo == null) { - throw new ArgumentException("Either URL, Priority, Trusted or CredentialInfo parameters must be requested to be set"); + throw new ArgumentException("Either Uri, Priority, Trusted or CredentialInfo parameters must be requested to be set"); } WriteVerbose("All required values to set repository provided, calling internal Update() API now"); @@ -230,7 +230,7 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr { return null; } - return RepositorySettings.Update(repoName, repoUrl, repoPriority, _trustedNullable, repoCredentialInfo); + return RepositorySettings.Update(repoName, repoUri, repoPriority, _trustedNullable, repoCredentialInfo); } private List RepositoriesParameterSetHelper() @@ -261,22 +261,22 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) { WriteVerbose(String.Format("Parsing through repository: {0}", repo["Name"])); - Uri repoURL = null; - if (repo.ContainsKey("Url")) + Uri repoUri = null; + if (repo.ContainsKey("Uri")) { - if (String.IsNullOrEmpty(repo["Url"].ToString())) + if (String.IsNullOrEmpty(repo["Uri"].ToString())) { WriteError(new ErrorRecord( - new PSInvalidOperationException("Repository url cannot be null if provided"), - "NullURLForRepositoriesParameterSetUpdate", + new PSInvalidOperationException("Repository Uri cannot be null if provided"), + "NullUriForRepositoriesParameterSetUpdate", ErrorCategory.InvalidArgument, this)); return null; } - if (!Utils.TryCreateValidUrl(uriString: repo["Url"].ToString(), + if (!Utils.TryCreateValidUri(uriString: repo["Uri"].ToString(), cmdletPassedIn: this, - uriResult: out repoURL, + uriResult: out repoUri, errorRecord: out ErrorRecord errorRecord)) { WriteError(errorRecord); @@ -306,7 +306,7 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) try { return UpdateRepositoryStoreHelper(repo["Name"].ToString(), - repoURL, + repoUri, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, repoTrusted, repoCredentialInfo); diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 54fd85e72..d11722a1c 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -156,9 +156,9 @@ public static string[] ProcessNameWildcards( errorMsgs = errorMsgsList.ToArray(); return namesWithSupportedWildcards.ToArray(); } - + #endregion - + #region Version methods public static string GetNormalizedVersionString( @@ -269,9 +269,9 @@ public static bool GetVersionForInstallPath( #endregion - #region Url methods + #region Uri methods - public static bool TryCreateValidUrl( + public static bool TryCreateValidUri( string uriString, PSCmdlet cmdletPassedIn, out Uri uriResult, @@ -286,7 +286,7 @@ public static bool TryCreateValidUrl( Exception ex; try { - // This is needed for a relative path urlstring. Does not throw error for an absolute path. + // This is needed for a relative path Uri string. Does not throw error for an absolute path. var filePath = cmdletPassedIn.SessionState.Path.GetResolvedPSPathFromPSPath(uriString)[0].Path; if (Uri.TryCreate(filePath, UriKind.Absolute, out uriResult)) { @@ -596,7 +596,7 @@ public static string GetInstalledPackageName(string pkgPath) // ex: ./PowerShell/Scripts/TestScript.ps1 return Path.GetFileNameWithoutExtension(pkgPath); } - + // expecting the full version module path // ex: ./PowerShell/Modules/TestModule/1.0.0 return new DirectoryInfo(pkgPath).Parent.Name; @@ -625,7 +625,7 @@ public static List GetAllResourcePaths( resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); } - + if (scope is null || scope.Value is ScopeType.AllUsers) { resourcePaths.Add(Path.Combine(programFilesPath, "Modules")); @@ -740,7 +740,7 @@ public static bool TryParseModuleManifest( // a module will still need the module manifest to be parsed. if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) { - // Parse the module manifest + // Parse the module manifest var ast = Parser.ParseFile( moduleFileInfo, out Token[] tokens, @@ -1059,8 +1059,8 @@ public static Collection InvokeScriptWithHost( ps.Runspace = _runspace; var cmd = new Command( - command: script, - isScript: true, + command: script, + isScript: true, useLocalScope: true); cmd.MergeMyResults( myResult: PipelineResultTypes.Error | PipelineResultTypes.Warning | PipelineResultTypes.Verbose | PipelineResultTypes.Debug | PipelineResultTypes.Information, @@ -1070,7 +1070,7 @@ public static Collection InvokeScriptWithHost( { ps.Commands.AddArgument(arg); } - + try { // Invoke the script. @@ -1102,7 +1102,7 @@ public static Collection InvokeScriptWithHost( case InformationRecord info: cmdlet.WriteInformation(info); break; - + case T result: returnCollection.Add(result); break; diff --git a/test/GetPSResourceRepository.Tests.ps1 b/test/GetPSResourceRepository.Tests.ps1 index 0e8777323..68b494293 100644 --- a/test/GetPSResourceRepository.Tests.ps1 +++ b/test/GetPSResourceRepository.Tests.ps1 @@ -25,16 +25,16 @@ Describe "Test Get-PSResourceRepository" { } It "get single already registered repo" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $res = Get-PSResourceRepository -Name $TestRepoName1 $res | Should -Not -BeNullOrEmpty $res.Name | Should -Be $TestRepoName1 } It "get all repositories matching single wildcard name" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path - Register-PSResourceRepository -Name $TestRepoName3 -URL $tmpDir3Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -Uri $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName3 -Uri $tmpDir3Path $res = Get-PSResourceRepository -Name "testReposit*" foreach ($entry in $res) { $entry.Name | Should -Match "testReposit" @@ -42,9 +42,9 @@ Describe "Test Get-PSResourceRepository" { } It "get all repositories matching multiple wildcard names" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path - Register-PSResourceRepository -Name "MyGallery" -URL $tmpDir3Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -Uri $tmpDir2Path + Register-PSResourceRepository -Name "MyGallery" -Uri $tmpDir3Path $res = Get-PSResourceRepository -Name "testReposit*","*Gallery" foreach ($entry in $res) { @@ -53,8 +53,8 @@ Describe "Test Get-PSResourceRepository" { } It "get all repositories matching multiple valid names provided" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Register-PSResourceRepository -Name "MyGallery" -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Register-PSResourceRepository -Name "MyGallery" -Uri $tmpDir2Path $res = Get-PSResourceRepository -Name $TestRepoName1,"MyGallery" foreach ($entry in $res) { @@ -73,8 +73,8 @@ Describe "Test Get-PSResourceRepository" { It "given invalid and valid Names, get valid ones and write error for non valid ones" { $nonRegisteredRepoName = "nonRegisteredRepository" - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -Uri $tmpDir2Path $res = Get-PSResourceRepository -Name $TestRepoName1,$nonRegisteredRepoName,$TestRepoName2 -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index be7d7253a..8982e6af7 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -234,21 +234,21 @@ function Get-NewPSResourceRepositoryFileWithCredentialInfo { } function Register-LocalRepos { - $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" - $null = New-Item $repoURLAddress -ItemType Directory -Force + $repoUriAddress = Join-Path -Path $TestDrive -ChildPath "testdir" + $null = New-Item $repoUriAddress -ItemType Directory -Force $localRepoParams = @{ Name = "psgettestlocal" - URL = $repoURLAddress + Uri = $repoUriAddress Priority = 40 Trusted = $false } Register-PSResourceRepository @localRepoParams - $repoURLAddress2 = Join-Path -Path $TestDrive -ChildPath "testdir2" - $null = New-Item $repoURLAddress2 -ItemType Directory -Force + $repoUriAddress2 = Join-Path -Path $TestDrive -ChildPath "testdir2" + $null = New-Item $repoUriAddress2 -ItemType Directory -Force $localRepoParams2 = @{ Name = "psgettestlocal2" - URL = $repoURLAddress2 + Uri = $repoUriAddress2 Priority = 50 Trusted = $false } @@ -384,22 +384,22 @@ function Get-ModuleResourcePublishedToLocalRepoTestDrive } function Register-LocalRepos { - $repoURLAddress = Join-Path -Path $TestDrive -ChildPath "testdir" - $null = New-Item $repoURLAddress -ItemType Directory -Force + $repoUriAddress = Join-Path -Path $TestDrive -ChildPath "testdir" + $null = New-Item $repoUriAddress -ItemType Directory -Force $localRepoParams = @{ Name = "psgettestlocal" - URL = $repoURLAddress + Uri = $repoUriAddress Priority = 40 Trusted = $false } Register-PSResourceRepository @localRepoParams - $repoURLAddress2 = Join-Path -Path $TestDrive -ChildPath "testdir2" - $null = New-Item $repoURLAddress2 -ItemType Directory -Force + $repoUriAddress2 = Join-Path -Path $TestDrive -ChildPath "testdir2" + $null = New-Item $repoUriAddress2 -ItemType Directory -Force $localRepoParams2 = @{ Name = "psgettestlocal2" - URL = $repoURLAddress2 + Uri = $repoUriAddress2 Priority = 50 Trusted = $false } diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 695f540ea..3ad06aba6 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -7,20 +7,20 @@ Describe "Test Publish-PSResource" { BeforeAll { Get-NewPSResourceRepositoryFile - # Register temporary repositories + # Register temporary repositories $tmpRepoPath = Join-Path -Path $TestDrive -ChildPath "tmpRepoPath" New-Item $tmpRepoPath -Itemtype directory -Force $testRepository = "testRepository" - Register-PSResourceRepository -Name $testRepository -URL $tmpRepoPath -Priority 1 -ErrorAction SilentlyContinue - $script:repositoryPath = [IO.Path]::GetFullPath((get-psresourcerepository "testRepository").Url.AbsolutePath) + Register-PSResourceRepository -Name $testRepository -Uri $tmpRepoPath -Priority 1 -ErrorAction SilentlyContinue + $script:repositoryPath = [IO.Path]::GetFullPath((get-psresourcerepository "testRepository").Uri.AbsolutePath) $tmpRepoPath2 = Join-Path -Path $TestDrive -ChildPath "tmpRepoPath2" New-Item $tmpRepoPath2 -Itemtype directory -Force $testRepository2 = "testRepository2" - Register-PSResourceRepository -Name $testRepository2 -URL $tmpRepoPath2 -ErrorAction SilentlyContinue - $script:repositoryPath2 = [IO.Path]::GetFullPath((get-psresourcerepository "testRepository2").Url.AbsolutePath) + Register-PSResourceRepository -Name $testRepository2 -Uri $tmpRepoPath2 -ErrorAction SilentlyContinue + $script:repositoryPath2 = [IO.Path]::GetFullPath((get-psresourcerepository "testRepository2").Uri.AbsolutePath) - # Create module + # Create module $script:tmpModulesPath = Join-Path -Path $TestDrive -ChildPath "tmpModulesPath" $script:PublishModuleName = "PSGetTestModule" $script:PublishModuleBase = Join-Path $script:tmpModulesPath -ChildPath $script:PublishModuleName @@ -61,7 +61,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath } It "Publish a module with -Path and -Repository" { @@ -71,10 +71,10 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } -<# Temporarily comment this test out until Find Helper is complete and code within PublishPSResource is uncommented +<# Temporarily comment this test out until Find Helper is complete and code within PublishPSResource is uncommented It "Publish a module with dependencies" { # Create dependency module $dependencyVersion = "2.0.0" @@ -89,7 +89,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -LiteralPath $script:PublishModuleBase $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | select-object -Last 1 | Should -Be $expectedPath + Get-ChildItem $script:repositoryPath | select-object -Last 1 | Should -Be $expectedPath } #> @@ -122,7 +122,7 @@ Describe "Test Publish-PSResource" { New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" # Create nuspec - $nuspec = + $nuspec = @' @@ -140,13 +140,13 @@ Describe "Test Publish-PSResource" { '@ - $nuspecPath = Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.nuspec" + $nuspecPath = Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.nuspec" New-Item $nuspecPath -ItemType File -Value $nuspec Publish-PSResource -Path $script:PublishModuleBase -Nuspec $nuspecPath $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | Should -Be $expectedPath + Get-ChildItem $script:repositoryPath | Should -Be $expectedPath } It "Publish a module with -ReleaseNotes" { @@ -157,7 +157,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -ReleaseNotes $releaseNotes $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" New-Item -Path $expectedExpandedPath -ItemType directory @@ -176,7 +176,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -LicenseUrl $licenseUrl $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" New-Item -Path $expectedExpandedPath -ItemType directory @@ -195,7 +195,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -IconUrl $iconUrl $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" New-Item -Path $expectedExpandedPath -ItemType directory @@ -206,16 +206,16 @@ Describe "Test Publish-PSResource" { $expectedNuspecContents.Contains($iconUrl) | Should Be $true } - + It "Publish a module with -ProjectUrl" { $version = "1.0.0" New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - $projectUrl = "https://www.fakeprojecturl.com" + $projectUrl = "https://www.fakeprojectUrl.com" Publish-PSResource -Path $script:PublishModuleBase -ProjectUrl $projectUrl $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" New-Item -Path $expectedExpandedPath -ItemType directory @@ -233,7 +233,7 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -Tags $tags $expectedNupkgPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath + Get-ChildItem $script:repositoryPath | Should -Be $expectedNupkgPath $expectedExpandedPath = Join-Path -Path $script:repositoryPath -ChildPath "ExpandedPackage" New-Item -Path $expectedExpandedPath -ItemType directory @@ -270,10 +270,10 @@ Describe "Test Publish-PSResource" { $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath $expectedPath = Join-Path -Path $script:destinationPath -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:destinationPath).FullName | Should -Be $expectedPath + (Get-ChildItem $script:destinationPath).FullName | Should -Be $expectedPath } It "Publish a module and clean up properly when file in module is readonly" { @@ -288,6 +288,6 @@ Describe "Test Publish-PSResource" { Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" - (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } } diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index 7fd83f084..a15bfdf13 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -6,7 +6,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test Register-PSResourceRepository" { BeforeEach { $PSGalleryName = Get-PSGalleryName - $PSGalleryURL = Get-PSGalleryLocation + $PSGalleryUri = Get-PSGalleryLocation $TestRepoName1 = "testRepository" $TestRepoName2 = "testRepository2" $TestRepoName3 = "testRepository3" @@ -37,34 +37,34 @@ Describe "Test Register-PSResourceRepository" { Get-RemoveTestDirs($tmpDirPaths) } - It "register repository given Name, URL (bare minimum for NameParmaterSet)" { - $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -PassThru + It "register repository given Name, Uri (bare minimum for NameParmaterSet)" { + $res = Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -PassThru $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } - It "register repository with Name, URL, Trusted (NameParameterSet)" { - $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -PassThru + It "register repository with Name, Uri, Trusted (NameParameterSet)" { + $res = Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -PassThru $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 50 } - It "register repository given Name, URL, Trusted, Priority (NameParameterSet)" { - $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -PassThru + It "register repository given Name, Uri, Trusted, Priority (NameParameterSet)" { + $res = Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -PassThru $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 20 } - It "register repository given Name, URL, Trusted, Priority, CredentialInfo (NameParameterSet)" { - $res = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo1 -PassThru + It "register repository given Name, Uri, Trusted, Priority, CredentialInfo (NameParameterSet)" { + $res = Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo1 -PassThru $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be True $res.Priority | Should -Be 20 $res.CredentialInfo.VaultName | Should -Be "testvault" @@ -75,7 +75,7 @@ Describe "Test Register-PSResourceRepository" { Unregister-PSResourceRepository -Name $PSGalleryName $res = Register-PSResourceRepository -PSGallery -PassThru $res.Name | Should -Be $PSGalleryName - $res.URL | Should -Be $PSGalleryURL + $res.Uri | Should -Be $PSGalleryUri $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } @@ -84,7 +84,7 @@ Describe "Test Register-PSResourceRepository" { Unregister-PSResourceRepository -Name $PSGalleryName $res = Register-PSResourceRepository -PSGallery -Trusted -PassThru $res.Name | Should -Be $PSGalleryName - $res.URL | Should -Be $PSGalleryURL + $res.Uri | Should -Be $PSGalleryUri $res.Trusted | Should -Be True $res.Priority | Should -Be 50 } @@ -93,36 +93,36 @@ Describe "Test Register-PSResourceRepository" { Unregister-PSResourceRepository -Name $PSGalleryName $res = Register-PSResourceRepository -PSGallery -Trusted -Priority 20 -PassThru $res.Name | Should -Be $PSGalleryName - $res.URL | Should -Be $PSGalleryURL + $res.Uri | Should -Be $PSGalleryUri $res.Trusted | Should -Be True $res.Priority | Should -Be 20 } It "register repositories with Repositories parameter, all name parameter style repositories (RepositoriesParameterSet)" { - $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir1Path} - $hashtable2 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} - $hashtable3 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} - $hashtable4 = @{Name = $TestRepoName4; URL = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} + $hashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} + $hashtable2 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $hashtable3 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $hashtable4 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 Register-PSResourceRepository -Repositories $arrayOfHashtables $res = Get-PSResourceRepository -Name $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False $res.Priority | Should -Be 50 $res2 = Get-PSResourceRepository -Name $TestRepoName2 - $res2.URL.LocalPath | Should -Contain $tmpDir2Path + $res2.Uri.LocalPath | Should -Contain $tmpDir2Path $res2.Trusted | Should -Be True $res2.Priority | Should -Be 50 $res3 = Get-PSResourceRepository -Name $TestRepoName3 - $res3.URL.LocalPath | Should -Contain $tmpDir3Path + $res3.Uri.LocalPath | Should -Contain $tmpDir3Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 20 $res4 = Get-PSResourceRepository -Name $TestRepoName4 - $res4.URL.LocalPath | Should -Contain $tmpDir4Path + $res4.Uri.LocalPath | Should -Contain $tmpDir4Path $res4.Trusted | Should -Be True $res4.Priority | Should -Be 30 $res4.CredentialInfo.VaultName | Should -Be "testvault" @@ -135,7 +135,7 @@ Describe "Test Register-PSResourceRepository" { $hashtable1 = @{PSGallery = $True} Register-PSResourceRepository -Repositories $hashtable1 $res = Get-PSResourceRepository -Name $PSGalleryName - $res.URL | Should -Be $PSGalleryURL + $res.Uri | Should -Be $PSGalleryUri $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } @@ -143,36 +143,36 @@ Describe "Test Register-PSResourceRepository" { It "register repositories with Repositories parameter, name and psgallery parameter styles (RepositoriesParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName $hashtable1 = @{PSGallery = $True} - $hashtable2 = @{Name = $TestRepoName1; URL = $tmpDir1Path} - $hashtable3 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} - $hashtable4 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} - $hashtable5 = @{Name = $TestRepoName4; URL = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} + $hashtable2 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} + $hashtable3 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $hashtable4 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $hashtable5 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4, $hashtable5 Register-PSResourceRepository -Repositories $arrayOfHashtables $res1 = Get-PSResourceRepository -Name $PSGalleryName - $res1.URL | Should -Be $PSGalleryURL + $res1.Uri | Should -Be $PSGalleryUri $res1.Trusted | Should -Be False $res1.Priority | Should -Be 50 $res2 = Get-PSResourceRepository -Name $TestRepoName1 - $res2.URL.LocalPath | Should -Contain $tmpDir1Path + $res2.Uri.LocalPath | Should -Contain $tmpDir1Path $res2.Trusted | Should -Be False $res2.Priority | Should -Be 50 $res3 = Get-PSResourceRepository -Name $TestRepoName2 - $res3.URL.LocalPath | Should -Contain $tmpDir2Path + $res3.Uri.LocalPath | Should -Contain $tmpDir2Path $res3.Trusted | Should -Be True $res3.Priority | Should -Be 50 $res4 = Get-PSResourceRepository -Name $TestRepoName3 - $res4.URL.LocalPath | Should -Contain $tmpDir3Path + $res4.Uri.LocalPath | Should -Contain $tmpDir3Path $res4.Trusted | Should -Be True $res4.Priority | Should -Be 20 $res5 = Get-PSResourceRepository -Name $TestRepoName4 - $res5.URL.LocalPath | Should -Contain $tmpDir4Path + $res5.Uri.LocalPath | Should -Contain $tmpDir4Path $res5.Trusted | Should -Be True $res5.Priority | Should -Be 30 $res5.CredentialInfo.VaultName | Should -Be "testvault" @@ -180,49 +180,49 @@ Describe "Test Register-PSResourceRepository" { $res5.CredentialInfo.Credential | Should -BeNullOrEmpty } - It "not register repository when Name is provided but URL is not" { - {Register-PSResourceRepository -Name $TestRepoName1 -URL "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + It "not register repository when Name is provided but Uri is not" { + {Register-PSResourceRepository -Name $TestRepoName1 -Uri "" -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } - It "not register repository when Name is empty but URL is provided" { - {Register-PSResourceRepository -Name "" -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + It "not register repository when Name is empty but Uri is provided" { + {Register-PSResourceRepository -Name "" -Uri $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } - It "not register repository when Name is null but URL is provided" { - {Register-PSResourceRepository -Name $null -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + It "not register repository when Name is null but Uri is provided" { + {Register-PSResourceRepository -Name $null -Uri $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } - It "not register repository when Name is just whitespace but URL is provided" { - {Register-PSResourceRepository -Name " " -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + It "not register repository when Name is just whitespace but Uri is provided" { + {Register-PSResourceRepository -Name " " -Uri $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } It "not register PSGallery with NameParameterSet" { - {Register-PSResourceRepository -Name $PSGalleryName -URL $PSGalleryURL -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + {Register-PSResourceRepository -Name $PSGalleryName -Uri $PSGalleryUri -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } # this error message comes from the parameter cmdlet tags (earliest point of detection) - It "not register PSGallery when PSGallery parameter provided with Name, URL or CredentialInfo" { + It "not register PSGallery when PSGallery parameter provided with Name, Uri or CredentialInfo" { {Register-PSResourceRepository -PSGallery -Name $PSGalleryName -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" - {Register-PSResourceRepository -PSGallery -URL $PSGalleryURL -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + {Register-PSResourceRepository -PSGallery -Uri $PSGalleryUri -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" {Register-PSResourceRepository -PSGallery -CredentialInfo $credentialInfo1 -ErrorAction Stop} | Should -Throw -ErrorId "AmbiguousParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" } $testCases = @{Type = "Name key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; Name=$PSGalleryName}}, - @{Type = "URL key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; URL=$PSGalleryURL}}, + @{Type = "Uri key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; Uri=$PSGalleryUri}}, @{Type = "CredentialInfo key specified with PSGallery key"; IncorrectHashTable = @{PSGallery = $True; CredentialInfo = $credentialInfo1}} It "not register incorrectly formatted PSGallery type repo among correct ones when incorrect type is " -TestCases $testCases { param($Type, $IncorrectHashTable) - $correctHashtable1 = @{Name = $TestRepoName1; URL = $tmpDir1Path} - $correctHashtable2 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} - $correctHashtable3 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} + $correctHashtable2 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable3 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUrlCredentialInfoForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUriCredentialInfoForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 @@ -234,16 +234,16 @@ Describe "Test Register-PSResourceRepository" { $res3.Name | Should -Be $TestRepoName3 } - $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{URL = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = $PSGalleryName; URL = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-URL not specified"; IncorrectHashTable = @{Name = $TestRepoName1}; ErrorId = "NullURLForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-URL is not valid scheme"; IncorrectHashTable = @{Name = $TestRepoName1; URL="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{Uri = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = $PSGalleryName; Uri = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-Uri not specified"; IncorrectHashTable = @{Name = $TestRepoName1}; ErrorId = "NullUriForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, + @{Type = "-Uri is not valid scheme"; IncorrectHashTable = @{Name = $TestRepoName1; Uri="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { param($Type, $IncorrectHashTable, $ErrorId) - $correctHashtable1 = @{Name = $TestRepoName2; URL = $tmpDir2Path; Trusted = $True} - $correctHashtable2 = @{Name = $TestRepoName3; URL = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} $correctHashtable3 = @{PSGallery = $True; Priority = 30}; $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 @@ -263,26 +263,26 @@ Describe "Test Register-PSResourceRepository" { $res3.Priority | Should -Be 30 } - It "should register repository with relative location provided as URL" { - Register-PSResourceRepository -Name $TestRepoName1 -URL "./" + It "should register repository with relative location provided as Uri" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri "./" $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $relativeCurrentPath + $Res.Uri.LocalPath | Should -Contain $relativeCurrentPath $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } It "should register local file share NuGet based repository" { - Register-PSResourceRepository -Name "localFileShareTestRepo" -URL "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + Register-PSResourceRepository -Name "localFileShareTestRepo" -Uri "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" $res = Get-PSResourceRepository -Name "localFileShareTestRepo" $res.Name | Should -Be "localFileShareTestRepo" - $res.URL.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + $res.Uri.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" } It "prints a warning if CredentialInfo is passed in without SecretManagement module setup" { - $output = Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo1 3>&1 + $output = Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo1 3>&1 $output | Should -Match "Microsoft.PowerShell.SecretManagement module cannot be found" $res = Get-PSResourceRepository -Name $TestRepoName1 @@ -290,7 +290,7 @@ Describe "Test Register-PSResourceRepository" { } It "throws error if CredentialInfo is passed in with Credential property without SecretManagement module setup" { - { Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore $res | Should -BeNullOrEmpty diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index ba38d53f7..f3d35f351 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -6,7 +6,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test Set-PSResourceRepository" { BeforeEach { $PSGalleryName = Get-PSGalleryName - $PSGalleryURL = Get-PSGalleryLocation + $PSGalleryUri = Get-PSGalleryLocation $TestRepoName1 = "testRepository" $TestRepoName2 = "testRepository2" $TestRepoName3 = "testRepository3" @@ -36,45 +36,45 @@ Describe "Test Set-PSResourceRepository" { Get-RemoveTestDirs($tmpDirPaths) } - It "set repository given Name and URL parameters" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir2Path + It "set repository given Name and Uri parameters" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir2Path $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir2Path + $Res.Uri.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False $res.CredentialInfo | Should -BeNullOrEmpty } It "set repository given Name and Priority parameters" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path Set-PSResourceRepository -Name $TestRepoName1 -Priority 25 $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False $res.CredentialInfo | Should -BeNullOrEmpty } It "set repository given Name and Trusted parameters" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path Set-PSResourceRepository -Name $TestRepoName1 -Trusted $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be True $res.CredentialInfo | Should -BeNullOrEmpty } It "set repository given Name and CredentialInfo parameters" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path Set-PSResourceRepository -Name $TestRepoName1 -CredentialInfo $credentialInfo1 $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False $res.CredentialInfo.VaultName | Should -Be "testvault" @@ -83,7 +83,7 @@ Describe "Test Set-PSResourceRepository" { } It "not set repository and write error given just Name parameter" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path {Set-PSResourceRepository -Name $TestRepoName1 -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } @@ -94,7 +94,7 @@ Describe "Test Set-PSResourceRepository" { It "not set repository and throw error given Name (NameParameterSet)" -TestCases $testCases { param($Type, $Name) - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path {Set-PSResourceRepository -Name $Name -Priority 25 -ErrorAction Stop} | Should -Throw -ErrorId "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } @@ -104,10 +104,10 @@ Describe "Test Set-PSResourceRepository" { It "not set repository and write error given Name (RepositoriesParameterSet)" -TestCases $testCases2 { param($Type, $Name, $ErrorId) - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -Uri $tmpDir2Path - $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir3Path} + $hashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir3Path} $hashtable2 = @{Name = $TestRepoName2; Priority = 25} $incorrectHashTable = @{Name = $Name; Trusted = $True} $arrayOfHashtables = $hashtable1, $incorrectHashTable, $hashtable2 @@ -117,7 +117,7 @@ Describe "Test Set-PSResourceRepository" { $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir3Path + $Res.Uri.LocalPath | Should -Contain $tmpDir3Path $res.Trusted | Should -Be False $res2 = Get-PSResourceRepository -Name $TestRepoName2 @@ -127,12 +127,12 @@ Describe "Test Set-PSResourceRepository" { It "set repositories with Repositories parameter" { Unregister-PSResourceRepository -Name $PSGalleryName - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Register-PSResourceRepository -Name $TestRepoName2 -URL $tmpDir2Path - Register-PSResourceRepository -Name $TestRepoName3 -URL $tmpDir3Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName2 -Uri $tmpDir2Path + Register-PSResourceRepository -Name $TestRepoName3 -Uri $tmpDir3Path Register-PSResourceRepository -PSGallery - $hashtable1 = @{Name = $TestRepoName1; URL = $tmpDir2Path}; + $hashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir2Path}; $hashtable2 = @{Name = $TestRepoName2; Priority = 25}; $hashtable3 = @{Name = $TestRepoName3; CredentialInfo = [PSCustomObject] @{ VaultName = "testvault"; SecretName = "testsecret" }}; $hashtable4 = @{Name = $PSGalleryName; Trusted = $True}; @@ -141,21 +141,21 @@ Describe "Test Set-PSResourceRepository" { Set-PSResourceRepository -Repositories $arrayOfHashtables $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir2Path + $Res.Uri.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False $res.CredentialInfo | Should -BeNullOrEmpty $res2 = Get-PSResourceRepository -Name $TestRepoName2 $res2.Name | Should -Be $TestRepoName2 - $res2.URL.LocalPath | Should -Contain $tmpDir2Path + $res2.Uri.LocalPath | Should -Contain $tmpDir2Path $res2.Priority | Should -Be 25 $res2.Trusted | Should -Be False $res2.CredentialInfo | Should -BeNullOrEmpty $res3 = Get-PSResourceRepository -Name $TestRepoName3 $res3.Name | Should -Be $TestRepoName3 - $res3.URL.LocalPath | Should -Contain $tmpDir3Path + $res3.Uri.LocalPath | Should -Contain $tmpDir3Path $res3.Priority | Should -Be 50 $res3.Trusted | Should -Be False $res3.CredentialInfo.VaultName | Should -Be "testvault" @@ -164,16 +164,16 @@ Describe "Test Set-PSResourceRepository" { $res4 = Get-PSResourceRepository -Name $PSGalleryName $res4.Name | Should -Be $PSGalleryName - $res4.URL | Should -Contain $PSGalleryURL + $res4.Uri | Should -Contain $PSGalleryUri $res4.Priority | Should -Be 50 $res4.Trusted | Should -Be True $res4.CredentialInfo | Should -BeNullOrEmpty } - It "not set and throw error for trying to set PSGallery URL (NameParameterSet)" { + It "not set and throw error for trying to set PSGallery Uri (NameParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -PSGallery - {Set-PSResourceRepository -Name $PSGalleryName -URL $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + {Set-PSResourceRepository -Name $PSGalleryName -Uri $tmpDir1Path -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } It "not set and throw error for trying to set PSGallery CredentialInfo (NameParameterSet)" { @@ -182,13 +182,13 @@ Describe "Test Set-PSResourceRepository" { {Set-PSResourceRepository -Name $PSGalleryName -CredentialInfo $credentialInfo1 -ErrorAction Stop} | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } - It "not set repository and throw error for trying to set PSGallery URL (RepositoriesParameterSet)" { + It "not set repository and throw error for trying to set PSGallery Uri (RepositoriesParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -PSGallery - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path - $hashtable1 = @{Name = $PSGalleryName; URL = $tmpDir1Path} + $hashtable1 = @{Name = $PSGalleryName; Uri = $tmpDir1Path} $hashtable2 = @{Name = $TestRepoName1; Priority = 25} $arrayOfHashtables = $hashtable1, $hashtable2 @@ -197,17 +197,17 @@ Describe "Test Set-PSResourceRepository" { $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False } - It "should set repository with relative URL provided" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Set-PSResourceRepository -Name $TestRepoName1 -URL $relativeCurrentPath + It "should set repository with relative Uri provided" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -Uri $relativeCurrentPath $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $relativeCurrentPath + $Res.Uri.LocalPath | Should -Contain $relativeCurrentPath $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } @@ -216,7 +216,7 @@ Describe "Test Set-PSResourceRepository" { Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -PSGallery - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $hashtable1 = @{Name = $PSGalleryName; CredentialInfo = $credentialInfo1} $hashtable2 = @{Name = $TestRepoName1; Priority = 25} @@ -227,32 +227,32 @@ Describe "Test Set-PSResourceRepository" { $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir1Path + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Priority | Should -Be 25 $res.Trusted | Should -Be False $res.CredentialInfo | Should -BeNullOrEmpty } It "should set repository with local file share NuGet based Uri" { - Register-PSResourceRepository -Name "localFileShareTestRepo" -URL $tmpDir1Path - Set-PSResourceRepository -Name "localFileShareTestRepo" -URL "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + Register-PSResourceRepository -Name "localFileShareTestRepo" -Uri $tmpDir1Path + Set-PSResourceRepository -Name "localFileShareTestRepo" -Uri "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" $res = Get-PSResourceRepository -Name "localFileShareTestRepo" $res.Name | Should -Be "localFileShareTestRepo" - $res.URL.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" + $Res.Uri.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" } It "set repository and see updated repository with -PassThru" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - $res = Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir2Path -PassThru + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + $res = Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir2Path -PassThru $res.Name | Should -Be $TestRepoName1 - $res.URL.LocalPath | Should -Contain $tmpDir2Path + $Res.Uri.LocalPath | Should -Contain $tmpDir2Path $res.Priority | Should -Be 50 $res.Trusted | Should -Be False } It "prints a warning if CredentialInfo is passed in without SecretManagement module setup" { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - $output = Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -CredentialInfo $credentialInfo1 3>&1 + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + $output = Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -CredentialInfo $credentialInfo1 3>&1 $output | Should -Match "Microsoft.PowerShell.SecretManagement module cannot be found" $res = Get-PSResourceRepository -Name $TestRepoName1 @@ -261,8 +261,8 @@ Describe "Test Set-PSResourceRepository" { It "throws error if CredentialInfo is passed in with Credential property without SecretManagement module setup" { { - Register-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path - Set-PSResourceRepository -Name $TestRepoName1 -URL $tmpDir1Path -CredentialInfo $credentialInfo2 + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore diff --git a/test/UnregisterPSResourceRepository.Tests.ps1 b/test/UnregisterPSResourceRepository.Tests.ps1 index 870da4717..f3e6e206e 100644 --- a/test/UnregisterPSResourceRepository.Tests.ps1 +++ b/test/UnregisterPSResourceRepository.Tests.ps1 @@ -6,7 +6,7 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test Unregister-PSResourceRepository" { BeforeEach { $TestGalleryName = Get-PoshTestGalleryName - $TestGalleryUrl = Get-PoshTestGalleryLocation + $TestGalleryUri = Get-PoshTestGalleryLocation Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" @@ -24,7 +24,7 @@ Describe "Test Unregister-PSResourceRepository" { } It "unregister single repository previously registered" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository" -Uri $tmpDir1Path Unregister-PSResourceRepository -Name "testRepository" $res = Get-PSResourceRepository -Name "testRepository" -ErrorVariable err -ErrorAction SilentlyContinue @@ -32,8 +32,8 @@ Describe "Test Unregister-PSResourceRepository" { } It "unregister multiple repositories previously registered" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name "testRepository" -Uri $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -Uri $tmpDir2Path Unregister-PSResourceRepository -Name "testRepository","testRepository2" $res = Get-PSResourceRepository -Name "testRepository","testRepository2" -ErrorVariable err -ErrorAction SilentlyContinue @@ -47,8 +47,8 @@ Describe "Test Unregister-PSResourceRepository" { } It "not register when -Name contains wildcard" { - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path - Register-PSResourceRepository -Name "testRepository2" -URL $tmpDir2Path + Register-PSResourceRepository -Name "testRepository" -Uri $tmpDir1Path + Register-PSResourceRepository -Name "testRepository2" -Uri $tmpDir2Path Unregister-PSResourceRepository -Name "testRepository*" -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "nameContainsWildCardError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" @@ -56,7 +56,7 @@ Describe "Test Unregister-PSResourceRepository" { It "when multiple repo Names provided, if one name isn't valid unregister the rest and write error message" { $nonRegisteredRepoName = "nonRegisteredRepository" - Register-PSResourceRepository -Name "testRepository" -URL $tmpDir1Path + Register-PSResourceRepository -Name "testRepository" -Uri $tmpDir1Path Unregister-PSResourceRepository -Name $nonRegisteredRepoName,"testRepository" -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorUnregisteringSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.UnregisterPSResourceRepository" @@ -73,7 +73,7 @@ Describe "Test Unregister-PSResourceRepository" { It "unregister repository using -PassThru" { $res = Unregister-PSResourceRepository -Name $TestGalleryName -PassThru $res.Name | Should -Be $TestGalleryName - $res.Url | Should -Be $TestGalleryURL + $Res.Uri | Should -Be $TestGalleryUri $res = Get-PSResourceRepository -Name $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue $res | Should -BeNullOrEmpty $err.Count | Should -Not -Be 0 diff --git a/test/testRepositories.xml b/test/testRepositories.xml index b84e90f9d..6426f2c53 100644 --- a/test/testRepositories.xml +++ b/test/testRepositories.xml @@ -1,6 +1,6 @@ - - - + + + diff --git a/test/testRepositoriesWithCredentialInfo.xml b/test/testRepositoriesWithCredentialInfo.xml index 2797e7bf4..235b8fd92 100644 --- a/test/testRepositoriesWithCredentialInfo.xml +++ b/test/testRepositoriesWithCredentialInfo.xml @@ -1,7 +1,7 @@ - - - - + + + + From c31d3651f25cd816bdab90520a4dbeca567f73c0 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 3 Feb 2022 14:19:47 -0800 Subject: [PATCH 126/276] Update tests to use PowerShell pipeline cmdlets (#570) --- test/FindPSResource.Tests.ps1 | 60 ++++++----------------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 602a6c823..c0a70f063 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -55,61 +55,21 @@ Describe 'Test Find-PSResource for Module' { } 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 - } + $foundResources = Find-PSResource -Name "*" -Repository "PoshTestGallery" - if ($item.Name -eq $testScriptName) - { - $foundTestScript = $True - } - - if($item.IsPrerelease) - { - $foundPreview = $True - } - } - - $foundPreview | Should -Be $False - $foundTestScript | Should -Be $True - $foundTestModule | Should -Be $True + # Should find Module and Script resources but no prerelease resources + $foundResources | where-object Name -eq "test_module" | Should -Not -BeNullOrEmpty -Because "test_module should exist in PoshTestGallery" + $foundResources | where-object Name -eq "test_script" | Should -Not -BeNullOrEmpty -Because "test_script should exist in PoshTestGallery" + $foundResources | where-object IsPrerelease -eq $true | Should -BeNullOrEmpty -Because "No prerelease resources should be returned" } 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 - } + $foundResources = Find-PSResource -Name "*" -Prerelease -Repository "PoshTestGallery" - if ($item.Name -eq $testScriptName) - { - $foundTestScript = $True - } - - if($item.IsPrerelease) - { - $foundPreview = $True - } - } - - $foundPreview | Should -Be $True - $foundTestScript | Should -Be $True - $foundTestModule | Should -Be $True + # Should find Module and Script resources inlcuding prerelease resources + $foundResources | where-object Name -eq "test_module" | Should -Not -BeNullOrEmpty -Because "test_module should exist in PoshTestGallery" + $foundResources | where-object Name -eq "test_script" | Should -Not -BeNullOrEmpty -Because "test_script should exist in PoshTestGallery" + $foundResources | where-object IsPrerelease -eq $true | Should -Not -BeNullOrEmpty -Because "Prerelease resources should be returned" } It "find resource given Name from V3 endpoint repository (NuGetGallery)" { From 927e01ce1113794b177cf32126276465144a7e6f Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 4 Feb 2022 13:36:19 -0500 Subject: [PATCH 127/276] Add support for Uninstall-PSResource (#593) Add support for Uninstall -Prerelease parameter uninstalling only prerelease versions --- help/Get-PSResource.md | 24 ++++++++++++++++-- help/Uninstall-PSResource.md | 15 +++++++++++- src/code/GetHelper.cs | 19 +++++++++------ src/code/GetPSResource.cs | 7 +++++- src/code/InstallHelper.cs | 11 +++++++-- src/code/UninstallPSResource.cs | 8 +++++- src/code/UpdatePSResource.cs | 5 +++- test/UninstallPSResource.Tests.ps1 | 39 ++++++++++++++++++++++++++++++ 8 files changed, 113 insertions(+), 15 deletions(-) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index 42239d789..a04868f42 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -26,7 +26,7 @@ The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript PS C:\> Get-PSResource Az ``` -This will return versions of the Az module installed via PowerShellGet. +This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. ### Example 2 ```powershell @@ -44,12 +44,32 @@ This will return all versions of the Az module within the specified range. ### Example 4 ```powershell +PS C:\> Get-PSResource Az -version "4.0.1-preview" +``` + +Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. + +```powershell +PS C:\> Get-PSResource Az -version "4.0.1" +``` +Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. + +### Example 5 +```powershell +PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] +``` + +Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. + + +### Example 6 +```powershell PS C:\> Get-PSResource Az -Path . ``` This will return all versions of the Az module that have been installed in the current directory. -### Example 5 +### Example 7 ```powershell PS C:\> Get-PSResource ``` diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index 6bfdef5b7..45cb44a4a 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -47,11 +47,24 @@ Uninstalls version 1.0.0 of the Az module. ### Example 3 ```powershell PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" +``` Uninstalls all versions within the specified version range. + +### Example 4 +```powershell +PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" ``` -Uninstalls version 1.0.0 of the Az module. +Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. + +### Example 4 +```powershell +PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease +``` + +Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. + ## PARAMETERS diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index d9784cdd9..946b270fe 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -39,11 +39,12 @@ public GetHelper(PSCmdlet cmdletPassedIn) public IEnumerable GetPackagesFromPath( string[] name, VersionRange versionRange, - List pathsToSearch) + List pathsToSearch, + bool selectPrereleaseOnly) { - List pgkPathsByName = FilterPkgPathsByName(name, pathsToSearch); + List pkgPathsByName = FilterPkgPathsByName(name, pathsToSearch); - foreach (string pkgPath in FilterPkgPathsByVersion(versionRange, pgkPathsByName)) + foreach (string pkgPath in FilterPkgPathsByVersion(versionRange, pkgPathsByName, selectPrereleaseOnly)) { PSResourceInfo pkg = OutputPackageObject(pkgPath, _scriptDictionary); if (pkg != null) @@ -77,7 +78,7 @@ public List FilterPkgPathsByName(string[] names, List dirsToSear } // Filter by user provided version - public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, List dirsToSearch) + public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, List dirsToSearch, bool selectPrereleaseOnly) { Dbg.Assert(versionRange != null, "Version Range cannot be null"); @@ -121,11 +122,15 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li _cmdletPassedIn.WriteVerbose(string.Format("Package version parsed as NuGet version: '{0}'", pkgNugetVersion)); + // For Uninstall-PSResource Prerelease parameter equates to selecting prerelease versions only to uninstall. + // For other cmdlets (Find-PSResource, Install-PSResource) Prerelease parmater equates to selecting stable and prerelease versions. + // We will not just select prerelase versions. For Get-PSResource, there is no Prerelease parameter. if (versionRange.Satisfies(pkgNugetVersion)) { - // This will be one version or a version range. - // yield results then continue with this iteration of the loop - yield return versionPath; + if (!selectPrereleaseOnly || pkgNugetVersion.IsPrerelease) + { + yield return versionPath; + } } } } diff --git a/src/code/GetPSResource.cs b/src/code/GetPSResource.cs index facee6bf5..703500d0c 100644 --- a/src/code/GetPSResource.cs +++ b/src/code/GetPSResource.cs @@ -128,7 +128,12 @@ protected override void ProcessRecord() } GetHelper getHelper = new GetHelper(this); - foreach (PSResourceInfo pkg in getHelper.GetPackagesFromPath(namesToSearch, _versionRange, _pathsToSearch)) + // selectPrereleaseOnly is false because we want both stable and prerelease versions all the time. + foreach (PSResourceInfo pkg in getHelper.GetPackagesFromPath( + name: namesToSearch, + versionRange: _versionRange, + pathsToSearch: _pathsToSearch, + selectPrereleaseOnly: false)) { WriteObject(pkg); } diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index a35fb1edc..8d75ae518 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -279,10 +279,12 @@ private IEnumerable FilterByInstalledPkgs(IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( name: filteredPackages.Keys.ToArray(), versionRange: _versionRange, - pathsToSearch: _pathsToSearch); + pathsToSearch: _pathsToSearch, + selectPrereleaseOnly: false); if (!pkgsAlreadyInstalled.Any()) { return packages; @@ -666,7 +668,12 @@ private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) // Get installed modules, then get all possible paths bool foundClobber = false; GetHelper getHelper = new GetHelper(_cmdletPassedIn); - IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath(new string[] { "*" }, VersionRange.All, _pathsToSearch); + // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, never select prerelease only. + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( + name: new string[] { "*" }, + versionRange: VersionRange.All, + pathsToSearch: _pathsToSearch, + selectPrereleaseOnly: false); // user parsed metadata hash List listOfCmdlets = new List(); foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index e52e6c622..44afd1670 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -35,6 +35,12 @@ public sealed class UninstallPSResource : PSCmdlet [ValidateNotNullOrEmpty] public string Version { get; set; } + /// + /// When specified, only uninstalls prerelease versions. + /// + [Parameter] + public SwitchParameter Prerelease { get; set; } + /// /// Used for pipeline input. /// @@ -163,7 +169,7 @@ private bool UninstallPkgHelper() // note that the xml file is located in ./Scripts/InstalledScriptInfos, eg: ./Scripts/InstalledScriptInfos/TestScript_InstalledScriptInfo.xml string pkgName; - foreach (string pkgPath in getHelper.FilterPkgPathsByVersion(_versionRange, dirsToDelete)) + foreach (string pkgPath in getHelper.FilterPkgPathsByVersion(_versionRange, dirsToDelete, selectPrereleaseOnly: Prerelease)) { pkgName = Utils.GetInstalledPackageName(pkgPath); diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index abf2c6034..9913b4468 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -246,10 +246,13 @@ private string[] ProcessPackageNames( // Get all installed packages selected for updating. GetHelper getHelper = new GetHelper(cmdletPassedIn: this); var installedPackages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + + // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, not select prerelease only. foreach (var installedPackage in getHelper.GetPackagesFromPath( name: namesToProcess, versionRange: VersionRange.All, - pathsToSearch: Utils.GetAllResourcePaths(this, Scope))) + pathsToSearch: Utils.GetAllResourcePaths(this, Scope), + selectPrereleaseOnly: false)) { if (!installedPackages.ContainsKey(installedPackage.Name)) { diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index b4542254a..b42ecaf19 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -13,6 +13,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $testScriptName = "test_script" Get-NewPSResourceRepositoryFile Uninstall-PSResource -name ContosoServer -Version "*" + Uninstall-PSResource -Name $testModuleName -Version "*" } BeforeEach { @@ -183,6 +184,44 @@ Describe 'Test Uninstall-PSResource for Modules' { $res.Version | Should -Be "2.5.0.0" } + It "uninstall all prerelease versions (which satisfy the range) when -Version '*' and -Prerelease parameter is specified" { + Install-PSResource -Name $testModuleName -Version "3.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "3.5.2-beta001" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "4.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "5.0.0" -Repository $TestGalleryName + $res = Get-PSResource -Name $testModuleName + $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} + $prereleaseVersionPkgs.Count | Should -Be 2 + + Uninstall-PSResource -Name $testModuleName -Version "*" -Prerelease + $res = Get-PSResource -Name $testModuleName + $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} + $prereleaseVersionPkgs.Count | Should -Be 0 + $stableVersionPkgs = $res | Where-Object {$_.IsPrerelease -ne $true} + $stableVersionPkgs.Count | Should -Be 3 + } + + It "uninstall all prerelease versions (which satisfy the range) when -Version range and -Prerelease parameter is specified" { + Install-PSResource -Name $testModuleName -Version "3.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "3.5.2-beta001" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "4.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "5.0.0" -Repository $TestGalleryName + $res = Get-PSResource -Name $testModuleName + $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} + $prereleaseVersionPkgs.Count | Should -Be 2 + + Uninstall-PSResource -Name $testModuleName -Version "[3.0.0, 4.0.0]" -Prerelease + $res = Get-PSResource -Name $testModuleName + # should only uninstall 3.5.2-beta001, 4.5.2-alpha001 is out of range and should remain installed + $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} + $prereleaseVersionPkgs.Count | Should -Be 1 + $stableVersionPkgs = $res | Where-Object {$_.IsPrerelease -ne $true} + # versions 3.0.0 and 4.0.0 fall in range but should not be uninstalled as Prerelease parameter only selects prerelease versions for uninstallation + $stableVersionPkgs.Count | Should -Be 3 + } + It "Uninstall module using -WhatIf, should not uninstall the module" { Uninstall-PSResource -Name "ContosoServer" -WhatIf $pkg = Get-Module ContosoServer -ListAvailable From d1cfda84cdc742ce4d528c2d0858c22705e17816 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 22 Feb 2022 17:13:06 -0800 Subject: [PATCH 128/276] Allow .psd1 to be passed into -RequiredResourceFile (#610) --- src/code/GetHelper.cs | 3 +- src/code/InstallHelper.cs | 22 +++++----- src/code/InstallPSResource.cs | 70 ++++++++++++++++++++++++++---- src/code/PublishPSResource.cs | 12 ++--- src/code/UninstallPSResource.cs | 3 +- src/code/Utils.cs | 8 ++-- test/InstallPSResource.Tests.ps1 | 23 +++++++++- test/TestRequiredResourceFile.json | 3 +- test/TestRequiredResourceFile.psd1 | 14 ++++++ 9 files changed, 125 insertions(+), 33 deletions(-) create mode 100644 test/TestRequiredResourceFile.psd1 diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 946b270fe..c96586d40 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -21,6 +21,7 @@ internal class GetHelper private readonly PSCmdlet _cmdletPassedIn; private readonly Dictionary _scriptDictionary; + public const string PSScriptFileExt = ".ps1"; #endregion @@ -222,7 +223,7 @@ private static string GetResourceNameFromPath(string path) // ./Modules/Microsoft.PowerShell.Test-Module : Microsoft.PowerShell.Test-Module // ./Scripts/Microsoft.PowerShell.Test-Script.ps1 : Microsoft.PowerShell.Test-Script var resourceName = Path.GetFileName(path); - return Path.GetExtension(resourceName).Equals(".ps1", StringComparison.OrdinalIgnoreCase) + return Path.GetExtension(resourceName).Equals(PSScriptFileExt, StringComparison.OrdinalIgnoreCase) ? Path.GetFileNameWithoutExtension(resourceName) : resourceName; } diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 8d75ae518..2d758216a 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -28,9 +28,11 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// Install helper class /// internal class InstallHelper : PSCmdlet - { + { #region Members + public const string PSDataFileExt = ".psd1"; + public const string PSScriptFileExt = ".ps1"; private const string MsgRepositoryNotTrusted = "Untrusted repository"; private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; @@ -461,8 +463,8 @@ private List InstallPackage( string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); string moduleManifestVersion = string.Empty; - var scriptPath = Path.Combine(tempDirNameVersion, pkg.Name + ".ps1"); - var modulePath = Path.Combine(tempDirNameVersion, pkg.Name + ".psd1"); + var scriptPath = Path.Combine(tempDirNameVersion, pkg.Name + PSScriptFileExt); + var modulePath = Path.Combine(tempDirNameVersion, pkg.Name + PSDataFileExt); // Check if the package is a module or a script var isModule = File.Exists(modulePath); @@ -497,7 +499,7 @@ private List InstallPackage( if (isModule) { - var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + ".psd1"); + var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + PSDataFileExt); if (!File.Exists(moduleManifest)) { var message = String.Format("{0} package could not be installed with error: Module manifest file: {1} does not exist. This is not a valid PowerShell module.", pkgIdentity.Id, moduleManifest); @@ -509,7 +511,7 @@ private List InstallPackage( continue; } - if (!Utils.TryParseModuleManifest(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) + if (!Utils.TryParsePSDataFile(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) { // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. continue; @@ -878,16 +880,16 @@ private void MoveFilesIntoInstallPath( Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); // Need to delete old script file, if that exists - _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1")))); - if (File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1"))) + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)))); + if (File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt))) { _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); - File.Delete(Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1")); + File.Delete(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)); } } - _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1"))); - Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + ".ps1")); + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt))); + Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)); } } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 687d89a7c..c08987d26 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -118,7 +118,7 @@ class InstallPSResource : PSCmdlet public PSResourceInfo InputObject { get; set; } /// - /// Installs resources based on input from a JSON file. + /// Installs resources based on input from a .psd1 (hashtable) or .json file. /// [Parameter(ParameterSetName = RequiredResourceFileParameterSet)] [ValidateNotNullOrEmpty] @@ -138,13 +138,31 @@ public String RequiredResourceFile if (!File.Exists(resolvedPath)) { - var exMessage = String.Format("The RequiredResourceFile does not exist. Please try specifying a path to a valid .json file"); + var exMessage = String.Format("The RequiredResourceFile does not exist. Please try specifying a path to a valid .json or .psd1 file"); var ex = new ArgumentException(exMessage); var RequiredResourceFileDoesNotExist = new ErrorRecord(ex, "RequiredResourceFileDoesNotExist", ErrorCategory.ObjectNotFound, null); ThrowTerminatingError(RequiredResourceFileDoesNotExist); } + if (resolvedPath.EndsWith(".json", StringComparison.InvariantCultureIgnoreCase)) + { + _resourceFileType = ResourceFileType.JsonFile; + } + else if (resolvedPath.EndsWith(".psd1", StringComparison.InvariantCultureIgnoreCase)) + { + _resourceFileType = ResourceFileType.PSDataFile; + } + else + { + // Throw here because no further processing can be done. + var exMessage = String.Format("The RequiredResourceFile must have either a '.json' or '.psd1' extension. Please try specifying a path to a valid .json or .psd1 file"); + var ex = new ArgumentException(exMessage); + var RequiredResourceFileNotValid = new ErrorRecord(ex, "RequiredResourceFileNotValid", ErrorCategory.ObjectNotFound, null); + + ThrowTerminatingError(RequiredResourceFileNotValid); + } + _requiredResourceFile = resolvedPath; } } @@ -176,6 +194,17 @@ public String RequiredResourceFile #endregion + #region Enums + + private enum ResourceFileType + { + UnknownFile, + JsonFile, + PSDataFile + } + + #endregion + #region Members private const string NameParameterSet = "NameParameterSet"; @@ -188,6 +217,7 @@ public String RequiredResourceFile private Hashtable _requiredResourceHash; VersionRange _versionRange; InstallHelper _installHelper; + ResourceFileType _resourceFileType; #endregion @@ -252,7 +282,7 @@ protected override void ProcessRecord() break; case RequiredResourceFileParameterSet: - /* json file contents should look like: + /* .json file contents should look like: { "Pester": { "allowPrerelease": true, @@ -262,28 +292,52 @@ protected override void ProcessRecord() } } */ - + + /* .psd1 file contents should look like: + @{ + "Configuration" = @{ version = "[4.4.2,4.7.0]" } + "Pester" = @{ + version = "[4.4.2,4.7.0]" + repository = PSGallery + credential = $cred + prerelease = $true + } + } + */ + string requiredResourceFileStream = string.Empty; using (StreamReader sr = new StreamReader(_requiredResourceFile)) { requiredResourceFileStream = sr.ReadToEnd(); } - Hashtable pkgsInJsonFile = null; + Hashtable pkgsInFile = null; try { - pkgsInJsonFile = Utils.ConvertJsonToHashtable(this, requiredResourceFileStream); + if (_resourceFileType.Equals(ResourceFileType.JsonFile)) + { + pkgsInFile = Utils.ConvertJsonToHashtable(this, requiredResourceFileStream); + } + else + { + // must be a .psd1 file + if (!Utils.TryParsePSDataFile(_requiredResourceFile, this, out pkgsInFile)) + { + // Ran into errors parsing the .psd1 file which was found in Utils.TryParsePSDataFile() and written. + return; + } + } } catch (Exception) { - var exMessage = String.Format("Argument for parameter -RequiredResourceFile is not in proper json format. Make sure argument is either a valid json file."); + var exMessage = String.Format("Argument for parameter -RequiredResourceFile is not in proper json or hashtable format. Make sure argument is either a valid .json or .psd1 file."); var ex = new ArgumentException(exMessage); var RequiredResourceFileNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceFileNotInProperJsonFormat", ErrorCategory.InvalidData, null); ThrowTerminatingError(RequiredResourceFileNotInProperJsonFormat); } - RequiredResourceHelper(pkgsInJsonFile); + RequiredResourceHelper(pkgsInFile); break; case RequiredResourceParameterSet: diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index b4acd8455..bd9f46dd6 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -63,7 +63,7 @@ public string Path { _path = resolvedPath; } - else if (File.Exists(resolvedPath) && resolvedPath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + else if (File.Exists(resolvedPath) && resolvedPath.EndsWith(PSDataFileExt, StringComparison.OrdinalIgnoreCase)) { _path = resolvedPath; } @@ -163,6 +163,8 @@ public PSCredential ProxyCredential { private NuGetVersion _pkgVersion; private string _pkgName; private static char[] _PathSeparators = new [] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; + public const string PSDataFileExt = ".psd1"; + public const string PSScriptFileExt = ".ps1"; #endregion @@ -179,7 +181,7 @@ protected override void ProcessRecord() { // Returns the name of the file or the name of the directory, depending on path var pkgFileOrDir = new DirectoryInfo(_path); - bool isScript = _path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase); + bool isScript = _path.EndsWith(PSScriptFileExt, StringComparison.OrdinalIgnoreCase); if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine", _path))) { @@ -233,7 +235,7 @@ protected override void ProcessRecord() else { _pkgName = pkgFileOrDir.Name; - resourceFilePath = System.IO.Path.Combine(_path, _pkgName + ".psd1"); + resourceFilePath = System.IO.Path.Combine(_path, _pkgName + PSDataFileExt); // Validate that there's a module manifest if (!File.Exists(resourceFilePath)) @@ -332,7 +334,7 @@ protected override void ProcessRecord() if (isScript) { // copy the script file to the temp directory - File.Copy(_path, System.IO.Path.Combine(outputDir, _pkgName + ".ps1"), true); + File.Copy(_path, System.IO.Path.Combine(outputDir, _pkgName + PSDataFileExt), true); } else { @@ -470,7 +472,7 @@ private string CreateNuspec( if (!isScript) { // Parse the module manifest and *replace* the passed-in metadata with the module manifest metadata. - if (!Utils.TryParseModuleManifest( + if (!Utils.TryParsePSDataFile( moduleFileInfo: filePath, cmdletPassedIn: this, parsedMetadataHashtable: out parsedMetadataHash)) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 44afd1670..5dfe13c00 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -60,6 +60,7 @@ public sealed class UninstallPSResource : PSCmdlet private const string NameParameterSet = "NameParameterSet"; private const string InputObjectParameterSet = "InputObjectParameterSet"; + public const string PSScriptFileExt = ".ps1"; public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); @@ -180,7 +181,7 @@ private bool UninstallPkgHelper() } ErrorRecord errRecord = null; - if (pkgPath.EndsWith(".ps1")) + if (pkgPath.EndsWith(PSScriptFileExt)) { successfullyUninstalled = UninstallScriptHelper(pkgPath, pkgName, out errRecord); } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index d11722a1c..07c74fc12 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -23,8 +23,8 @@ internal static class Utils { #region String fields - public static readonly string[] EmptyStrArray = Array.Empty(); - + public static readonly string[] EmptyStrArray = Array.Empty(); + public const string PSDataFileExt = ".psd1"; private const string ConvertJsonToHashtableScript = @" param ( [string] $json @@ -728,7 +728,7 @@ private static void GetStandardPlatformPaths( #region Manifest methods - public static bool TryParseModuleManifest( + public static bool TryParsePSDataFile( string moduleFileInfo, PSCmdlet cmdletPassedIn, out Hashtable parsedMetadataHashtable) @@ -738,7 +738,7 @@ public static bool TryParseModuleManifest( // A script will already have the metadata parsed into the parsedMetadatahash, // a module will still need the module manifest to be parsed. - if (moduleFileInfo.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) + if (moduleFileInfo.EndsWith(PSDataFileExt, StringComparison.OrdinalIgnoreCase)) { // Parse the module manifest var ast = Parser.ParseFile( diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index bf73e0fb2..fae7b83bf 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -12,6 +12,7 @@ Describe 'Test Install-PSResource for Module' { $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "TestModule" $RequiredResourceJSONFileName = "TestRequiredResourceFile.json" + $RequiredResourcePSD1FileName = "TestRequiredResourceFile.psd1" Get-NewPSResourceRepositoryFile Register-LocalRepos } @@ -381,10 +382,28 @@ Describe 'Test Install-PSResource for Module' { $res3.Version | Should -Be "0.0.5" } + It "Install modules using -RequiredResourceFile with PSD1 file" { + $rrFilePSD1 = Join-Path -Path $psscriptroot -ChildPath $RequiredResourcePSD1FileName + + Install-PSResource -RequiredResourceFile $rrFilePSD1 + + $res1 = Get-Module "TestModule" -ListAvailable + $res1.Name | Should -Be "TestModule" + $res1.Version | Should -Be "1.3.0" + + $res2 = Get-Module "TestModulePrerelease" -ListAvailable + $res2.Name | Should -Be "TestModulePrerelease" + $res2.Version | Should -Be "0.0.1" + + $res3 = Get-Module "TestModule99" -ListAvailable + $res3.Name | Should -Be "TestModule99" + $res3.Version | Should -Be "0.0.5" + } + It "Install modules using -RequiredResourceFile with JSON file" { - $rrFileJSON = ".\$RequiredResourceJSONFileName" + $rrFileJSON = Join-Path -Path $psscriptroot -ChildPath $RequiredResourceJSONFileName - Install-PSResource -RequiredResourceFile $rrFileJSON -Verbose + Install-PSResource -RequiredResourceFile $rrFileJSON $res1 = Get-Module "TestModule" -ListAvailable $res1.Name | Should -Be "TestModule" diff --git a/test/TestRequiredResourceFile.json b/test/TestRequiredResourceFile.json index 1a790c79b..6d6c04e9f 100644 --- a/test/TestRequiredResourceFile.json +++ b/test/TestRequiredResourceFile.json @@ -8,6 +8,5 @@ "repository": "PoshTestGallery", "prerelease": "true" }, - "TestModule99": { - } + "TestModule99": {} } diff --git a/test/TestRequiredResourceFile.psd1 b/test/TestRequiredResourceFile.psd1 new file mode 100644 index 000000000..767e404bf --- /dev/null +++ b/test/TestRequiredResourceFile.psd1 @@ -0,0 +1,14 @@ + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PoshTestGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PoshTestGallery" + prerelease = "true" + } + + TestModule99 = @{} +} From 4cdc5dce78ee8a6c55e11b3499dac35e266a1d6b Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 14 Apr 2022 15:10:52 -0400 Subject: [PATCH 129/276] Refactor tests to use test modules from PSGallery, not PoshTestGallery (#628) * remove PoshTestGallery from repositories xml file used during tests as it won't be able to search it --- test/FindPSResource.Tests.ps1 | 226 ++++++---- test/GetInstalledPSResource.Tests.ps1 | 82 ++-- test/InstallPSResource.Tests.ps1 | 394 +++++++++--------- test/SavePSResource.Tests.ps1 | 134 +++--- test/TestRequiredResourceFile.json | 16 +- test/TestRequiredResourceFile.psd1 | 20 +- test/UninstallPSResource.Tests.ps1 | 210 +++++----- test/UnregisterPSResourceRepository.Tests.ps1 | 12 +- test/UpdatePSResource.Tests.ps1 | 195 ++++----- test/testRepositories.xml | 1 - 10 files changed, 657 insertions(+), 633 deletions(-) diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index c0a70f063..9d946b33b 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -6,7 +6,6 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Find-PSResource for Module' { BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "test_module" @@ -54,23 +53,36 @@ Describe 'Test Find-PSResource for Module' { $foundScript | Should -BeTrue } - It "should find all resources given Name that equals wildcard, '*'" { - $foundResources = Find-PSResource -Name "*" -Repository "PoshTestGallery" - - # Should find Module and Script resources but no prerelease resources - $foundResources | where-object Name -eq "test_module" | Should -Not -BeNullOrEmpty -Because "test_module should exist in PoshTestGallery" - $foundResources | where-object Name -eq "test_script" | Should -Not -BeNullOrEmpty -Because "test_script should exist in PoshTestGallery" - $foundResources | where-object IsPrerelease -eq $true | Should -BeNullOrEmpty -Because "No prerelease resources should be returned" - } - - It "should find all resources (including prerelease) given Name that equals wildcard, '*' and Prerelease parameter" { - $foundResources = Find-PSResource -Name "*" -Prerelease -Repository "PoshTestGallery" - - # Should find Module and Script resources inlcuding prerelease resources - $foundResources | where-object Name -eq "test_module" | Should -Not -BeNullOrEmpty -Because "test_module should exist in PoshTestGallery" - $foundResources | where-object Name -eq "test_script" | Should -Not -BeNullOrEmpty -Because "test_script should exist in PoshTestGallery" - $foundResources | where-object IsPrerelease -eq $true | Should -Not -BeNullOrEmpty -Because "Prerelease resources should be returned" - } + # TODO: get working with local repo + # It "should find all resources given Name that equals wildcard, '*'" { + # $repoName = "psgettestlocal" + # Get-ModuleResourcePublishedToLocalRepoTestDrive "TestLocalModule1" $repoName + # Get-ModuleResourcePublishedToLocalRepoTestDrive "TestLocalModule2" $repoName + # Get-ModuleResourcePublishedToLocalRepoTestDrive "TestLocalModule3" $repoName + + # $foundResources = Find-PSResource -Name "TestLocalModule1","TestLocalModule2","TestLocalModule3" -Repository $repoName + # # TODO: wildcard search is not supported with local repositories, from NuGet protocol API side- ask about this. + # # $foundResources = Find-PSResource -Name "*" -Repository $repoName + # $foundResources.Count | Should -Not -Be 0 + + # # Should find Module and Script resources but no prerelease resources + # $foundResources | where-object Name -eq "TestLocalModule1" | Should -Not -BeNullOrEmpty -Because "TestLocalModule1 should exist in local repo" + # $foundResources | where-object Name -eq "test_script" | Should -Not -BeNullOrEmpty -Because "TestLocalScript1 should exist in local repo" + # $foundResources | where-object IsPrerelease -eq $true | Should -BeNullOrEmpty -Because "No prerelease resources should be returned" + # } + + # # TODO: get working with local repo + # It "should find all resources (including prerelease) given Name that equals wildcard, '*' and Prerelease parameter" { + # Get-ModuleResourcePublishedToLocalRepoTestDrive "TestLocalModule1" $repoName + # Get-ModuleResourcePublishedToLocalRepoTestDrive "TestLocalModule2" $repoName + # Get-ModuleResourcePublishedToLocalRepoTestDrive "TestLocalModule3" $repoName + # $foundResources = Find-PSResource -Name "*" -Prerelease -Repository $repoName + + # # Should find Module and Script resources inlcuding prerelease resources + # $foundResources | where-object Name -eq "test_module" | Should -Not -BeNullOrEmpty -Because "test_module should exist in local repo" + # $foundResources | where-object Name -eq "test_script" | Should -Not -BeNullOrEmpty -Because "test_script should exist in local repo" + # $foundResources | where-object IsPrerelease -eq $true | Should -Not -BeNullOrEmpty -Because "Prerelease resources should be returned" + # } It "find resource given Name from V3 endpoint repository (NuGetGallery)" { $res = Find-PSResource -Name "Serilog" -Repository $NuGetGalleryName @@ -86,18 +98,18 @@ Describe 'Test Find-PSResource for Module' { $testCases2 = @{Version="[5.0.0.0]"; ExpectedVersions=@("5.0.0.0"); Reason="validate version, exact match"}, @{Version="5.0.0.0"; ExpectedVersions=@("5.0.0.0"); Reason="validate version, exact match without bracket syntax"}, - @{Version="[2.5.0.0, 5.0.0.0]"; ExpectedVersions=@("2.5.0.0", "3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, exact range inclusive"}, - @{Version="(2.5.0.0, 5.0.0.0)"; ExpectedVersions=@("3.0.0.0", "4.0.0.0"); Reason="validate version, exact range exclusive"}, - @{Version="(2.5.0.0,)"; ExpectedVersions=@("3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, minimum version exclusive"}, - @{Version="[2.5.0.0,)"; ExpectedVersions=@("2.5.0.0", "3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, minimum version inclusive"}, - @{Version="(,2.5.0.0)"; ExpectedVersions=@("1.2.0.0", "1.5.0.0", "2.0.0.0"); Reason="validate version, maximum version exclusive"}, - @{Version="(,2.0.0.0]"; ExpectedVersions=@("1.2.0.0", "1.5.0.0", "2.0.0.0", "2.5.0.0"); Reason="validate version, maximum version inclusive"}, - @{Version="[2.5.0.0, 5.0.0.0)"; ExpectedVersions=@("2.5.0.0", "3.0.0.0", "4.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - @{Version="(2.5.0.0, 5.0.0.0]"; ExpectedVersions=@("3.0.0.0", "4.0.0.0", "5.0.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} + @{Version="[1.0.0.0, 5.0.0.0]"; ExpectedVersions=@("1.0.0.0", "3.0.0.0", "5.0.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 5.0.0.0)"; ExpectedVersions=@("3.0.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersions=@("3.0.0.0", "5.0.0.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersions=@("1.0.0.0", "3.0.0.0", "5.0.0.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,3.0.0.0)"; ExpectedVersions=@("1.0.0.0"); Reason="validate version, maximum version exclusive"}, + @{Version="(,3.0.0.0]"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 5.0.0.0)"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + @{Version="(1.0.0.0, 5.0.0.0]"; ExpectedVersions=@("3.0.0.0", "5.0.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} It "find resource when given Name to " -TestCases $testCases2{ param($Version, $ExpectedVersions) - $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName + $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName foreach ($item in $res) { $item.Name | Should -Be $testModuleName $ExpectedVersions | Should -Contain $item.Version @@ -105,8 +117,8 @@ Describe 'Test Find-PSResource for Module' { } It "not find resource with incorrectly formatted version such as " -TestCases @( - @{Version='(2.5.0.0)'; Description="exclusive version (2.5.0.0)"}, - @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"} + @{Version='(1.0.0.0)'; Description="exclusive version (2.5.0.0)"}, + @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter"} ) { param($Version, $Description) @@ -114,24 +126,24 @@ Describe 'Test Find-PSResource for Module' { $res | Should -BeNullOrEmpty } - $testCases = @{Version='[2.*.0.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, - @{Version='[2.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[2.5.0.*'; Description="version with wildcard at end"}, - @{Version='[2..0.0]'; Description="version with missing digit in middle"}, - @{Version='[2.5.0.]'; Description="version with missing digit at end"}, - @{Version='[2.5.0.0.0]'; Description="version with more than 4 digits"} + $testCases = @{Version='[1.*.0.0]'; Description="version with wilcard in middle"}, + @{Version='[*.0.0.0]'; Description="version with wilcard at start"}, + @{Version='[1.0.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.0.0.*'; Description="version with wildcard at end"}, + @{Version='[1..0.0]'; Description="version with missing digit in middle"}, + @{Version='[1.0.0.]'; Description="version with missing digit at end"}, + @{Version='[1.0.0.0.0]'; Description="version with more than 4 digits"} It "not find resource and throw exception with incorrectly formatted version such as " -TestCases $testCases { param($Version, $Description) - Find-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue + Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "IncorrectVersionFormat,Microsoft.PowerShell.PowerShellGet.Cmdlets.FindPSResource" } - It "find resources when given Name, Version not null --> '*'" { - $res = Find-PSResource -Name $testModuleName -Version "*" -Repository $TestGalleryName + It "find all versions of resource when given Name, Version not null --> '*'" { + $res = Find-PSResource -Name $testModuleName -Version "*" -Repository $PSGalleryName $res | ForEach-Object { $_.Name | Should -Be $testModuleName } @@ -139,7 +151,7 @@ Describe 'Test Find-PSResource for Module' { } It "find resources when given Name with wildcard, Version not null --> '*'" { - $res = Find-PSResource -Name "TestModuleWithDependency*" -Version "*" -Repository $TestGalleryName + $res = Find-PSResource -Name "TestModuleWithDependency*" -Version "*" -Repository $PSGalleryName $moduleA = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyA"} $moduleA.Count | Should -BeGreaterOrEqual 3 $moduleB = $res | Where-Object {$_.Name -eq "TestModuleWithDependencyB"} @@ -155,51 +167,105 @@ Describe 'Test Find-PSResource for Module' { } It "find resources when given Name with wildcard, Version range" { - $res = Find-PSResource -Name "TestModuleWithDependency*" -Version "[1.0.0.0, 2.0.0.0]" -Repository $TestGalleryName + $res = Find-PSResource -Name "TestModuleWithDependency*" -Version "[1.0.0.0, 5.0.0.0]" -Repository $PSGalleryName foreach ($pkg in $res) { $pkg.Name | Should -Match "TestModuleWithDependency*" - [System.Version]$pkg.Version -ge [System.Version]"1.0.0.0" -or [System.Version]$pkg.Version -le [System.Version]"2.0.0.0" | Should -Be $true + [System.Version]$pkg.Version -ge [System.Version]"1.0.0.0" -or [System.Version]$pkg.Version -le [System.Version]"5.0.0.0" | Should -Be $true } } It "find resource when given Name, Version param null" { - $res = Find-PSResource -Name $testModuleName -Repository $TestGalleryName + $res = Find-PSResource -Name $testModuleName -Repository $PSGalleryName $res.Name | Should -Be $testModuleName $res.Version | Should -Be "5.0.0.0" } It "find resource with latest (including prerelease) version given Prerelease parameter" { # test_module resource's latest version is a prerelease version, before that it has a non-prerelease version - $res = Find-PSResource -Name $testModuleName -Repository $TestGalleryName + $res = Find-PSResource -Name $testModuleName -Repository $PSGalleryName $res.Version | Should -Be "5.0.0.0" - $resPrerelease = Find-PSResource -Name $testModuleName -Prerelease -Repository $TestGalleryName + $resPrerelease = Find-PSResource -Name $testModuleName -Prerelease -Repository $PSGalleryName $resPrerelease.Version | Should -Be "5.2.5.0" $resPrerelease.Prerelease | Should -Be "alpha001" } It "find resources, including Prerelease version resources, when given Prerelease parameter" { - $resWithoutPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $TestGalleryName - $resWithPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $TestGalleryName + $resWithoutPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $PSGalleryName + $resWithPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $PSGalleryName $resWithPrerelease.Count | Should -BeGreaterOrEqual $resWithoutPrerelease.Count } - It "find resource of Type script or module from PSGallery/PoshTestGallery, when no Type parameter provided" { - $resScript = Find-PSResource -Name "AzureSqlScale" -Repository $PSGalleryName - $resScript.Name | Should -Be "AzureSqlScale" - $resScript.Type | Should -Be "Script" + It "find resource and its dependency resources with IncludeDependencies parameter" { + $resWithoutDependencies = Find-PSResource -Name "TestModuleWithDependencyE" -Repository $PSGalleryName + $resWithoutDependencies.Count | Should -Be 1 + $resWithoutDependencies.Name | Should -Be "TestModuleWithDependencyE" + + # TestModuleWithDependencyE has the following dependencies: + # TestModuleWithDependencyC <= 1.0.0.0 + # TestModuleWithDependencyB >= 1.0.0.0 + # TestModuleWithDependencyD <= 1.0.0.0 - $resModule = Find-PSResource -Name $testModuleName -Repository $TestGalleryName + $resWithDependencies = Find-PSResource -Name "TestModuleWithDependencyE" -IncludeDependencies -Repository $PSGalleryName + $resWithDependencies.Count | Should -BeGreaterThan $resWithoutDependencies.Count + + $foundParentPkgE = $false + $foundDepB = $false + $foundDepBCorrectVersion = $false + $foundDepC = $false + $foundDepCCorrectVersion = $false + $foundDepD = $false + $foundDepDCorrectVersion = $false + foreach ($pkg in $resWithDependencies) + { + if ($pkg.Name -eq "TestModuleWithDependencyE") + { + $foundParentPkgE = $true + } + elseif ($pkg.Name -eq "TestModuleWithDependencyC") + { + $foundDepC = $true + $foundDepCCorrectVersion = [System.Version]$pkg.Version -le [System.Version]"1.0.0.0" + } + elseif ($pkg.Name -eq "TestModuleWithDependencyB") + { + $foundDepB = $true + $foundDepBCorrectVersion = [System.Version]$pkg.Version -ge [System.Version]"3.0.0.0" + } + elseif ($pkg.Name -eq "TestModuleWithDependencyD") + { + $foundDepD = $true + $foundDepDCorrectVersion = [System.Version]$pkg.Version -le [System.Version]"1.0.0.0" + } + } + + $foundParentPkgE | Should -Be $true + $foundDepC | Should -Be $true + $foundDepCCorrectVersion | Should -Be $true + $foundDepB | Should -Be $true + $foundDepBCorrectVersion | Should -Be $true + $foundDepD | Should -Be $true + $foundDepDCorrectVersion | Should -Be $true + } + + It "find resource of Type script or module from PSGallery, when no Type parameter provided" { + $resScript = Find-PSResource -Name $testScriptName -Repository $PSGalleryName + $resScript.Name | Should -Be $testScriptName + $resScriptType = Out-String -InputObject $resScript.Type + $resScriptType.Replace(",", " ").Split() | Should -Contain "Script" + + $resModule = Find-PSResource -Name $testModuleName -Repository $PSGalleryName $resModule.Name | Should -Be $testModuleName $resModuleType = Out-String -InputObject $resModule.Type $resModuleType.Replace(",", " ").Split() | Should -Contain "Module" } It "find resource of Type Script from PSGallery, when Type Script specified" { - $resScript = Find-PSResource -Name "AzureSqlScale" -Repository $PSGalleryName -Type "Script" - $resScript.Name | Should -Be "AzureSqlScale" + $resScript = Find-PSResource -Name $testScriptName -Repository $PSGalleryName -Type "Script" + $resScript.Name | Should -Be $testScriptName $resScript.Repository | Should -Be "PSGalleryScripts" - $resScript.Type | Should -Be "Script" + $resScriptType = Out-String -InputObject $resScript.Type + $resScriptType.Replace(",", " ").Split() | Should -Contain "Script" } It "find resource of Type Command from PSGallery, when Type Command specified" { @@ -210,10 +276,9 @@ Describe 'Test Find-PSResource for Module' { } } - # Skip test for now because it takes too long to run (> 60 sec) It "find all resources of Type Module when Type parameter set is used" -Skip { $foundScript = $False - $res = Find-PSResource -Type Module -Repository $PSGalleryName + $res = Find-PSResource -Name "test*" -Type Module -Repository $PSGalleryName $res.Count | Should -BeGreaterThan 1 foreach ($item in $res) { if ($item.Type -eq "Script") @@ -237,7 +302,7 @@ Describe 'Test Find-PSResource for Module' { $foundTestModule = $False $foundTestScript = $False $tagToFind = "Tag2" - $res = Find-PSResource -Tag $tagToFind -Repository $TestGalleryName + $res = Find-PSResource -Tag $tagToFind -Repository $PSGalleryName foreach ($item in $res) { $item.Tags -contains $tagToFind | Should -Be $True @@ -256,21 +321,6 @@ Describe 'Test Find-PSResource for Module' { $foundTestScript | Should -Be $True } - It "find resource with IncludeDependencies parameter" { - $res = Find-PSResource -Name "Az.Compute" -IncludeDependencies -Repository $PSGalleryName - $isDependencyNamePresent = $False - $isDependencyVersionCorrect = $False - foreach ($item in $res) { - if ($item.Name -eq "Az.Accounts") - { - $isDependencyNamePresent = $True - $isDependencyVersionCorrect = [System.Version]$item.Version -ge [System.Version]"2.2.8.0" - } - } - $isDependencyNamePresent | Should -BeTrue - $isDependencyVersionCorrect | Should -BeTrue - } - It "find resource in local repository given Repository parameter" { $publishModuleName = "TestFindModule" $repoName = "psgettestlocal" @@ -297,14 +347,14 @@ Describe 'Test Find-PSResource for Module' { $resNonDefault.Repository | Should -Be $repoLowerPriorityRanking } - # Skip test for now because it takes too run (132.24 sec) - It "find resource given CommandName (CommandNameParameterSet)" -Skip { - $res = Find-PSResource -CommandName $commandName -Repository $PSGalleryName - foreach ($item in $res) { - $item.Name | Should -Be $commandName - $item.ParentResource.Includes.Command | Should -Contain $commandName - } - } + # # Skip test for now because it takes too run (132.24 sec) + # It "find resource given CommandName (CommandNameParameterSet)" -Skip { + # $res = Find-PSResource -CommandName $commandName -Repository $PSGalleryName + # foreach ($item in $res) { + # $item.Name | Should -Be $commandName + # $item.ParentResource.Includes.Command | Should -Contain $commandName + # } + # } It "find resource given CommandName and ModuleName (CommandNameParameterSet)" { $res = Find-PSResource -CommandName $commandName -ModuleName $parentModuleName -Repository $PSGalleryName @@ -314,13 +364,13 @@ Describe 'Test Find-PSResource for Module' { } # Skip test for now because it takes too long to run (> 60 sec) - It "find resource given DSCResourceName (DSCResourceNameParameterSet)" -Skip { - $res = Find-PSResource -DscResourceName $dscResourceName -Repository $PSGalleryName - foreach ($item in $res) { - $item.Name | Should -Be $dscResourceName - $item.ParentResource.Includes.DscResource | Should -Contain $dscResourceName - } - } + # It "find resource given DSCResourceName (DSCResourceNameParameterSet)" -Skip { + # $res = Find-PSResource -DscResourceName $dscResourceName -Repository $PSGalleryName + # foreach ($item in $res) { + # $item.Name | Should -Be $dscResourceName + # $item.ParentResource.Includes.DscResource | Should -Contain $dscResourceName + # } + # } It "find resource given DscResourceName and ModuleName (DSCResourceNameParameterSet)" { $res = Find-PSResource -DscResourceName $dscResourceName -ModuleName $parentModuleName -Repository $PSGalleryName diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 986f25c59..1f3492921 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -7,19 +7,21 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Get-PSResource for Module' { BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName $testModuleName = "test_module" $testScriptName = "test_script" Get-NewPSResourceRepositoryFile - Install-PSResource -Name ContosoServer -Repository $TestGalleryName -Verbose - Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "2.0" - Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "1.5" - Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -Version "1.0" - Install-PSResource TestTestScript -Repository $TestGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Verbose + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Version "1.0" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Version "3.0" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Version "5.0" + Install-PSResource -Name $testScriptName -Repository $PSGalleryName -TrustRepository } AfterAll { + Uninstall-PSResource -Name $testModuleName -Version "*" + Uninstall-PSResource -Name $testScriptName -Version "*" Get-RevertPSResourceRepositoryFile } @@ -29,59 +31,59 @@ Describe 'Test Get-PSResource for Module' { } It "Get specific module resource by name" { - $pkg = Get-PSResource -Name ContosoServer - $pkg.Name | Should -Contain "ContosoServer" + $pkg = Get-PSResource -Name $testModuleName + $pkg.Name | Should -Contain $testModuleName } It "Get specific script resource by name" { - $pkg = Get-PSResource -Name TestTestScript - $pkg.Name | Should -Be "TestTestScript" + $pkg = Get-PSResource -Name $testScriptName + $pkg.Name | Should -Be $testScriptName } It "Get resource when given Name to " -TestCases @( - @{Name="*tosoSer*"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard at beginning and end of name: *tosoSer*"}, - @{Name="ContosoSer*"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard at end of name: ContosoSer*"}, - @{Name="*tosoServer"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard at beginning of name: *tosoServer"}, - @{Name="Cont*erver"; ExpectedName="ContosoServer"; Reason="validate name, with wildcard in middle of name: Cont*erver"} + @{Name="*est_modul*"; ExpectedName=$testModuleName; Reason="validate name, with wildcard at beginning and end of name: *est_modul*"}, + @{Name="test_mod*"; ExpectedName=$testModuleName; Reason="validate name, with wildcard at end of name: test_mod*"}, + @{Name="*est_module"; ExpectedName=$testModuleName; Reason="validate name, with wildcard at beginning of name: *est_module"}, + @{Name="tes*ule"; ExpectedName=$testModuleName; Reason="validate name, with wildcard in middle of name: tes*ule"} ) { param($Version, $ExpectedVersion) $pkgs = Get-PSResource -Name $Name - $pkgs.Name | Should -Contain "ContosoServer" + $pkgs.Name | Should -Contain $testModuleName } $testCases = - @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion=@("2.5.0.0", "2.0.0.0", "1.5.0.0", "1.0.0.0"); Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion=@("2.0.0.0", "1.5.0.0"); Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion=@("2.5.0.0", "2.0.0.0", "1.5.0.0"); Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion=@("2.5.0.0", "2.0.0.0", "1.5.0.0", "1.0.0.0"); Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion=@("1.5.0.0", "1.0.0.0"); Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion=@("2.0.0.0", "1.5.0.0", "1.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + @{Version="[1.0.0.0]"; ExpectedVersion="1.0.0.0"; Reason="validate version, exact match"}, + @{Version="1.0.0.0"; ExpectedVersion="1.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 5.0.0.0]"; ExpectedVersion=@("5.0.0.0", "3.0.0.0", "1.0.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 5.0.0.0)"; ExpectedVersion=@("3.0.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion=@("5.0.0.0", "3.0.0.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion=@("5.0.0.0", "3.0.0.0", "1.0.0.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,5.0.0.0)"; ExpectedVersion=@("3.0.0.0", "1.0.0.0"); Reason="validate version, maximum version exclusive"}, + @{Version="(,5.0.0.0]"; ExpectedVersion=@("5.0.0.0", "3.0.0.0", "1.0.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 5.0.0.0)"; ExpectedVersion=@("3.0.0.0", "1.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} It "Get resource when given Name to " -TestCases $testCases { param($Version, $ExpectedVersion) - $pkgs = Get-PSResource -Name "ContosoServer" -Version $Version - $pkgs.Name | Should -Contain "ContosoServer" + $pkgs = Get-PSResource -Name $testModuleName -Version $Version + $pkgs.Name | Should -Contain $testModuleName $pkgs.Version | Should -Be $ExpectedVersion } It "Throw invalid version error when passing incorrectly formatted version such as " -TestCases @( @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[*.0.0.0]'; Description="version with wilcard at start"}, @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*'; Description="version with wildcard at end"}, + @{Version='[1.0.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.0.0.*'; Description="version with wildcard at end"}, @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + @{Version='[1.0.0.]'; Description="version with missing digit at end"}, + @{Version='[1.0.0.0.0]'; Description="version with more than 4 digits"} ) { param($Version, $Description) $res = $null try { - $res = Find-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore + $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -ErrorAction Ignore } catch {} @@ -90,15 +92,15 @@ $testCases = # These versions technically parse into proper NuGet versions, but will not return the version expected It "Does not return resource when passing incorrectly formatted version such as , does not throw error" -TestCases @( - @{Version='(1.5.0.0)'; Description="exlcusive version (8.1.0.0)"}, - @{Version='[1-5-0-0]'; Description="version formatted with invalid delimiter"} + @{Version='(1.0.0.0)'; Description="exlcusive version (8.1.0.0)"}, + @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter"} ) { param($Version, $Description) $res = $null try { - $res = Find-PSResource -Name "ContosoServer" -Version $Version -Repository $TestGalleryName -ErrorAction Ignore + $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -ErrorAction Ignore } catch {} @@ -106,12 +108,12 @@ $testCases = } It "Get resources when given Name, and Version is '*'" { - $pkgs = Get-PSResource -Name ContosoServer -Version "*" + $pkgs = Get-PSResource -Name $testModuleName -Version "*" $pkgs.Count | Should -BeGreaterOrEqual 2 } It "Get prerelease version module when version with correct prerelease label is specified" { - Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName -Version "5.2.5" $res | Should -BeNullOrEmpty $res = Get-PSResource -Name $testModuleName -Version "5.2.5-alpha001" @@ -121,12 +123,12 @@ $testCases = } It "Get prerelease version script when version with correct prerelease label is specified" { - Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha" -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testScriptName -Version "3.0.0" $res | Should -BeNullOrEmpty - $res = Get-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res = Get-PSResource -Name $testScriptName -Version "3.0.0-alpha" $res.Name | Should -Be $testScriptName $res.Version | Should -Be "3.0.0" - $res.Prerelease | Should -Be "alpha001" + $res.Prerelease | Should -Be "alpha" } } diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index fae7b83bf..c6f173483 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -7,10 +7,11 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Install-PSResource for Module' { BeforeAll { - $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName - $testModuleName = "TestModule" + $testModuleName = "test_module" + $testModuleName2 = "TestModule99" + $testScriptName = "test_script" $RequiredResourceJSONFileName = "TestRequiredResourceFile.json" $RequiredResourcePSD1FileName = "TestRequiredResourceFile.psd1" Get-NewPSResourceRepositoryFile @@ -18,9 +19,7 @@ Describe 'Test Install-PSResource for Module' { } AfterEach { - Uninstall-PSResource "TestModule", "TestModule99", "myTestModule", "myTestModule2", "testModulePrerelease", - "testModuleWithlicense","PSGetTestModule", "PSGetTestDependency1", "TestFindModule","ClobberTestModule1", - "ClobberTestModule2" -SkipDependencyCheck -ErrorAction SilentlyContinue + Uninstall-PSResource "test_module", "test_module2", "test_script", "TestModule99", "testModuleWithlicense", "TestFindModule","ClobberTestModule1", "ClobberTestModule2" -SkipDependencyCheck -ErrorAction SilentlyContinue } AfterAll { @@ -28,7 +27,7 @@ Describe 'Test Install-PSResource for Module' { } $testCases = @{Name="*"; ErrorId="NameContainsWildcard"}, - @{Name="TestModule*"; ErrorId="NameContainsWildcard"}, + @{Name="Test_Module*"; ErrorId="NameContainsWildcard"}, @{Name="Test?Module","Test[Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"} It "Should not install resource with wildcard in name" -TestCases $testCases { @@ -39,29 +38,29 @@ Describe 'Test Install-PSResource for Module' { } It "Install specific module resource by name" { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.3.0" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" } It "Install specific script resource by name" { - Install-PSResource -Name "TestTestScript" -Repository $TestGalleryName - $pkg = Get-PSResource "TestTestScript" - $pkg.Name | Should -Be "TestTestScript" - $pkg.Version | Should -Be "1.3.1.0" + Install-PSResource -Name $testScriptName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testScriptName + $pkg.Name | Should -Be $testScriptName + $pkg.Version | Should -Be "3.5.0.0" } It "Install multiple resources by name" { - $pkgNames = @("TestModule","TestModule99") - Install-PSResource -Name $pkgNames -Repository $TestGalleryName - $pkg = Get-Module $pkgNames -ListAvailable + $pkgNames = @($testModuleName,$testModuleName2) + Install-PSResource -Name $pkgNames -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $pkgNames $pkg.Name | Should -Be $pkgNames } It "Should not install resource given nonexistant name" { - Install-PSResource -Name "NonExistantModule" -Repository $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue - $pkg = Get-Module "NonExistantModule" -ListAvailable + Install-PSResource -Name "NonExistantModule" -Repository $PSGalleryName -TrustRepository -ErrorVariable err -ErrorAction SilentlyContinue + $pkg = Get-PSResource "NonExistantModule" $pkg.Name | Should -BeNullOrEmpty $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" @@ -69,157 +68,162 @@ Describe 'Test Install-PSResource for Module' { # Do some version testing, but Find-PSResource should be doing thorough testing It "Should install resource given name and exact version" { - Install-PSResource -Name "TestModule" -Version "1.2.0" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.2.0" + Install-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "1.0.0.0" } It "Should install resource given name and exact version with bracket syntax" { - Install-PSResource -Name "TestModule" -Version "[1.2.0]" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.2.0" + Install-PSResource -Name $testModuleName -Version "[1.0.0]" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "1.0.0.0" } - It "Should install resource given name and exact range inclusive [1.0.0, 1.1.1]" { - Install-PSResource -Name "TestModule" -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.1.1" + It "Should install resource given name and exact range inclusive [1.0.0, 5.0.0]" { + Install-PSResource -Name $testModuleName -Version "[1.0.0, 5.0.0]" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" } - It "Should install resource given name and exact range exclusive (1.0.0, 1.1.1)" { - Install-PSResource -Name "TestModule" -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.1" + It "Should install resource given name and exact range exclusive (1.0.0, 5.0.0)" { + Install-PSResource -Name $testModuleName -Version "(1.0.0, 5.0.0)" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "3.0.0.0" } It "Should not install resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, - @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + @{Version='(1.0.0.0)'; Description="exclusive version (1.0.0.0)"}, + @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter [1-0-0-0]"} ) { param($Version, $Description) - Install-PSResource -Name "TestModule" -Version $Version -Repository $TestGalleryName -ErrorAction SilentlyContinue + Install-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue $Error[0].FullyQualifiedErrorId | Should -be "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" - $res = Get-Module "TestModule" -ListAvailable + $res = Get-PSResource $testModuleName $res | Should -BeNullOrEmpty } It "Install resource when given Name, Version '*', should install the latest version" { - Install-PSResource -Name "TestModule" -Version "*" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.3.0" + Install-PSResource -Name $testModuleName -Version "*" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" } It "Install resource with latest (including prerelease) version given Prerelease parameter" { - Install-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName - $pkg = Get-Module "TestModulePrerelease" -ListAvailable - $pkg.Name | Should -Be "TestModulePrerelease" - $pkg.Version | Should -Be "0.0.1" - $pkg.PrivateData.PSData.Prerelease | Should -Be "preview" + Install-PSResource -Name $testModuleName -Prerelease -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.2.5" + $pkg.Prerelease | Should -Be "alpha001" } It "Install a module with a dependency" { - Install-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName - $pkg = Get-Module "PSGetTestModule" -ListAvailable - $pkg.Name | Should -Be "PSGetTestModule" - $pkg.Version | Should -Be "2.0.2" - $pkg.PrivateData.PSData.Prerelease | Should -Be "-alpha1" + Uninstall-PSResource -Name "TestModuleWithDependency*" -Version "*" -SkipDependencyCheck + Install-PSResource -Name "TestModuleWithDependencyC" -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - $pkg = Get-Module "PSGetTestDependency1" -ListAvailable - $pkg.Name | Should -Be "PSGetTestDependency1" - $pkg.Version | Should -Be "1.0.0" + $pkg = Get-PSResource "TestModuleWithDependencyC" + $pkg.Name | Should -Be "TestModuleWithDependencyC" + $pkg.Version | Should -Be "1.0.0.0" + + $pkg = Get-PSResource "TestModuleWithDependencyB" + $pkg.Name | Should -Be "TestModuleWithDependencyB" + $pkg.Version | Should -Be "3.0.0.0" + + $pkg = Get-PSResource "TestModuleWithDependencyD" + $pkg.Name | Should -Be "TestModuleWithDependencyD" + $pkg.Version | Should -Be "1.0.0.0" } It "Install a module with a dependency and skip installing the dependency" { - Install-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -SkipDependencyCheck - $pkg = Get-Module "PSGetTestModule" -ListAvailable - $pkg.Name | Should -Be "PSGetTestModule" - $pkg.Version | Should -Be "2.0.2" - $pkg.PrivateData.PSData.Prerelease | Should -Be "-alpha1" + Uninstall-PSResource -Name "TestModuleWithDependency*" -Version "*" -SkipDependencyCheck + Install-PSResource -Name "TestModuleWithDependencyC" -Version "1.0.0.0" -SkipDependencyCheck -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource "TestModuleWithDependencyC" + $pkg.Name | Should -Be "TestModuleWithDependencyC" + $pkg.Version | Should -Be "1.0.0.0" - $pkg = Get-Module "PSGetTestDependency1" -ListAvailable + $pkg = Get-PSResource "TestModuleWithDependencyB", "TestModuleWithDependencyD" $pkg | Should -BeNullOrEmpty } It "Install resource via InputObject by piping from Find-PSresource" { - Find-PSResource -Name "TestModule" -Repository $TestGalleryName | Install-PSResource - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.3.0" + Find-PSResource -Name $testModuleName -Repository $PSGalleryName | Install-PSResource -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" } # Windows only It "Install resource under CurrentUser scope - Windows only" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("Documents") | Should -Be $true + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope CurrentUser + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.InstalledLocation.ToString().Contains("Documents") | Should -Be $true } # Windows only It "Install resource under AllUsers scope - Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope AllUsers - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("Program Files") | Should -Be $true + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.InstalledLocation.ToString().Contains("Program Files") | Should -Be $true } # Windows only It "Install resource under no specified scope - Windows only" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("Documents") | Should -Be $true + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.InstalledLocation.ToString().Contains("Documents") | Should -Be $true } # Unix only # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' It "Install resource under CurrentUser scope - Unix only" -Skip:(Get-IsWindows) { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Scope CurrentUser - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("$env:HOME/.local") | Should -Be $true + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope CurrentUser + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.InstalledLocation.ToString().Contains("$env:HOME/.local") | Should -Be $true } # Unix only # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' It "Install resource under no specified scope - Unix only" -Skip:(Get-IsWindows) { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Path.Contains("$env:HOME/.local") | Should -Be $true + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.InstalledLocation.ToString().Contains("$env:HOME/.local") | Should -Be $true } It "Should not install resource that is already installed" { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -WarningVariable WarningVar -warningaction SilentlyContinue + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -WarningVariable WarningVar -warningaction SilentlyContinue $WarningVar | Should -Not -BeNullOrEmpty } It "Reinstall resource that is already installed with -Reinstall parameter" { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.3.0" - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Reinstall - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.3.0" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -Reinstall -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" } It "Restore resource after reinstall fails" { - Install-PSResource -Name "TestModule" -Repository $TestGalleryName - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" - $pkg.Version | Should -Be "1.3.0" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-Module $testModuleName -ListAvailable + $pkg.Name | Should -Be $testModuleName + $pkg.Version | Should -Be "5.0.0.0" $resourcePath = Split-Path -Path $pkg.Path -Parent $resourceFiles = Get-ChildItem -Path $resourcePath -Recurse @@ -229,7 +233,7 @@ Describe 'Test Install-PSResource for Module' { try { # Reinstall of resource should fail with one of its files locked. - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -Reinstall -ErrorVariable ev -ErrorAction Silent + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Reinstall -ErrorVariable ev -ErrorAction Silent $ev.FullyQualifiedErrorId | Should -BeExactly 'InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource' } finally @@ -241,33 +245,23 @@ Describe 'Test Install-PSResource for Module' { (Get-ChildItem -Path $resourcePath -Recurse).Count | Should -BeExactly $resourceFiles.Count } - It "Install resource that requires accept license with -AcceptLicense flag" { - Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName -AcceptLicense - $pkg = Get-PSResource "testModuleWithlicense" - $pkg.Name | Should -Be "testModuleWithlicense" - $pkg.Version | Should -Be "0.0.3.0" - } - - It "Install resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { - Set-PSResourceRepository PoshTestGallery -Trusted:$false - - Install-PSResource -Name "TestModule" -Repository $TestGalleryName -TrustRepository - - $pkg = Get-Module "TestModule" -ListAvailable - $pkg.Name | Should -Be "TestModule" + # It "Install resource that requires accept license with -AcceptLicense flag" { + # Install-PSResource -Name "testModuleWithlicense" -Repository $TestGalleryName -AcceptLicense + # $pkg = Get-PSResource "testModuleWithlicense" + # $pkg.Name | Should -Be "testModuleWithlicense" + # $pkg.Version | Should -Be "0.0.3.0" + # } - Set-PSResourceRepository PoshTestGallery -Trusted - } It "Install resource with cmdlet names from a module already installed (should clobber)" { - Install-PSResource -Name "myTestModule" -Repository $TestGalleryName - $pkg = Get-PSResource "myTestModule" - $pkg.Name | Should -Be "myTestModule" - $pkg.Version | Should -Be "0.0.3.0" - - Install-PSResource -Name "myTestModule2" -Repository $TestGalleryName - $pkg = Get-PSResource "myTestModule2" - $pkg.Name | Should -Be "myTestModule2" + Install-PSResource -Name "CLobberTestModule1" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource "ClobberTestModule1" + $pkg.Name | Should -Be "ClobberTestModule1" + $pkg.Version | Should -Be "0.0.1.0" + + Install-PSResource -Name "ClobberTestModule2" -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource "ClobberTestModule2" + $pkg.Name | Should -Be "ClobberTestModule2" $pkg.Version | Should -Be "0.0.1.0" } @@ -278,144 +272,148 @@ Describe 'Test Install-PSResource for Module' { Set-PSResourceRepository "psgettestlocal" -Trusted:$true Install-PSResource -Name $publishModuleName -Repository $repoName - $pkg = Get-Module $publishModuleName -ListAvailable + $pkg = Get-PSResource $publishModuleName $pkg | Should -Not -BeNullOrEmpty $pkg.Name | Should -Be $publishModuleName } It "Install module using -WhatIf, should not install the module" { - Install-PSResource -Name "TestModule" -WhatIf + Install-PSResource -Name $testModuleName -WhatIf - $res = Get-Module "TestModule" -ListAvailable + $res = Get-PSResource $testModuleName $res | Should -BeNullOrEmpty } It "Validates that a module with module-name script files (like Pester) installs under Modules path" { - Install-PSResource -Name "testModuleWithScript" -Repository $TestGalleryName + Install-PSResource -Name "testModuleWithScript" -Repository $PSGalleryName -TrustRepository - $res = Get-Module "testModuleWithScript" -ListAvailable - $res.Path.Contains("Modules") | Should -Be $true + $res = Get-PSResource "testModuleWithScript" + $res.InstalledLocation.ToString().Contains("Modules") | Should -Be $true } It "Install module using -NoClobber, should throw clobber error and not install the module" { - Install-PSResource -Name "ClobberTestModule1" -Repository $TestGalleryName + Install-PSResource -Name "ClobberTestModule1" -Repository $PSGalleryName -TrustRepository - $res = Get-Module "ClobberTestModule1" -ListAvailable + $res = Get-PSResource "ClobberTestModule1" $res.Name | Should -Be "ClobberTestModule1" - Install-PSResource -Name "ClobberTestModule2" -Repository $TestGalleryName -NoClobber -ErrorAction SilentlyContinue + Install-PSResource -Name "ClobberTestModule2" -Repository $PSGalleryName -TrustRepository -NoClobber -ErrorAction SilentlyContinue $Error[0].FullyQualifiedErrorId | Should -be "CommandAlreadyExists,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } - It "Install PSResourceInfo object piped in" { - Find-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName | Install-PSResource + + It "Install PSResourceInfo object piped in" { + Find-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName | Install-PSResource -TrustRepository $res = Get-PSResource -Name $testModuleName $res.Name | Should -Be $testModuleName - $res.Version | Should -Be "1.1.0.0" + $res.Version | Should -Be "1.0.0.0" } It "Install module using -PassThru" { - $res = Install-PSResource -Name "TestModule" -Version "1.3.0" -Repository $TestGalleryName -PassThru - $res.Name | Should -Be "TestModule" - $res.Version | Should -Be "1.3.0.0" + $res = Install-PSResource -Name $testModuleName -Repository $PSGalleryName -PassThru -TrustRepository + $res.Name | Should -Contain $testModuleName } It "Install modules using -RequiredResource with hashtable" { $rrHash = @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = $TestGalleryName + test_module = @{ + version = "[1.0.0,5.0.0)" + repository = $PSGalleryName } - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = $TestGalleryName + test_module2 = @{ + version = "[1.0.0,3.0.0)" + repository = $PSGalleryName prerelease = "true" } - TestModule99 = @{ - } + TestModule99 = @{} } - Install-PSResource -RequiredResource $rrHash + Install-PSResource -RequiredResource $rrHash -TrustRepository - $res1 = Get-Module "TestModule" -ListAvailable - $res1.Name | Should -Be "TestModule" - $res1.Version | Should -Be "1.3.0" + $res1 = Get-PSResource $testModuleName + $res1.Name | Should -Be $testModuleName + $res1.Version | Should -Be "3.0.0.0" - $res2 = Get-Module "TestModulePrerelease" -ListAvailable - $res2.Name | Should -Be "TestModulePrerelease" - $res2.Version | Should -Be "0.0.1" + $res2 = Get-PSResource "test_module2" -Version "2.5.0-beta" + $res2.Name | Should -Be "test_module2" + $res2.Version | Should -Be "2.5.0" + $res2.Prerelease | Should -Be "beta" - $res3 = Get-Module "TestModule99" -ListAvailable - $res3.Name | Should -Be "TestModule99" - $res3.Version | Should -Be "0.0.5" + $res3 = Get-PSResource $testModuleName2 + $res3.Name | Should -Be $testModuleName2 + $res3.Version | Should -Be "0.0.93.0" } It "Install modules using -RequiredResource with JSON string" { $rrJSON = "{ - 'TestModule': { - 'version': '[0.0.1,1.3.0]', - 'repository': 'PoshTestGallery' + 'test_module': { + 'version': '[1.0.0,5.0.0)', + 'repository': 'PSGallery' }, - 'TestModulePrerelease': { - 'version': '[0.0.0,0.0.5]', - 'repository': 'PoshTestGallery', + 'test_module2': { + 'version': '[1.0.0,3.0.0)', + 'repository': 'PSGallery', 'prerelease': 'true' }, 'TestModule99': { + 'repository': 'PSGallery' } }" - Install-PSResource -RequiredResource $rrJSON + Install-PSResource -RequiredResource $rrJSON -TrustRepository - $res1 = Get-Module "TestModule" -ListAvailable - $res1.Name | Should -Be "TestModule" - $res1.Version | Should -Be "1.3.0" + $res1 = Get-PSResource $testModuleName + $res1.Name | Should -Be $testModuleName + $res1.Version | Should -Be "3.0.0.0" - $res2 = Get-Module "TestModulePrerelease" -ListAvailable - $res2.Name | Should -Be "TestModulePrerelease" - $res2.Version | Should -Be "0.0.1" + $res2 = Get-PSResource "test_module2" -Version "2.5.0-beta" + $res2.Name | Should -Be "test_module2" + $res2.Version | Should -Be "2.5.0" + $res2.Prerelease | Should -Be "beta" - $res3 = Get-Module "TestModule99" -ListAvailable - $res3.Name | Should -Be "TestModule99" - $res3.Version | Should -Be "0.0.5" + $res3 = Get-PSResource $testModuleName2 + $res3.Name | Should -Be $testModuleName2 + $res3.Version | Should -Be "0.0.93.0" } It "Install modules using -RequiredResourceFile with PSD1 file" { $rrFilePSD1 = Join-Path -Path $psscriptroot -ChildPath $RequiredResourcePSD1FileName - Install-PSResource -RequiredResourceFile $rrFilePSD1 + Install-PSResource -RequiredResourceFile $rrFilePSD1 -TrustRepository - $res1 = Get-Module "TestModule" -ListAvailable - $res1.Name | Should -Be "TestModule" - $res1.Version | Should -Be "1.3.0" + $res1 = Get-PSResource $testModuleName + $res1.Name | Should -Be $testModuleName + $res1.Version | Should -Be "3.0.0.0" - $res2 = Get-Module "TestModulePrerelease" -ListAvailable - $res2.Name | Should -Be "TestModulePrerelease" - $res2.Version | Should -Be "0.0.1" + $res2 = Get-PSResource "test_module2" -Version "2.5.0-beta" + $res2.Name | Should -Be "test_module2" + $res2.Version | Should -Be "2.5.0" + $res2.Prerelease | Should -Be "beta" - $res3 = Get-Module "TestModule99" -ListAvailable - $res3.Name | Should -Be "TestModule99" - $res3.Version | Should -Be "0.0.5" + $res3 = Get-PSResource $testModuleName2 + $res3.Name | Should -Be $testModuleName2 + $res3.Version | Should -Be "0.0.93.0" } It "Install modules using -RequiredResourceFile with JSON file" { $rrFileJSON = Join-Path -Path $psscriptroot -ChildPath $RequiredResourceJSONFileName - Install-PSResource -RequiredResourceFile $rrFileJSON + Install-PSResource -RequiredResourceFile $rrFileJSON -TrustRepository - $res1 = Get-Module "TestModule" -ListAvailable - $res1.Name | Should -Be "TestModule" - $res1.Version | Should -Be "1.2.0" + $res1 = Get-PSResource $testModuleName + $res1.Name | Should -Be $testModuleName + $res1.Version | Should -Be "3.0.0.0" - $res2 = Get-Module "TestModulePrerelease" -ListAvailable - $res2.Name | Should -Be "TestModulePrerelease" - $res2.Version | Should -Be "0.0.1" + $res2 = Get-PSResource "test_module2" -Version "2.5.0-beta" + $res2.Name | Should -Be "test_module2" + $res2.Version | Should -Be "2.5.0" + $res2.Prerelease | Should -Be "beta" - $res3 = Get-Module "TestModule99" -ListAvailable - $res3.Name | Should -Be "TestModule99" - $res3.Version | Should -Be "0.0.5" + $res3 = Get-PSResource $testModuleName2 + $res3.Name | Should -Be $testModuleName2 + $res3.Version | Should -Be "0.0.93.0" } } diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 6704ee72b..8160144bc 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -7,12 +7,11 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Save-PSResource for PSResources' { BeforeAll { - $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "test_module" - $testModuleName2 = "TestModule" - $testScriptName = "TestTestScript" + $testScriptName = "test_script" + $testModuleName2 = "testmodule99" Get-NewPSResourceRepositoryFile Register-LocalRepos @@ -30,30 +29,30 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save specific module resource by name" { - Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 } It "Save specific script resource by name" { - Save-PSResource -Name $testScriptName -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestTestScript.ps1" + Save-PSResource -Name $testScriptName -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "test_script.ps1" $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem $pkgDir.FullName).Count | Should -Be 1 } It "Save multiple resources by name" { - $pkgNames = @("TestModule","TestModule99") - Save-PSResource -Name $pkgNames -Repository $TestGalleryName -Path $SaveDir - $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "TestModule" -or $_.Name -eq "TestModule99" } + $pkgNames = @($testModuleName, $testModuleName2) + Save-PSResource -Name $pkgNames -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq $testModuleName -or $_.Name -eq $testModuleName2 } $pkgDirs.Count | Should -Be 2 (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 } It "Should not save resource given nonexistant name" { - Save-PSResource -Name NonExistentModule -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue + Save-PSResource -Name NonExistentModule -Repository $PSGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue -TrustRepository $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "NonExistentModule" $pkgDir.Name | Should -BeNullOrEmpty $err.Count | Should -Not -Be 0 @@ -61,108 +60,96 @@ Describe 'Test Save-PSResource for PSResources' { } It "Not Save module with Name containing wildcard" { - Save-PSResource -Name "TestModule*" -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue + Save-PSResource -Name "TestModule*" -Repository $PSGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue -TrustRepository $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "NameContainsWildcard,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } # Do some version testing, but Find-PSResource should be doing thorough testing It "Should save resource given name and exact version" { - Save-PSResource -Name $testModuleName2 -Version "1.2.0" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.2.0" + $pkgDirVersion.Name | Should -Be "1.0.0.0" } It "Should save resource given name and exact version with bracket syntax" { - Save-PSResource -Name $testModuleName2 -Version "[1.2.0]" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Version "[1.0.0]" -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.2.0" + $pkgDirVersion.Name | Should -Be "1.0.0.0" } - It "Should save resource given name and exact range inclusive [1.0.0, 1.1.1]" { - Save-PSResource -Name $testModuleName2 -Version "[1.0.0, 1.1.1]" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + It "Should save resource given name and exact range inclusive [1.0.0, 3.0.0]" { + Save-PSResource -Name $testModuleName -Version "[1.0.0, 3.0.0]" -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.1.1" + $pkgDirVersion.Name | Should -Be "3.0.0.0" } - It "Should save resource given name and exact range exclusive (1.0.0, 1.1.1)" { - Save-PSResource -Name $testModuleName2 -Version "(1.0.0, 1.1.1)" -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + It "Should save resource given name and exact range exclusive (1.0.0, 5.0.0)" { + Save-PSResource -Name $testModuleName -Version "(1.0.0, 5.0.0)" -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.1" + $pkgDirVersion.Name | Should -Be "3.0.0.0" } It "Should not save resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, - @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + @{Version='(1.0.0.0)'; Description="exclusive version (1.0.0.0)"}, + @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter [1-0-0-0]"} ) { param($Version, $Description) - Save-PSResource -Name $testModuleName2 -Version $Version -Repository $TestGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -BeNullOrEmpty $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } It "Save resource when given Name, Version '*', should install the latest version" { - Save-PSResource -Name $testModuleName2 -Version "*" -Repository $TestGalleryName -Path $SaveDir -ErrorAction SilentlyContinue - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Version "*" -Repository $PSGalleryName -Path $SaveDir -ErrorAction SilentlyContinue -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" + $pkgDirVersion.Name | Should -Be "5.0.0.0" } It "Save resource with latest (including prerelease) version given Prerelease parameter" { - Save-PSResource -Name "TestModulePrerelease" -Prerelease -Repository $TestGalleryName -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "TestModulePrerelease" + Save-PSResource -Name $testModuleName -Prerelease -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "0.0.1" + $pkgDirVersion.Name | Should -Be "5.2.5" } It "Save a module with a dependency" { - Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir - $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } - $pkgDirs.Count | Should -Be 2 + Save-PSResource -Name "TestModuleWithDependencyE" -Version "1.0.0.0" -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "TestModuleWithDependencyE" -or $_.Name -eq "TestModuleWithDependencyC" -or $_.Name -eq "TestModuleWithDependencyB" -or $_.Name -eq "TestModuleWithDependencyD"} + $pkgDirs.Count | Should -Be 4 (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 (Get-ChildItem $pkgDirs[1].FullName).Count | Should -Be 1 + (Get-ChildItem $pkgDirs[2].FullName).Count | Should -Be 1 + (Get-ChildItem $pkgDirs[3].FullName).Count | Should -Be 1 } It "Save a module with a dependency and skip saving the dependency" { - Save-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName -Path $SaveDir -SkipDependencyCheck - $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "PSGetTestModule" -or $_.Name -eq "PSGetTestDependency1" } + Save-PSResource -Name "TestModuleWithDependencyE" -Version "1.0.0.0" -SkipDependencyCheck -Repository $PSGalleryName -Path $SaveDir -TrustRepository + $pkgDirs = Get-ChildItem -Path $SaveDir | Where-Object { $_.Name -eq "TestModuleWithDependencyE"} $pkgDirs.Count | Should -Be 1 (Get-ChildItem $pkgDirs[0].FullName).Count | Should -Be 1 } It "Save resource via InputObject by piping from Find-PSresource" { - Find-PSResource -Name $testModuleName2 -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Find-PSResource -Name $testModuleName -Repository $PSGalleryName | Save-PSResource -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" - } - - It "Save resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { - try { - Set-PSResourceRepository PoshTestGallery -Trusted:$false - Save-PSResource -Name $testModuleName2 -Repository $TestGalleryName -TrustRepository -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 - $pkgDir | Should -Not -BeNullOrEmpty - $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" - } - finally { - Set-PSResourceRepository PoshTestGallery -Trusted - } + $pkgDirVersion.Name | Should -Be "5.0.0.0" } It "Save resource from local repository given Repository parameter" { @@ -178,58 +165,57 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save specific module resource by name when no repository is specified" { - Set-PSResourceRepository "PoshTestGallery" -Trusted:$True Set-PSResourceRepository "PSGallery" -Trusted:$True Set-PSResourceRepository "psgettestlocal2" -Trusted:$True - Save-PSResource -Name "TestModule" -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Path $SaveDir + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } It "Save PSResourceInfo object piped in" { - Find-PSResource -Name $testModuleName2 -Version "1.1.0.0" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Find-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName | Save-PSResource -Path $SaveDir -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } It "Save PSResourceInfo object piped in for prerelease version object" { - Find-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName | Save-PSResource -Path $SaveDir + Find-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName | Save-PSResource -Path $SaveDir $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty (Get-ChildItem -Path $pkgDir.FullName).Count | Should -Be 1 } It "Save module as a nupkg" { - Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -AsNupkg + Save-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -Path $SaveDir -AsNupkg -TrustRepository write-host $SaveDir write-host - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testmodule.1.3.0.nupkg" + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "test_module.1.0.0.nupkg" $pkgDir | Should -Not -BeNullOrEmpty } It "Save script as a nupkg" { - Save-PSResource -Name $testScriptName -Version "1.3.1" -Repository $TestGalleryName -Path $SaveDir -AsNupkg - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "testtestscript.1.3.1.nupkg" + Save-PSResource -Name $testScriptName -Version "2.5.0" -Repository $PSGalleryName -Path $SaveDir -AsNupkg -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "test_script.2.5.0.nupkg" $pkgDir | Should -Not -BeNullOrEmpty } It "Save module and include XML metadata file" { - Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -IncludeXML - $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName2 + Save-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -Path $SaveDir -IncludeXML -TrustRepository + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName - $pkgDirVersion.Name | Should -Be "1.3.0" + $pkgDirVersion.Name | Should -Be "1.0.0.0" $xmlFile = Get-ChildItem -Path $pkgDirVersion.FullName | Where-Object Name -eq "PSGetModuleInfo.xml" $xmlFile | Should -Not -BeNullOrEmpty } It "Save module using -PassThru" { - $res = Save-PSResource -Name $testModuleName2 -Version "1.3.0" -Repository $TestGalleryName -Path $SaveDir -PassThru - $res.Name | Should -Be $testModuleName2 - $res.Version | Should -Be "1.3.0.0" + $res = Save-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -Path $SaveDir -PassThru -TrustRepository + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "1.0.0.0" } <# # Tests should not write to module directory diff --git a/test/TestRequiredResourceFile.json b/test/TestRequiredResourceFile.json index 6d6c04e9f..5c193eac4 100644 --- a/test/TestRequiredResourceFile.json +++ b/test/TestRequiredResourceFile.json @@ -1,12 +1,14 @@ { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PoshTestGallery" + "test_module": { + "version": "[1.0.0,5.0.0)", + "repository": "PSGallery" }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PoshTestGallery", + "test_module2": { + "version": "[1.0.0,3.0.0)", + "repository": "PSGallery", "prerelease": "true" }, - "TestModule99": {} + "TestModule99": { + "repository": "PSGallery" + } } diff --git a/test/TestRequiredResourceFile.psd1 b/test/TestRequiredResourceFile.psd1 index 767e404bf..71eba50fa 100644 --- a/test/TestRequiredResourceFile.psd1 +++ b/test/TestRequiredResourceFile.psd1 @@ -1,14 +1,16 @@ @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PoshTestGallery" + test_module = @{ + version = "[1.0.0,5.0.0)" + repository = "PSGallery" } - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PoshTestGallery" - prerelease = "true" - } + test_module2 = @{ + version = "[1.0.0,3.0.0)" + repository = "PSGallery" + prerelease = "true" + } - TestModule99 = @{} + TestModule99 = @{ + repository = "PSGallery" + } } diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index b42ecaf19..54cfeb062 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -7,17 +7,20 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe 'Test Uninstall-PSResource for Modules' { BeforeAll{ - $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName - $testModuleName = "test_module" + $testModuleName = "test_module2" $testScriptName = "test_script" Get-NewPSResourceRepositoryFile - Uninstall-PSResource -name ContosoServer -Version "*" Uninstall-PSResource -Name $testModuleName -Version "*" + Uninstall-PSResource -Name $testScriptName -Version "*" } BeforeEach { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -TrustRepository -WarningAction SilentlyContinue + } + + AfterEach { + Uninstall-PSResource -Name $testModuleName -Version "*" } AfterAll { @@ -25,8 +28,8 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall a specific module by name" { - Uninstall-PSResource -name ContosoServer - Get-Module ContosoServer -ListAvailable | Should -Be $null + Uninstall-PSResource -name $testModuleName + Get-PSResource $testModuleName | Should -BeNullOrEmpty } $testCases = @{Name="Test?Module"; ErrorId="ErrorFilteringNamesForUnsupportedWildcards"}, @@ -40,129 +43,131 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall a list of modules by name" { - $null = Install-PSResource BaseTestPackage -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue -SkipDependencyCheck + $null = Install-PSResource "RequiredModule1" -Repository $PSGalleryName -TrustRepository -WarningAction SilentlyContinue -SkipDependencyCheck - Uninstall-PSResource -Name BaseTestPackage, ContosoServer - Get-Module ContosoServer, BaseTestPackage -ListAvailable | Should -be $null + Uninstall-PSResource -Name $testModuleName, "RequiredModule1" + Get-PSResource $testModuleName, "RequiredModule1" | Should -BeNullOrEmpty } It "Uninstall a specific script by name" { - $null = Install-PSResource "test_script" -Repository $TestGalleryName -TrustRepository - $res = Get-PSResource -Name "test_script" - $res.Name | Should -Be "test_script" + $null = Install-PSResource $testScriptName -Repository $PSGalleryName -TrustRepository + $res = Get-PSResource -Name $testScriptName + $res.Name | Should -Be $testScriptName - Uninstall-PSResource -name "test_script" - $res = Get-PSResource -Name "test_script" + Uninstall-PSResource -Name $testScriptName + $res = Get-PSResource -Name $testScriptName $res | Should -BeNullOrEmpty } It "Uninstall a list of scripts by name" { - $null = Install-PSResource "test_script", "TestTestScript" -Repository $TestGalleryName -TrustRepository - $res = Get-PSResource -Name "test_script" - $res2 = Get-PSResource -Name "TestTestScript" - $res.Name | Should -Be "test_script" - $res2.Name | Should -Be "TestTestScript" - - Uninstall-PSResource -Name "test_script", "TestTestScript" - $res = Get-PSResource -Name "test_script" - $res2 = Get-PSResource -Name "TestTestScript" + $null = Install-PSResource $testScriptName, "Required-Script1" -Repository $PSGalleryName -TrustRepository + $res = Get-PSResource -Name $testScriptName + $res.Name | Should -Be $testScriptName + $res2 = Get-PSResource -Name "Required-Script1" + $res2.Name | Should -Be "Required-Script1" + + Uninstall-PSResource -Name $testScriptName, "Required-Script1" + $res = Get-PSResource -Name $testScriptName $res | Should -BeNullOrEmpty + $res2 = Get-PSResource -Name "Required-Script1" $res2 | Should -BeNullOrEmpty } It "Uninstall a module when given name and specifying all versions" { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "3.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "5.0.0" -TrustRepository -WarningAction SilentlyContinue - Uninstall-PSResource -Name ContosoServer -version "*" - $pkgs = Get-Module ContosoServer -ListAvailable + Uninstall-PSResource -Name $testModuleName -version "*" + $pkgs = Get-PSResource $testModuleName $pkgs.Version | Should -Not -Contain "1.0.0" - $pkgs.Version | Should -Not -Contain "1.5.0" - $pkgs.Version | Should -Not -Contain "2.0.0" - $pkgs.Version | Should -Not -Contain "2.5.0" + $pkgs.Version | Should -Not -Contain "3.0.0" + $pkgs.Version | Should -Not -Contain "5.0.0" } It "Uninstall a module when given name and using the default version (ie all versions, not explicitly specified)" { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "3.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "5.0.0" -TrustRepository -WarningAction SilentlyContinue - Uninstall-PSResource -Name ContosoServer - $pkgs = Get-Module ContosoServer -ListAvailable + Uninstall-PSResource -Name $testModuleName + $pkgs = Get-PSResource $testModuleName $pkgs.Version | Should -Not -Contain "1.0.0" - $pkgs.Version | Should -Not -Contain "1.5.0" - $pkgs.Version | Should -Not -Contain "2.0.0" - $pkgs.Version | Should -Not -Contain "2.5.0" + $pkgs.Version | Should -Not -Contain "3.0.0" + $pkgs.Version | Should -Not -Contain "5.0.0" } It "Uninstall module when given Name and specifying exact version" { - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "3.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "5.0.0" -TrustRepository -WarningAction SilentlyContinue - Uninstall-PSResource -Name "ContosoServer" -Version "1.0.0" - $pkgs = Get-Module ContosoServer -ListAvailable + Uninstall-PSResource -Name $testModuleName -Version "3.0.0" + $pkgs = Get-PSResource -Name $testModuleName $pkgs.Version | Should -Not -Contain "1.0.0" } - $testCases = @{Version="[2.0.0.0]"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match"}, - @{Version="2.0.0.0"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.0.0.0, 2.5.0.0]"; ExpectedVersion="2.5.0.0"; Reason="validate version, exact range inclusive"}, - @{Version="(1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, exact range exclusive"}, - @{Version="(1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version exclusive"}, - @{Version="[1.0.0.0,)"; ExpectedVersion="2.5.0.0"; Reason="validate version, minimum version inclusive"}, - @{Version="(,1.5.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, - @{Version="(,1.5.0.0]"; ExpectedVersion="1.5.0.0"; Reason="validate version, maximum version inclusive"}, - @{Version="[1.0.0.0, 2.5.0.0)"; ExpectedVersion="2.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + $testCases = @{Version="[1.0.0.0]"; ExpectedVersion="1.0.0.0"; Reason="validate version, exact match"}, + @{Version="1.0.0.0"; ExpectedVersion="1.0.0.0"; Reason="validate version, exact match without bracket syntax"}, + @{Version="[1.0.0.0, 5.0.0.0]"; ExpectedVersion="5.0.0.0"; Reason="validate version, exact range inclusive"}, + @{Version="(1.0.0.0, 5.0.0.0)"; ExpectedVersion="3.0.0.0"; Reason="validate version, exact range exclusive"}, + @{Version="(1.0.0.0,)"; ExpectedVersion="5.0.0.0"; Reason="validate version, minimum version exclusive"}, + @{Version="[1.0.0.0,)"; ExpectedVersion="5.0.0.0"; Reason="validate version, minimum version inclusive"}, + @{Version="(,3.0.0.0)"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version exclusive"}, + @{Version="(,3.0.0.0]"; ExpectedVersion="1.0.0.0"; Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 5.0.0.0)"; ExpectedVersion="3.0.0.0"; Reason="validate version, mixed inclusive minimum and exclusive maximum version"} It "Uninstall module when given Name to " -TestCases $testCases { param($Version, $ExpectedVersion) - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "1.5.0" -TrustRepository -WarningAction SilentlyContinue - $null = Install-PSResource ContosoServer -Repository $TestGalleryName -Version "2.0.0" -TrustRepository -WarningAction SilentlyContinue + Uninstall-PSResource -Name $testModuleName -Version "*" + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "1.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "3.0.0" -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -Version "5.0.0" -TrustRepository -WarningAction SilentlyContinue - Uninstall-PSResource -Name ContosoServer -Version $Version - $pkgs = Get-Module ContosoServer -ListAvailable + Uninstall-PSResource -Name $testModuleName -Version $Version + $pkgs = Get-PSResource $testModuleName $pkgs.Version | Should -Not -Contain $Version } $testCases2 = @{Version='[1.*.0]'; Description="version with wilcard in middle"}, - @{Version='[*.5.0.0]'; Description="version with wilcard at start"}, + @{Version='[*.0.0.0]'; Description="version with wilcard at start"}, @{Version='[1.*.0.0]'; Description="version with wildcard at second digit"}, - @{Version='[1.5.*.0]'; Description="version with wildcard at third digit"} - @{Version='[1.5.0.*]'; Description="version with wildcard at end"}, + @{Version='[1.0.*.0]'; Description="version with wildcard at third digit"} + @{Version='[1.0.0.*]'; Description="version with wildcard at end"}, @{Version='[1..0.0]'; Description="version with missing digit in middle"}, - @{Version='[1.5.0.]'; Description="version with missing digit at end"}, - @{Version='[1.5.0.0.0]'; Description="version with more than 4 digits"} + @{Version='[1.0.0.]'; Description="version with missing digit at end"}, + @{Version='[1.0.0.0.0]'; Description="version with more than 4 digits"} It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases2 { param($Version, $Description) - {Uninstall-PSResource -Name "ContosoServer" -Version $Version} | Should -Throw "Argument for -Version parameter is not in the proper format." + {Uninstall-PSResource -Name $testModuleName -Version $Version} | Should -Throw "Argument for -Version parameter is not in the proper format." } - $testCases3 = @{Version='(2.5.0.0)'; Description="exclusive version (8.1.0.0)"}, - @{Version='[2-5-0-0]'; Description="version formatted with invalid delimiter"} + $testCases3 = @{Version='(1.0.0.0)'; Description="exclusive version (1.0.0.0)"}, + @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter"} It "Do not uninstall module with incorrectly formatted version such as " -TestCases $testCases3 { param($Version, $Description) - Uninstall-PSResource -Name "ContosoServer" -Version $Version + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - $pkg = Get-Module ContosoServer -ListAvailable - $pkg.Version | Should -Be "2.5" + Uninstall-PSResource -Name $testModuleName -Version $Version + $pkg = Get-PSResource $testModuleName -Version "1.0.0.0" + $pkg.Version | Should -Be "1.0.0.0" } It "Uninstall prerelease version module when prerelease version specified" { - Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName -TrustRepository Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" $res = Get-PSResource $testModuleName -Version "5.2.5-alpha001" $res | Should -BeNullOrEmpty } It "Not uninstall non-prerelease version module when similar prerelease version is specified" { - Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $TestGalleryName + # test_module has a version 5.0.0.0, but no version 5.0.0-preview. + # despite the core version part being the same this uninstall on a nonexistant prerelease version should not be successful + Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $PSGalleryName -TrustRepository Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" $res = Get-PSResource -Name $testModuleName -Version "5.0.0.0" $res.Name | Should -Be $testModuleName @@ -170,14 +175,14 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall prerelease version script when prerelease version specified" { - Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName - Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha" -Repository $PSGalleryName -TrustRepository + Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha" $res = Get-PSResource -Name $testScriptName $res | Should -BeNullOrEmpty } It "Not uninstall non-prerelease version module when prerelease version specified" { - Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $PSGalleryName -TrustRepository Uninstall-PSResource -Name $testScriptName -Version "2.5.0-alpha001" $res = Get-PSResource -Name $testScriptName -Version "2.5.0.0" $res.Name | Should -Be $testScriptName @@ -185,11 +190,11 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "uninstall all prerelease versions (which satisfy the range) when -Version '*' and -Prerelease parameter is specified" { - Install-PSResource -Name $testModuleName -Version "3.0.0" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "3.5.2-beta001" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "4.0.0" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "5.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testModuleName -Version "*" + Install-PSResource -Name $testModuleName -Version "2.5.0-beta" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Version "3.0.0" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Version "5.0.0" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} $prereleaseVersionPkgs.Count | Should -Be 2 @@ -199,66 +204,67 @@ Describe 'Test Uninstall-PSResource for Modules' { $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} $prereleaseVersionPkgs.Count | Should -Be 0 $stableVersionPkgs = $res | Where-Object {$_.IsPrerelease -ne $true} - $stableVersionPkgs.Count | Should -Be 3 + $stableVersionPkgs.Count | Should -Be 2 } It "uninstall all prerelease versions (which satisfy the range) when -Version range and -Prerelease parameter is specified" { - Install-PSResource -Name $testModuleName -Version "3.0.0" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "3.5.2-beta001" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "4.0.0" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - Install-PSResource -Name $testModuleName -Version "5.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testModuleName -Version "*" + Install-PSResource -Name $testModuleName -Version "2.5.0-beta" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Version "3.0.0" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Version "5.0.0" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName -TrustRepository + $res = Get-PSResource -Name $testModuleName $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} $prereleaseVersionPkgs.Count | Should -Be 2 - Uninstall-PSResource -Name $testModuleName -Version "[3.0.0, 4.0.0]" -Prerelease + Uninstall-PSResource -Name $testModuleName -Version "[2.0.0, 5.0.0]" -Prerelease $res = Get-PSResource -Name $testModuleName - # should only uninstall 3.5.2-beta001, 4.5.2-alpha001 is out of range and should remain installed + # should only uninstall 2.5.0-beta, 5.2.5-alpha001 is out of range and should remain installed $prereleaseVersionPkgs = $res | Where-Object {$_.IsPrerelease -eq $true} $prereleaseVersionPkgs.Count | Should -Be 1 $stableVersionPkgs = $res | Where-Object {$_.IsPrerelease -ne $true} - # versions 3.0.0 and 4.0.0 fall in range but should not be uninstalled as Prerelease parameter only selects prerelease versions for uninstallation - $stableVersionPkgs.Count | Should -Be 3 + # versions 3.0.0 falls in range but should not be uninstalled as Prerelease parameter only selects prerelease versions to uninstall + $stableVersionPkgs.Count | Should -Be 2 } It "Uninstall module using -WhatIf, should not uninstall the module" { - Uninstall-PSResource -Name "ContosoServer" -WhatIf - $pkg = Get-Module ContosoServer -ListAvailable - $pkg.Version | Should -Be "2.5" + Uninstall-PSResource -Name $testModuleName -WhatIf + $pkg = Get-PSResource $testModuleName -Version "5.0.0.0" + $pkg.Version | Should -Be "5.0.0.0" } It "Do not Uninstall module that is a dependency for another module" { - $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource "test_module" -Repository $PSGalleryName -TrustRepository -WarningAction SilentlyContinue Uninstall-PSResource -Name "RequiredModule1" -ErrorVariable ev -ErrorAction SilentlyContinue - $pkg = Get-Module "RequiredModule1" -ListAvailable + $pkg = Get-PSResource "RequiredModule1" $pkg | Should -Not -Be $null $ev.FullyQualifiedErrorId | Should -BeExactly 'UninstallPSResourcePackageIsaDependency,Microsoft.PowerShell.PowerShellGet.Cmdlets.UninstallPSResource' } It "Uninstall module that is a dependency for another module using -SkipDependencyCheck" { - $null = Install-PSResource $testModuleName -Repository $TestGalleryName -TrustRepository -WarningAction SilentlyContinue + $null = Install-PSResource $testModuleName -Repository $PSGalleryName -TrustRepository -WarningAction SilentlyContinue Uninstall-PSResource -Name "RequiredModule1" -SkipDependencyCheck - $pkg = Get-Module "RequiredModule1" -ListAvailable + $pkg = Get-PSResource "RequiredModule1" $pkg | Should -BeNullOrEmpty } It "Uninstall PSResourceInfo object piped in" { - Install-PSResource -Name "ContosoServer" -Version "1.5.0.0" -Repository $TestGalleryName - Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" | Uninstall-PSResource - $res = Get-PSResource -Name "ContosoServer" -Version "1.5.0.0" + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Get-PSResource -Name $testModuleName -Version "1.0.0.0" | Uninstall-PSResource + $res = Get-PSResource -Name "ContosoServer" -Version "1.0.0.0" $res | Should -BeNullOrEmpty } It "Uninstall PSResourceInfo object piped in for prerelease version object" { - Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource - $res = Get-PSResource -Name $testModuleName -Version "4.5.2-alpha001" + Install-PSResource -Name $testModuleName -Version "2.5.0-beta" -Repository $PSGalleryName -TrustRepository + Get-PSResource -Name $testModuleName -Version "2.5.0-beta" | Uninstall-PSResource + $res = Get-PSResource -Name $testModuleName -Version "2.5.0-beta" $res | Should -BeNullOrEmpty } } diff --git a/test/UnregisterPSResourceRepository.Tests.ps1 b/test/UnregisterPSResourceRepository.Tests.ps1 index f3e6e206e..97b9e3a1f 100644 --- a/test/UnregisterPSResourceRepository.Tests.ps1 +++ b/test/UnregisterPSResourceRepository.Tests.ps1 @@ -5,8 +5,8 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test Unregister-PSResourceRepository" { BeforeEach { - $TestGalleryName = Get-PoshTestGalleryName - $TestGalleryUri = Get-PoshTestGalleryLocation + $PSGalleryName = Get-PSGalleryName + $PSGalleryUri = Get-PSGalleryLocation Get-NewPSResourceRepositoryFile $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" $tmpDir2Path = Join-Path -Path $TestDrive -ChildPath "tmpDir2" @@ -71,10 +71,10 @@ Describe "Test Unregister-PSResourceRepository" { } It "unregister repository using -PassThru" { - $res = Unregister-PSResourceRepository -Name $TestGalleryName -PassThru - $res.Name | Should -Be $TestGalleryName - $Res.Uri | Should -Be $TestGalleryUri - $res = Get-PSResourceRepository -Name $TestGalleryName -ErrorVariable err -ErrorAction SilentlyContinue + $res = Unregister-PSResourceRepository -Name $PSGalleryName -PassThru + $res.Name | Should -Be $PSGalleryName + $Res.Uri | Should -Be $PSGalleryUri + $res = Get-PSResourceRepository -Name $PSGalleryName -ErrorVariable err -ErrorAction SilentlyContinue $res | Should -BeNullOrEmpty $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PowerShellGet.Cmdlets.GetPSResourceRepository" diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index bd081d970..05b2bbf7b 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -8,15 +8,17 @@ Describe 'Test Update-PSResource' { BeforeAll { - $TestGalleryName = Get-PoshTestGalleryName + $PSGalleryName = Get-PSGalleryName $NuGetGalleryName = Get-NuGetGalleryName - $testModuleName = "TestModule" + $testModuleName = "test_module" + $testModuleName2 = "test_module2" + $testModuleName3 = "TestModule99" Get-NewPSResourceRepositoryFile Get-PSResourceRepository } AfterEach { - Uninstall-PSResource "TestModule", "TestModule99", "TestModuleWithLicense", "PSGetTestModule" + Uninstall-PSResource "test_module", "TestModule99", "TestModuleWithLicense", "test_module2", "test_script" } AfterAll { @@ -24,15 +26,15 @@ Describe 'Test Update-PSResource' { } It "update resource installed given Name parameter" { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name $testModuleName -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $isPkgUpdated = $true } @@ -42,43 +44,43 @@ Describe 'Test Update-PSResource' { } It "update resources installed given Name (with wildcard) parameter" { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Install-PSResource -Name "TestModule99" -Version "0.0.4.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Install-PSResource -Name $testModuleName2 -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name "TestModule*" -Repository $TestGalleryName - $res = Get-PSResource -Name "TestModule*" + Update-PSResource -Name "test_mod*" -Repository $PSGalleryName -TrustRepository + $res = Get-PSResource -Name "test_mod*" -Version "5.0.0.0" - $inputHashtable = @{TestModule = "1.1.0.0"; TestModule99 = "0.0.4.0"} - $isTestModuleUpdated = $false - $isTestModule99Updated = $false + $inputHashtable = @{test_module = "1.0.0.0"; test_module2 = "1.0.0.0"} + $isTest_ModuleUpdated = $false + $isTest_Module2Updated = $false foreach ($item in $res) { if ([System.Version]$item.Version -gt [System.Version]$inputHashtable[$item.Name]) { if ($item.Name -like $testModuleName) { - $isTestModuleUpdated = $true + $isTest_ModuleUpdated = $true } - elseif ($item.Name -like "TestModule99") + elseif ($item.Name -like $testModuleName2) { - $isTestModule99Updated = $true + $isTest_Module2Updated = $true } } } - $isTestModuleUpdated | Should -BeTrue - $isTestModule99Updated | Should -BeTrue + $isTest_ModuleUpdated | Should -BeTrue + $isTest_Module2Updated | Should -BeTrue } It "update resource installed given Name and Version (specific) parameters" { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -eq [System.Version]"1.2.0.0") + if ([System.Version]$pkg.Version -eq [System.Version]"5.0.0.0") { $isPkgUpdated = $true } @@ -87,22 +89,22 @@ Describe 'Test Update-PSResource' { $isPkgUpdated | Should -BeTrue } - $testCases2 = @{Version="[1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, exact match"}, - @{Version="1.3.0.0"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, exact match without bracket syntax"}, - @{Version="[1.1.1.0, 1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, exact range inclusive"}, - @{Version="(1.1.1.0, 1.3.0.0)"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, exact range exclusive"}, - @{Version="(1.1.1.0,)"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, minimum version exclusive"}, - @{Version="[1.1.1.0,)"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, minimum version inclusive"}, - @{Version="(,1.3.0.0)"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, maximum version exclusive"}, - @{Version="(,1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.3.0.0"); Reason="validate version, maximum version inclusive"}, - @{Version="[1.1.1.0, 1.3.0.0)"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} - @{Version="(1.1.1.0, 1.3.0.0]"; ExpectedVersions=@("1.1.0.0", "1.2.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} + $testCases2 = @{Version="[3.0.0.0]"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, exact match"}, + @{Version="3.0.0.0"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, exact match without bracket syntax"}, + @{Version="[3.0.0.0, 5.0.0.0]"; ExpectedVersions=@("1.0.0.0", "3.0.0.0", "5.0.0.0"); Reason="validate version, exact range inclusive"}, + @{Version="(3.0.0.0, 6.0.0.0)"; ExpectedVersions=@("1.0.0.0", "3.0.0.0", "5.0.0.0"); Reason="validate version, exact range exclusive"}, + @{Version="(3.0.0.0,)"; ExpectedVersions=@("1.0.0.0", "5.0.0.0"); Reason="validate version, minimum version exclusive"}, + @{Version="[3.0.0.0,)"; ExpectedVersions=@("1.0.0.0", "3.0.0.0", "5.0.0.0"); Reason="validate version, minimum version inclusive"}, + @{Version="(,5.0.0.0)"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, maximum version exclusive"}, + @{Version="(,5.0.0.0]"; ExpectedVersions=@("1.0.0.0", "3.0.0.0", "5.0.0.0"); Reason="validate version, maximum version inclusive"}, + @{Version="[1.0.0.0, 5.0.0.0)"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"} + @{Version="(1.0.0.0, 3.0.0.0]"; ExpectedVersions=@("1.0.0.0", "3.0.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"} It "update resource when given Name to " -TestCases $testCases2{ param($Version, $ExpectedVersions) - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName @@ -113,20 +115,20 @@ Describe 'Test Update-PSResource' { } $testCases = @( - @{Version='(1.2.0.0)'; Description="exclusive version (2.10.0.0)"}, - @{Version='[1-2-0-0]'; Description="version formatted with invalid delimiter [1-2-0-0]"} + @{Version='(3.0.0.0)'; Description="exclusive version (3.0.0.0)"}, + @{Version='[3-0-0-0]'; Description="version formatted with invalid delimiter [3-0-0-0]"} ) It "Should not update resource with incorrectly formatted version such as " -TestCases $testCases{ param($Version, $Description) - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name $testModuleName -Version $Version -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $isPkgUpdated = $true } @@ -136,18 +138,16 @@ Describe 'Test Update-PSResource' { } It "update resource with latest (including prerelease) version given Prerelease parameter" { - # PSGetTestModule resource's latest version is a prerelease version, before that it has a non-prerelease version - - Install-PSResource -Name "PSGetTestModule" -Version "1.0.2.0" -Repository $TestGalleryName - Update-PSResource -Name "PSGetTestModule" -Prerelease -Repository $TestGalleryName - $res = Get-PSResource -Name "PSGetTestModule" + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $testModuleName -Prerelease -Repository $PSGalleryName -TrustRepository + $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.0.2.0") + if ([System.Version]$pkg.Version -ge [System.Version]"5.2.5") { - $pkg.Prerelease | Should -Be "alpha1" + $pkg.Prerelease | Should -Be "alpha001" $isPkgUpdated = $true } } @@ -158,17 +158,17 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under CurrentUser scope" -skip:(!$IsWindows) { # TODO: perhaps also install TestModule with the highest version (the one above 1.2.0.0) to the AllUsers path too - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope AllUsers + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser - Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName -Scope CurrentUser + Update-PSResource -Name $testModuleName -Version "3.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $pkg.InstalledLocation.Contains("Documents") | Should -Be $true $isPkgUpdated = $true @@ -180,16 +180,16 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under AllUsers scope" -skip:(!($IsWindows -and (Test-IsAdmin))) { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope AllUsers + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser - Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName -Scope AllUsers + Update-PSResource -Name $testModuleName -Version "3.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope AllUsers $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $pkg.InstalledLocation.Contains("Program Files") | Should -Be $true $isPkgUpdated = $true @@ -201,15 +201,15 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under no specified scope" -skip:(!$IsWindows) { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $testModuleName -Version "3.0.0.0" -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $pkg.InstalledLocation.Contains("Documents") | Should -Be $true $isPkgUpdated = $true @@ -224,16 +224,16 @@ Describe 'Test Update-PSResource' { It "Update resource under CurrentUser scope - Unix only" -Skip:(Get-IsWindows) { # this line is commented out because AllUsers scope requires sudo and that isn't supported in CI yet # Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser - Update-PSResource -Name $testModuleName -Repository $TestGalleryName -Scope CurrentUser + Update-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope CurrentUser $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $pkg.InstalledLocation.Contains("$env:HOME/.local") | Should -Be $true $isPkgUpdated = $true @@ -247,17 +247,17 @@ Describe 'Test Update-PSResource' { # Expected path should be similar to: '/usr/local/share/powershell/Modules' # this test is skipped because it requires sudo to run and has yet to be resolved in CI It "Update resource under AllUsers scope - Unix only" -Skip:($true) { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope AllUsers + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser - Update-PSResource -Name $testModuleName -Repository $TestGalleryName -Scope AllUsers + Update-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $pkg.InstalledLocation.Contains("usr") | Should -Be $true $isPkgUpdated = $true @@ -272,16 +272,16 @@ Describe 'Test Update-PSResource' { It "Update resource under no specified scope - Unix only" -Skip:(Get-IsWindows) { # this is commented out because it requires sudo to run with AllUsers scope and this hasn't been resolved in CI yet # Install-PSResource -Name "TestModule" -Version "1.1.0.0" -Repository $TestGalleryName -Scope AllUsers - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName -Scope CurrentUser + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser - Update-PSResource -Name $testModuleName -Repository $TestGalleryName + Update-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $pkg.InstalledLocation.Contains("$env:HOME/.local") | Should -Be $true $isPkgUpdated = $true @@ -291,54 +291,33 @@ Describe 'Test Update-PSResource' { $isPkgUpdated | Should -Be $true } - It "update resource that requires accept license with -AcceptLicense flag" { - Install-PSResource -Name "TestModuleWithLicense" -Version "0.0.1.0" -Repository $TestGalleryName -AcceptLicense - Update-PSResource -Name "TestModuleWithLicense" -Repository $TestGalleryName -AcceptLicense - $res = Get-PSResource "TestModuleWithLicense" - - $isPkgUpdated = $false - foreach ($pkg in $res) - { - if ([System.Version]$pkg.Version -gt [System.Version]"0.0.1.0") - { - $isPkgUpdated = $true - } - } - - $isPkgUpdated | Should -Be $true - } - - It "update resource should not prompt 'trust repository' if repository is not trusted but -TrustRepository is used" { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - - Set-PSResourceRepository PoshTestGallery -Trusted:$false + # It "update resource that requires accept license with -AcceptLicense flag" { + # Install-PSResource -Name "TestModuleWithLicense" -Version "0.0.1.0" -Repository $TestGalleryName -AcceptLicense + # Update-PSResource -Name "TestModuleWithLicense" -Repository $TestGalleryName -AcceptLicense + # $res = Get-PSResource "TestModuleWithLicense" - Update-PSResource -Name $testModuleName -Version "1.2.0.0" -Repository $TestGalleryName -TrustRepository - $res = Get-PSResource -Name $testModuleName + # $isPkgUpdated = $false + # foreach ($pkg in $res) + # { + # if ([System.Version]$pkg.Version -gt [System.Version]"0.0.1.0") + # { + # $isPkgUpdated = $true + # } + # } - $isPkgUpdated = $false - foreach ($pkg in $res) - { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") - { - $isPkgUpdated = $true - } - } - - $isPkgUpdated | Should -BeTrue - Set-PSResourceRepository PoshTestGallery -Trusted - } + # $isPkgUpdated | Should -Be $true + # } It "Update module using -WhatIf, should not update the module" { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName - Update-PSResource -Name $testModuleName -WhatIf + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $testModuleName -WhatIf -Repository $PSGalleryName -TrustRepository $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false foreach ($pkg in $res) { - if ([System.Version]$pkg.Version -gt [System.Version]"1.1.0.0") + if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") { $isPkgUpdated = $true } @@ -348,10 +327,10 @@ Describe 'Test Update-PSResource' { } It "update resource installed given -Name and -PassThru parameters" { - Install-PSResource -Name $testModuleName -Version "1.1.0.0" -Repository $TestGalleryName + Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - $res = Update-PSResource -Name $testModuleName -Version "1.3.0.0" -Repository $TestGalleryName -PassThru - $res.Name | Should -Be $testModuleName - $res.Version | Should -Be "1.3.0.0" + $res = Update-PSResource -Name $testModuleName -Version "3.0.0.0" -Repository $PSGalleryName -TrustRepository -PassThru + $res.Name | Should -Contain $testModuleName + $res.Version | Should -Contain "3.0.0.0" } } diff --git a/test/testRepositories.xml b/test/testRepositories.xml index 6426f2c53..a0da40886 100644 --- a/test/testRepositories.xml +++ b/test/testRepositories.xml @@ -1,6 +1,5 @@ - From 71cc804356ced977643220e25e1c9129c51ddaf0 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 9 May 2022 21:19:17 -0700 Subject: [PATCH 130/276] Add -Scope parameter to Get-PSResource and Uninstall-PSResource (#639) --- src/code/GetPSResource.cs | 8 +++- src/code/UninstallPSResource.cs | 8 +++- ...urce.Tests.ps1 => GetPSResource.Tests.ps1} | 38 +++++++++++++++++++ test/InstallPSResource.Tests.ps1 | 12 +++--- test/UninstallPSResource.Tests.ps1 | 26 +++++++++++-- test/UpdatePSResource.Tests.ps1 | 21 +++------- 6 files changed, 87 insertions(+), 26 deletions(-) rename test/{GetInstalledPSResource.Tests.ps1 => GetPSResource.Tests.ps1} (76%) diff --git a/src/code/GetPSResource.cs b/src/code/GetPSResource.cs index 703500d0c..367262f7a 100644 --- a/src/code/GetPSResource.cs +++ b/src/code/GetPSResource.cs @@ -44,6 +44,12 @@ public sealed class GetPSResource : PSCmdlet [Parameter] [ValidateNotNullOrEmpty()] public string Path { get; set; } + + /// + /// Specifies the scope of installation. + /// + [Parameter] + public ScopeType Scope { get; set; } #endregion @@ -102,7 +108,7 @@ protected override void BeginProcessing() else { // retrieve all possible paths - _pathsToSearch = Utils.GetAllResourcePaths(this); + _pathsToSearch = Utils.GetAllResourcePaths(this, Scope); } } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 5dfe13c00..019484191 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -54,6 +54,12 @@ public sealed class UninstallPSResource : PSCmdlet [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } + /// + /// Specifies the scope of installation. + /// + [Parameter] + public ScopeType Scope { get; set; } + #endregion #region Members @@ -71,7 +77,7 @@ public sealed class UninstallPSResource : PSCmdlet protected override void BeginProcessing() { - _pathsToSearch = Utils.GetAllResourcePaths(this); + _pathsToSearch = Utils.GetAllResourcePaths(this, Scope); } protected override void ProcessRecord() diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetPSResource.Tests.ps1 similarity index 76% rename from test/GetInstalledPSResource.Tests.ps1 rename to test/GetPSResource.Tests.ps1 index 1f3492921..f0f4b0c25 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetPSResource.Tests.ps1 @@ -131,4 +131,42 @@ $testCases = $res.Version | Should -Be "3.0.0" $res.Prerelease | Should -Be "alpha" } + + # Windows only + It "Get resource under CurrentUser scope - Windows only" -Skip:(!(Get-IsWindows)) { + $pkg = Get-PSResource -Name $testModuleName -Scope CurrentUser + $pkg[0].Name | Should -Be $testModuleName + $pkg[0].InstalledLocation.ToString().Contains("Documents") | Should -Be $true + } + + # Windows only + It "Get resource under AllUsers scope when module is installed under CurrentUser - Windows only" -Skip:(!(Get-IsWindows)) { + $pkg = Get-PSResource -Name $testModuleName -Scope AllUsers + $pkg | Should -BeNullOrEmpty + } + + # Windows only + It "Get resource under AllUsers scope - Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers + $pkg = Get-PSResource -Name $testModuleName -Scope AllUsers + $pkg.Name | Should -Be $testModuleName + $pkg.InstalledLocation.ToString().Contains("Program Files") | Should -Be $true + } + + # Windows only + It "Get resource under CurrentUser scope when module is installed under AllUsers - Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { + Uninstall-PSResource -Name $testModuleName -Version "*" + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers + $pkg = Get-PSResource -Name $testModuleName -Scope CurrentUser + $pkg | Should -BeNullOrEmpty + } + + # Unix only + # Expected path should be similar to: '/home/janelane/.local/share/powershell/Modules' + It "Get resource under CurrentUser scope - Unix only" -Skip:(Get-IsWindows) { + Install-PSResource -Name "testmodule99" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser + $pkg = Get-PSResource "testmodule99" -Scope CurrentUser + $pkg.Name | Should -contain "testmodule99" + $pkg.InstalledLocation.ToString().Contains("/.local") | Should -Be $true + } } diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index c6f173483..e887265ed 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -168,10 +168,10 @@ Describe 'Test Install-PSResource for Module' { # Windows only It "Install resource under AllUsers scope - Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { - Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers - $pkg = Get-PSResource $testModuleName - $pkg.Name | Should -Be $testModuleName - $pkg.InstalledLocation.ToString().Contains("Program Files") | Should -Be $true + Install-PSResource -Name "testmodule99" -Repository $PSGalleryName -TrustRepository -Scope AllUsers -Verbose + $pkg = Get-Module "testmodule99" -ListAvailable + $pkg.Name | Should -Be "testmodule99" + $pkg.Path.ToString().Contains("Program Files") } # Windows only @@ -222,8 +222,8 @@ Describe 'Test Install-PSResource for Module' { It "Restore resource after reinstall fails" { Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository $pkg = Get-Module $testModuleName -ListAvailable - $pkg.Name | Should -Be $testModuleName - $pkg.Version | Should -Be "5.0.0.0" + $pkg.Name | Should -Contain $testModuleName + $pkg.Version | Should -Contain "5.0.0.0" $resourcePath = Split-Path -Path $pkg.Path -Parent $resourceFiles = Get-ChildItem -Path $resourcePath -Recurse diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 54cfeb062..0c0850e60 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -43,10 +43,10 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall a list of modules by name" { - $null = Install-PSResource "RequiredModule1" -Repository $PSGalleryName -TrustRepository -WarningAction SilentlyContinue -SkipDependencyCheck + $null = Install-PSResource "testmodule99" -Repository $PSGalleryName -TrustRepository -WarningAction SilentlyContinue -SkipDependencyCheck - Uninstall-PSResource -Name $testModuleName, "RequiredModule1" - Get-PSResource $testModuleName, "RequiredModule1" | Should -BeNullOrEmpty + Uninstall-PSResource -Name $testModuleName, "testmodule99" + Get-PSResource $testModuleName, "testmodule99" | Should -BeNullOrEmpty } It "Uninstall a specific script by name" { @@ -267,4 +267,24 @@ Describe 'Test Uninstall-PSResource for Modules' { $res = Get-PSResource -Name $testModuleName -Version "2.5.0-beta" $res | Should -BeNullOrEmpty } + + # Windows only + It "Uninstall resource under CurrentUser scope only- Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers -Reinstall + Uninstall-PSResource -Name $testModuleName -Scope CurrentUser + + $pkg = Get-Module $testModuleName -ListAvailable + $pkg.Name | Should -Be $testModuleName + $pkg.Path.ToString().Contains("Program Files") | Should -Be $true + } + + # Windows only + It "Uninstall resource under AllUsers scope only- Windows only" -Skip:(!((Get-IsWindows) -and (Test-IsAdmin))) { + Install-PSResource $testModuleName -Repository $PSGalleryName -TrustRepository -Scope AllUsers -Reinstall + Uninstall-PSResource -Name $testModuleName -Scope AllUsers + + $pkg = Get-Module $testModuleName -ListAvailable + $pkg.Name | Should -Be $testModuleName + $pkg.Path.ToString().Contains("Documents") | Should -Be $true + } } diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 05b2bbf7b..4c3bf082b 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -180,23 +180,14 @@ Describe 'Test Update-PSResource' { # Windows only It "update resource under AllUsers scope" -skip:(!($IsWindows -and (Test-IsAdmin))) { - Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope AllUsers - Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser + Install-PSResource -Name "testmodule99" -Version "0.0.91" -Repository $PSGalleryName -TrustRepository -Scope AllUsers -Verbose + Install-PSResource -Name "testmodule99" -Version "0.0.91" -Repository $PSGalleryName -TrustRepository -Scope CurrentUser -Verbose - Update-PSResource -Name $testModuleName -Version "3.0.0.0" -Repository $PSGalleryName -TrustRepository -Scope AllUsers + Update-PSResource -Name "testmodule99" -Version "0.0.93" -Repository $PSGalleryName -TrustRepository -Scope AllUsers -Verbose - $res = Get-PSResource -Name $testModuleName - $isPkgUpdated = $false - foreach ($pkg in $res) - { - if ([System.Version]$pkg.Version -gt [System.Version]"1.0.0.0") - { - $pkg.InstalledLocation.Contains("Program Files") | Should -Be $true - $isPkgUpdated = $true - } - } - - $isPkgUpdated | Should -Be $true + $res = Get-Module -Name "testmodule99" -ListAvailable + $res | Should -Not -BeNullOrEmpty + $res.Version | Should -Contain "0.0.93" } # Windows only From b323701f59dd77fe6560d7ca7370b19962cb28c6 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 17 May 2022 14:50:24 -0700 Subject: [PATCH 131/276] Change -Repositories param to -Repository in Register-PSResourceRepository (#645) --- help/Register-PSResourceRepository.md | 8 ++++---- help/Set-PSResourceRepository.md | 6 +++--- src/code/RegisterPSResourceRepository.cs | 4 ++-- src/code/SetPSResourceRepository.cs | 4 ++-- test/RegisterPSResourceRepository.Tests.ps1 | 16 ++++++++-------- test/SetPSResourceRepository.Tests.ps1 | 8 ++++---- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index 9fb3e02e1..9b5cc7855 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -26,7 +26,7 @@ Register-PSResourceRepository [-PSGallery] [-Trusted] [-Priority ] [-Pass ### RepositoriesParameterSet ``` -Register-PSResourceRepository -Repositories [-PassThru] [-WhatIf] [-Confirm] [] +Register-PSResourceRepository -Repository [-PassThru] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -59,7 +59,7 @@ This example registers the "PSGallery" repository, with the 'PSGallery' paramete ### Example 3 ``` PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} -PS C:\> Register-PSResourceRepository -Repositories $arrayOfHashtables +PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables PS C:\> Get-PSResourceRepository Name Uri Trusted Priority ---- --- ------- -------- @@ -68,7 +68,7 @@ PS C:\> Get-PSResourceRepository ``` -This example registers multiple repositories at once. To do so, we use the `-Repositories` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. +This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. ## PARAMETERS @@ -119,7 +119,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Repositories +### -Repository Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. ```yaml diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index f5dd6e52f..90eba5cb6 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -19,7 +19,7 @@ Set-PSResourceRepository [-Name] [-Uri ] [-Trusted] [-Priority ### RepositoriesParameterSet ``` -Set-PSResourceRepository -Repositories [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository -Repository [-Priority ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -65,14 +65,14 @@ PS C:\> Get-PSResourceRepository -Name "*" PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} -PS C:\> Set-PSResourceRepository -Repositories $arrayOfHashtables -PassThru +PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Name Uri Trusted Priority ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 True 50 PoshTestGallery file:///c:/code/testdir False 50 ``` -This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repositories` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. +This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. ## PARAMETERS diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 9ca9434d1..6564f4d18 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -64,7 +64,7 @@ class RegisterPSResourceRepository : PSCmdlet /// [Parameter(Mandatory = true, ParameterSetName = RepositoriesParameterSet)] [ValidateNotNullOrEmpty] - public Hashtable[] Repositories {get; set;} + public Hashtable[] Repository {get; set;} /// /// Specifies whether the repository should be trusted. @@ -270,7 +270,7 @@ private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repo private List RepositoriesParameterSetHelper() { List reposAddedFromHashTable = new List(); - foreach (Hashtable repo in Repositories) + foreach (Hashtable repo in Repository) { if (repo.ContainsKey(PSGalleryRepoName)) { diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 1adcd83ae..2ada5bdee 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -51,7 +51,7 @@ public sealed class SetPSResourceRepository : PSCmdlet /// [Parameter(Mandatory = true, ParameterSetName = RepositoriesParameterSet)] [ValidateNotNullOrEmpty] - public Hashtable[] Repositories { get; set; } + public Hashtable[] Repository { get; set; } /// /// Specifies whether the repository should be trusted. @@ -236,7 +236,7 @@ private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUr private List RepositoriesParameterSetHelper() { List reposUpdatedFromHashtable = new List(); - foreach (Hashtable repo in Repositories) + foreach (Hashtable repo in Repository) { if (!repo.ContainsKey("Name") || repo["Name"] == null || String.IsNullOrEmpty(repo["Name"].ToString())) { diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index a15bfdf13..acaeca848 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -98,14 +98,14 @@ Describe "Test Register-PSResourceRepository" { $res.Priority | Should -Be 20 } - It "register repositories with Repositories parameter, all name parameter style repositories (RepositoriesParameterSet)" { + It "register repositories with -Repository parameter, all name parameter style repositories (RepositoriesParameterSet)" { $hashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} $hashtable2 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} $hashtable3 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} $hashtable4 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 - Register-PSResourceRepository -Repositories $arrayOfHashtables + Register-PSResourceRepository -Repository $arrayOfHashtables $res = Get-PSResourceRepository -Name $TestRepoName1 $Res.Uri.LocalPath | Should -Contain $tmpDir1Path $res.Trusted | Should -Be False @@ -130,17 +130,17 @@ Describe "Test Register-PSResourceRepository" { $res4.CredentialInfo.Credential | Should -BeNullOrEmpty } - It "register repositories with Repositories parameter, psgallery style repository (RepositoriesParameterSet)" { + It "register repositories with -Repository parameter, psgallery style repository (RepositoriesParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName $hashtable1 = @{PSGallery = $True} - Register-PSResourceRepository -Repositories $hashtable1 + Register-PSResourceRepository -Repository $hashtable1 $res = Get-PSResourceRepository -Name $PSGalleryName $res.Uri | Should -Be $PSGalleryUri $res.Trusted | Should -Be False $res.Priority | Should -Be 50 } - It "register repositories with Repositories parameter, name and psgallery parameter styles (RepositoriesParameterSet)" { + It "register repositories with -Repository parameter, name and psgallery parameter styles (RepositoriesParameterSet)" { Unregister-PSResourceRepository -Name $PSGalleryName $hashtable1 = @{PSGallery = $True} $hashtable2 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} @@ -149,7 +149,7 @@ Describe "Test Register-PSResourceRepository" { $hashtable5 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4, $hashtable5 - Register-PSResourceRepository -Repositories $arrayOfHashtables + Register-PSResourceRepository -Repository $arrayOfHashtables $res1 = Get-PSResourceRepository -Name $PSGalleryName $res1.Uri | Should -Be $PSGalleryUri @@ -220,7 +220,7 @@ Describe "Test Register-PSResourceRepository" { $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 Unregister-PSResourceRepository -Name $PSGalleryName - Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "NotProvideNameUriCredentialInfoForPSGalleryRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" @@ -248,7 +248,7 @@ Describe "Test Register-PSResourceRepository" { $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 Unregister-PSResourceRepository -Name $PSGalleryName - Register-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly $ErrorId diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index f3d35f351..25eb1c820 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -112,7 +112,7 @@ Describe "Test Set-PSResourceRepository" { $incorrectHashTable = @{Name = $Name; Trusted = $True} $arrayOfHashtables = $hashtable1, $incorrectHashTable, $hashtable2 - Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" @@ -138,7 +138,7 @@ Describe "Test Set-PSResourceRepository" { $hashtable4 = @{Name = $PSGalleryName; Trusted = $True}; $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 - Set-PSResourceRepository -Repositories $arrayOfHashtables + Set-PSResourceRepository -Repository $arrayOfHashtables $res = Get-PSResourceRepository -Name $TestRepoName1 $res.Name | Should -Be $TestRepoName1 $Res.Uri.LocalPath | Should -Contain $tmpDir2Path @@ -192,7 +192,7 @@ Describe "Test Set-PSResourceRepository" { $hashtable2 = @{Name = $TestRepoName1; Priority = 25} $arrayOfHashtables = $hashtable1, $hashtable2 - Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" @@ -222,7 +222,7 @@ Describe "Test Set-PSResourceRepository" { $hashtable2 = @{Name = $TestRepoName1; Priority = 25} $arrayOfHashtables = $hashtable1, $hashtable2 - Set-PSResourceRepository -Repositories $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" From 0ad2f504602c8dc01d4554809370fbcc81fb481f Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 18 May 2022 10:18:38 -0700 Subject: [PATCH 132/276] Bug fix for publishing modules with RequiredModules specified in .psd1 (#640) --- src/code/PublishPSResource.cs | 105 +++++++++++++++++++++---------- test/PublishPSResource.Tests.ps1 | 44 +++++++++---- 2 files changed, 102 insertions(+), 47 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index bd9f46dd6..8ff51d999 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -12,11 +12,13 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Management.Automation; using System.Management.Automation.Language; using System.Net.Http; +using System.Threading; using System.Xml; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets @@ -160,9 +162,10 @@ public PSCredential ProxyCredential { #region Members + private CancellationToken _cancellationToken; private NuGetVersion _pkgVersion; private string _pkgName; - private static char[] _PathSeparators = new [] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; + private static char[] _PathSeparators = new[] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; public const string PSDataFileExt = ".psd1"; public const string PSScriptFileExt = ".ps1"; @@ -172,6 +175,8 @@ public PSCredential ProxyCredential { protected override void BeginProcessing() { + _cancellationToken = new CancellationToken(); + // Create a respository story (the PSResourceRepository.xml file) if it does not already exist // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); @@ -317,15 +322,13 @@ protected override void ProcessRecord() return; } - string repositoryUri = repository.Uri.AbsoluteUri; - // Check if dependencies already exist within the repo if: // 1) the resource to publish has dependencies and // 2) the -SkipDependenciesCheck flag is not passed in if (dependencies != null && !SkipDependenciesCheck) { // If error gets thrown, exit process record - if (!CheckDependenciesExist(dependencies, repositoryUri)) + if (!CheckDependenciesExist(dependencies, repository.Name)) { return; } @@ -366,14 +369,14 @@ protected override void ProcessRecord() // pack into a nupkg try { - if (!PackNupkg(outputDir, outputNupkgDir, nuspec)) - { + if (!PackNupkg(outputDir, outputNupkgDir, nuspec)) + { return; - } + } } catch (Exception e) { - var message = string.Format("Error packing into .nupkg: '{0}'.", e.Message); + var message = string.Format("Error packing into .nupkg: '{0}'.", e.Message); var ex = new ArgumentException(message); var ErrorPackingIntoNupkg = new ErrorRecord(ex, "ErrorPackingIntoNupkg", ErrorCategory.NotSpecified, null); WriteError(ErrorPackingIntoNupkg); @@ -403,6 +406,7 @@ protected override void ProcessRecord() } // This call does not throw any exceptions, but it will write unsuccessful responses to the console + string repositoryUri = repository.Uri.AbsoluteUri; PushNupkg(outputNupkgDir, repository.Name, repositoryUri); } @@ -428,28 +432,48 @@ private bool IsValidModuleManifest(string moduleManifestPath) // locally on the machine. Consider adding a -Syntax param to Test-ModuleManifest so that it only checks that // the syntax is correct. In build/release pipelines for example, the modules listed under RequiredModules may // not be locally available, but we still want to allow the user to publish. - var results = pwsh.AddCommand("Test-ModuleManifest").AddParameter("Path", moduleManifestPath).Invoke(); + Collection results = null; + try + { + results = pwsh.AddCommand("Test-ModuleManifest").AddParameter("Path", moduleManifestPath).Invoke(); + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new ArgumentException("Error occured while running 'Test-ModuleManifest': " + e.Message), + "ErrorExecutingTestModuleManifest", + ErrorCategory.InvalidArgument, + this)); + } if (pwsh.HadErrors) { var message = string.Empty; - if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Author)) - { - message = "No author was provided in the module manifest. The module manifest must specify a version, author and description."; - } - else if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Description)) + + if (results.Any()) { - message = "No description was provided in the module manifest. The module manifest must specify a version, author and description."; + if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Author)) + { + message = "No author was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + } + else if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Description)) + { + message = "No description was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + } + else if ((results[0].BaseObject as PSModuleInfo).Version == null) + { + message = "No version or an incorrectly formatted version was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + } } - else + + if (string.IsNullOrEmpty(message) && pwsh.Streams.Error.Count > 0) { // This will handle version errors - var error = pwsh.Streams.Error; - message = error[0].ToString(); + message = pwsh.Streams.Error[0].ToString() + "Run 'Test-ModuleManifest' to validate the module manifest."; } var ex = new ArgumentException(message); var InvalidModuleManifest = new ErrorRecord(ex, "InvalidModuleManifest", ErrorCategory.InvalidData, null); - WriteError(InvalidModuleManifest); + ThrowTerminatingError(InvalidModuleManifest); isValid = false; } } @@ -569,7 +593,7 @@ private string CreateNuspec( metadataElementsDictionary.Add("description", parsedMetadataHash["description"].ToString().Trim()); } - if (parsedMetadataHash.ContainsKey("releasenotes")) + if (parsedMetadataHash.ContainsKey("releasenotes")) { metadataElementsDictionary.Add("releaseNotes", parsedMetadataHash["releasenotes"].ToString().Trim()); } @@ -579,7 +603,7 @@ private string CreateNuspec( metadataElementsDictionary.Add("copyright", parsedMetadataHash["copyright"].ToString().Trim()); } - string tags = isScript ? "PSScript" : "PSModule"; + string tags = isScript ? "PSScript" : "PSModule"; if (parsedMetadataHash.ContainsKey("tags")) { if (parsedMetadataHash["tags"] != null) @@ -762,7 +786,7 @@ Example cmdlet here { // expecting only one or two comments var commentText = token.Text; - parsedComments.AddRange(commentText.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries) ); + parsedComments.AddRange(commentText.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries)); } } @@ -775,7 +799,7 @@ Example cmdlet here var key = newlist[0].TrimStart(TrimBeginning); var value = newlist.Length > 1 ? newlist[1].Trim() : string.Empty; - parsedMetadataHash.Add(key,value); + parsedMetadataHash.Add(key, value); } } } @@ -783,7 +807,7 @@ Example cmdlet here return parsedMetadataHash; } - private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUri) + private bool CheckDependenciesExist(Hashtable dependencies, string repositoryName) { // Check to see that all dependencies are in the repository // Searches for each dependency in the repository the pkg is being pushed to, @@ -792,19 +816,32 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryUri { // Need to make individual calls since we're look for exact version numbers or ranges. var depName = new[] { (string)dependency }; - var depVersion = (string)dependencies[dependency]; - var type = new[] { "module", "script" }; - var repository = new[] { repositoryUri }; - + // test version + string depVersion = dependencies[dependency] as string; + depVersion = string.IsNullOrWhiteSpace(depVersion) ? "*" : depVersion; + + VersionRange versionRange = null; + if (!Utils.TryParseVersionOrVersionRange(depVersion, out versionRange)) + { + // This should never be true because Test-ModuleManifest will throw an error if dependency versions are incorrectly formatted + // This is being left as a safeguard for parsing a version from a string to a version range. + ThrowTerminatingError(new ErrorRecord( + new ArgumentException(string.Format("Error parsing dependency version {0}, from the module {1}", depVersion, depName)), + "IncorrectVersionFormat", + ErrorCategory.InvalidArgument, + this)); + } + // Search for and return the dependency if it's in the repository. - // TODO: When find is complete, uncomment beginFindHelper method below (resourceNameParameterHelper) - //var dependencyFound = findHelper.beginFindHelper(depName, type, depVersion, true, null, null, repository, Credential, false, false); - // TODO: update the type from PSObject to PSResourceInfo - List dependencyFound = null; + FindHelper findHelper = new FindHelper(_cancellationToken, this); + bool depPrerelease = depVersion.Contains("-"); + + var repository = new[] { repositoryName }; + var dependencyFound = findHelper.FindByResourceName(depName, ResourceType.Module, depVersion, depPrerelease, null, repository, Credential, false); if (dependencyFound == null || !dependencyFound.Any()) { - var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryUri); - var ex = new ArgumentException(message); // System.ArgumentException vs PSArgumentException + var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryName); + var ex = new ArgumentException(message); var dependencyNotFound = new ErrorRecord(ex, "DependencyNotFound", ErrorCategory.ObjectNotFound, null); WriteError(dependencyNotFound); diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 3ad06aba6..604087dd7 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -53,7 +53,6 @@ Describe "Test Publish-PSResource" { # Remove-Item $pkgsToDelete -Recurse } - It "Publish a module with -Path to the highest priority repo" { $version = "1.0.0" New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" @@ -74,33 +73,29 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } -<# Temporarily comment this test out until Find Helper is complete and code within PublishPSResource is uncommented It "Publish a module with dependencies" { # Create dependency module $dependencyVersion = "2.0.0" New-ModuleManifest -Path (Join-Path -Path $script:DependencyModuleBase -ChildPath "$script:DependencyModuleName.psd1") -ModuleVersion $dependencyVersion -Description "$script:DependencyModuleName module" - Publish-PSResource -LiteralPath $script:DependencyModuleBase + Publish-PSResource -Path $script:DependencyModuleBase # Create module to test $version = "1.0.0" - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" -RequiredModules @{ModuleName = "$script:DependencyModuleName"; ModuleVersion = "$dependencyVersion" } + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName = 'PackageManagement'; ModuleVersion = '2.0.0' }) - Publish-PSResource -LiteralPath $script:PublishModuleBase + Publish-PSResource -Path $script:PublishModuleBase - $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" - Get-ChildItem $script:repositoryPath | select-object -Last 1 | Should -Be $expectedPath + $nupkg = Get-ChildItem $script:repositoryPath | select-object -Last 1 + $nupkg.Name | Should Be "$script:PublishModuleName.$version.nupkg" } -#> It "Publish a module with a dependency that is not published, should throw" { $version = "1.0.0" $dependencyVersion = "2.0.0" - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName="PackageManagement"; ModuleVersion="$dependencyVersion"}) - - Publish-PSResource -Path $script:PublishModuleBase -ErrorAction SilentlyContinue + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.4.4' }) - $Error[0].FullyQualifiedErrorId | Should -be "DependencyNotFound,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + {Publish-PSResource -Path $script:PublishModuleBase -ErrorAction Stop} | Should -Throw -ErrorId "DependencyNotFound,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" } @@ -114,7 +109,7 @@ Describe "Test Publish-PSResource" { $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$script:PublishModuleName.$version.nupkg" (Get-ChildItem $script:repositoryPath).FullName | select-object -Last 1 | Should -Be $expectedPath } - + <# The following tests are related to passing in parameters to customize a nuspec. # These parameters are not going in the current release, but is open for discussion to include in the future. It "Publish a module with -Nuspec" { @@ -290,4 +285,27 @@ Describe "Test Publish-PSResource" { $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } + + <# The following tests required manual testing because New-ModuleManifest will not allow for incorrect syntax/formatting, + At the moment, 'Update-ModuleManifest' is not yet complete, but that too should call 'Test-ModuleManifest', which also + does not allow for incorrect syntax. + It's still important to validate these scenarios because users may alter the module manifest manually, or the file may + get corrupted. #> + <# + It "Publish a module with that has an invalid version format, should throw -- Requires Manual testing" { + $incorrectVersion = '1..0.0' + $correctVersion = '1.0.0.0' + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $incorrectVersion -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName = 'PackageManagement'; ModuleVersion = $correctVersion }) + + {Publish-PSResource -Path $script:PublishModuleBase -ErrorAction Stop} | Should -Throw -ErrorId "InvalidModuleManifest,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + } + + It "Publish a module with a dependency that has an invalid version format, should throw -- Requires Manual testing" { + $correctVersion = '1.0.0' + $incorrectVersion = '1..0.0' + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $correctVersion -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName = 'PackageManagement'; ModuleVersion = $incorrectVersion }) + + {Publish-PSResource -Path $script:PublishModuleBase -ErrorAction Stop} | Should -Throw -ErrorId "InvalidModuleManifest,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + } + #> } From 7a2fd8d289116a27a2bf612cad1339c0055fa6ad Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:27:11 -0700 Subject: [PATCH 133/276] Update Uninstall-PSResource.md --- help/Uninstall-PSResource.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index 45cb44a4a..ce325c973 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -98,6 +98,21 @@ Accept pipeline input: True Accept wildcard characters: False ``` +### -Scope +Specifies the scope of the resource to uninstall. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: (All) +Aliases: +Accepted values: CurrentUser, AllUsers + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False + ### -SkipDependencyCheck Skips check to see if other resources are dependent on the resource being uninstalled. From 6d77c359b3fd8f7c1f7831d838487c3a6f256c87 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:27:43 -0700 Subject: [PATCH 134/276] Update Get-PSResource.md --- help/Get-PSResource.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index a04868f42..3a2575eb3 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -131,6 +131,20 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -Scope +Specifies the scope of the resource. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: (All) +Aliases: +Accepted values: CurrentUser, AllUsers + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: Falsef ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). From 4f0121d715ee4c446eb3763bf99668bb93e8259f Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:28:19 -0700 Subject: [PATCH 135/276] Update Get-PSResource.md --- help/Get-PSResource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index 3a2575eb3..cc79f9213 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -13,7 +13,7 @@ Returns resources (modules and scripts) installed on the machine via PowerShellG ## SYNTAX ``` -Get-PSResource [[-Name] ] [-Version ] [-Path ] [] +Get-PSResource [[-Name] ] [-Version ] [-Path ] [-Scope ] [] ``` ## DESCRIPTION From 4fdc3241cf11ddfe2c69fb36f32765e292e7c3b3 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:28:46 -0700 Subject: [PATCH 136/276] Update Uninstall-PSResource.md --- help/Uninstall-PSResource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index ce325c973..a833341b3 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -14,7 +14,7 @@ Uninstalls a resource (module or script) that has been installed on the machine ### NameParameterSet ``` -Uninstall-PSResource [-Name] [-Version ] [-SkipDependencyCheck] [-WhatIf] [] +Uninstall-PSResource [-Name] [-Version ] [-Scope ] [-SkipDependencyCheck] [-WhatIf] [] ``` ### InputObjectParameterSet From 137780cc1084d8544502a8c696fb903a124c32e7 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:57:30 -0700 Subject: [PATCH 137/276] Update Update-PSResource.md --- help/Update-PSResource.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 167a60673..62d2e6a78 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -15,7 +15,7 @@ Updates a package already installed on the user's machine. ### NameParameterSet (Default) ``` Update-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] + [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-AuthenticodeCheck] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -221,6 +221,19 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -AuthenticodeCheck +Does a check to to validate signed files and catalog files on Windows. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False ### -SkipdependencyCheck Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. From 90d295ef887ead8ca3a6dc3501c3cb297f18c0b1 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:58:54 -0700 Subject: [PATCH 138/276] Update Save-PSResource.md --- help/Save-PSResource.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 8e9f667af..4071ae0ea 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -15,7 +15,7 @@ Saves resources (modules and scripts) from a registered repository onto the mach ### NameParameterSet ``` Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] + [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet @@ -199,6 +199,19 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` + ### -AuthenticodeCheck +Does a check to to validate signed files and catalog files on Windows. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False ### -PassThru Passes the resource saved to the console. From 41248803bba9e2c3b8e405dee8aa560d3b73f0af Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 13:59:07 -0700 Subject: [PATCH 139/276] Update Install-PSResource.md --- help/Install-PSResource.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 8272e9fbc..f7321bf41 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -16,13 +16,13 @@ Installs resources (modules and scripts) from a registered repository onto the m ``` Install-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-PassThru] [-WhatIf] [-Confirm] [] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet ``` Install-PSResource [-InputObject ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -252,6 +252,19 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -AuthenticodeCheck +Does a check to to validate signed files and catalog files on Windows. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False ### -PassThru Passes the resource installed to the console. @@ -322,4 +335,4 @@ None ## NOTES -## RELATED LINKS \ No newline at end of file +## RELATED LINKS From ee056c2fd502c852a277ad7af4159f504b4e2596 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 14:21:22 -0700 Subject: [PATCH 140/276] Update Set-PSResourceRepository.md --- help/Set-PSResourceRepository.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index 90eba5cb6..042a56113 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -14,7 +14,7 @@ Sets information for a registered repository. ### NameParameterSet (Default) ``` -Set-PSResourceRepository [-Name] [-Uri ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository [-Name] [-Uri ][CredentialInfo ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet @@ -129,6 +129,24 @@ Type: String Parameter Sets: NameParameterSet Aliases: +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` +### -CredentialInfo +Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. +Takes a PSCredentialInfo Objects which takes in a vault name and secret name. +This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + +`New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + +```yaml +Type: PSCredentialInfo +Parameter Sets: NameParameterSet +Aliases: + Required: False Position: Named Default value: None From 2d620ddfc92281710c6295cad91b3aca64018775 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 18 May 2022 14:21:36 -0700 Subject: [PATCH 141/276] Update Register-PSResourceRepository.md --- help/Register-PSResourceRepository.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index 9b5cc7855..183f58259 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -14,7 +14,7 @@ Registers a repository for PowerShell resources. ### NameParameterSet (Default) ``` -Register-PSResourceRepository [-Name] [-Uri] [-Trusted] [-Priority ] [-PassThru] +Register-PSResourceRepository [-Name ] [-Uri ] [CredentialInfo ] [-Trusted] [-Priority ] [-PassThru] [-WhatIf] [-Confirm] [] ``` @@ -164,6 +164,24 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -CredentialInfo +Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. +Takes a PSCredentialInfo Objects which takes in a vault name and secret name. +This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + +`New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + +```yaml +Type: PSCredentialInfo +Parameter Sets: NameParameterSet +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` ### -Confirm Prompts you for confirmation before running the cmdlet. From 2d307af9928f9c64b06f845f3d75e4bc1bfe36e3 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 18 May 2022 18:09:00 -0700 Subject: [PATCH 142/276] Update tests for Publish-PSResource (#648) --- test/PublishPSResource.Tests.ps1 | 31 ++-- .../incorrectdepmoduleversion.psd1 | 132 ++++++++++++++++++ .../incorrectmoduleversion.psd1 | 132 ++++++++++++++++++ 3 files changed, 277 insertions(+), 18 deletions(-) create mode 100644 test/testFiles/testModules/incorrectdepmoduleversion/incorrectdepmoduleversion.psd1 create mode 100644 test/testFiles/testModules/incorrectmoduleversion/incorrectmoduleversion.psd1 diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 604087dd7..615271346 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -40,6 +40,10 @@ Describe "Test Publish-PSResource" { # Create temp destination path $script:destinationPath = [IO.Path]::GetFullPath((Join-Path -Path $TestDrive -ChildPath "tmpDestinationPath")) New-Item $script:destinationPath -ItemType directory -Force + + # Path to folder, within our test folder, where we store invalid module files used for testing + $script:testFilesFolderPath = Join-Path $psscriptroot -ChildPath "testFiles" + $script:testModulesFolderPath = Join-Path $testFilesFolderPath -ChildPath "testModules" } AfterAll { # Get-RevertPSResourceRepositoryFile @@ -286,26 +290,17 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } - <# The following tests required manual testing because New-ModuleManifest will not allow for incorrect syntax/formatting, - At the moment, 'Update-ModuleManifest' is not yet complete, but that too should call 'Test-ModuleManifest', which also - does not allow for incorrect syntax. - It's still important to validate these scenarios because users may alter the module manifest manually, or the file may - get corrupted. #> - <# - It "Publish a module with that has an invalid version format, should throw -- Requires Manual testing" { - $incorrectVersion = '1..0.0' - $correctVersion = '1.0.0.0' - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $incorrectVersion -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName = 'PackageManagement'; ModuleVersion = $correctVersion }) - - {Publish-PSResource -Path $script:PublishModuleBase -ErrorAction Stop} | Should -Throw -ErrorId "InvalidModuleManifest,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + It "Publish a module with that has an invalid version format, should throw" { + $moduleName = "incorrectmoduleversion" + $incorrectmoduleversion = Join-Path -Path $script:testModulesFolderPath -ChildPath $moduleName + + {Publish-PSResource -Path $incorrectmoduleversion -ErrorAction Stop} | Should -Throw -ErrorId "InvalidModuleManifest,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" } - It "Publish a module with a dependency that has an invalid version format, should throw -- Requires Manual testing" { - $correctVersion = '1.0.0' - $incorrectVersion = '1..0.0' - New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $correctVersion -Description "$script:PublishModuleName module" -RequiredModules @(@{ModuleName = 'PackageManagement'; ModuleVersion = $incorrectVersion }) + It "Publish a module with a dependency that has an invalid version format, should throw" { + $moduleName = "incorrectdepmoduleversion" + $incorrectdepmoduleversion = Join-Path -Path $script:testModulesFolderPath -ChildPath $moduleName - {Publish-PSResource -Path $script:PublishModuleBase -ErrorAction Stop} | Should -Throw -ErrorId "InvalidModuleManifest,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + {Publish-PSResource -Path $incorrectdepmoduleversion -ErrorAction Stop} | Should -Throw -ErrorId "InvalidModuleManifest,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" } - #> } diff --git a/test/testFiles/testModules/incorrectdepmoduleversion/incorrectdepmoduleversion.psd1 b/test/testFiles/testModules/incorrectdepmoduleversion/incorrectdepmoduleversion.psd1 new file mode 100644 index 000000000..54bd102c8 --- /dev/null +++ b/test/testFiles/testModules/incorrectdepmoduleversion/incorrectdepmoduleversion.psd1 @@ -0,0 +1,132 @@ +# +# Module manifest for module 'testmodule-incorrect' +# +# Generated by: americks +# +# Generated on: 5/18/2022 +# + +@{ + + # Script module or binary module file associated with this manifest. + # RootModule = '' + + # Version number of this module. + ModuleVersion = '1.0.0.0' + + # Supported PSEditions + # CompatiblePSEditions = @() + + # ID used to uniquely identify this module + GUID = '4f56ed2b-72af-4c29-bda6-ef3dc91c1624' + + # Author of this module + Author = 'americks' + + # Company or vendor of this module + CompanyName = 'Unknown' + + # Copyright statement for this module + Copyright = '(c) americks. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'incorrectdepmoduleversion module' + + # Minimum version of the PowerShell engine required by this module + # PowerShellVersion = '' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # DotNetFrameworkVersion = '' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1..0.0'; }) + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + # TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + # FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + FunctionsToExport = '*' + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + CmdletsToExport = '*' + + # Variables to export from this module + VariablesToExport = '*' + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + AliasesToExport = '*' + + # DSC resources to export from this module + # DscResourcesToExport = @() + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' + + } + \ No newline at end of file diff --git a/test/testFiles/testModules/incorrectmoduleversion/incorrectmoduleversion.psd1 b/test/testFiles/testModules/incorrectmoduleversion/incorrectmoduleversion.psd1 new file mode 100644 index 000000000..864acb695 --- /dev/null +++ b/test/testFiles/testModules/incorrectmoduleversion/incorrectmoduleversion.psd1 @@ -0,0 +1,132 @@ +# +# Module manifest for module 'testmodule-incorrect' +# +# Generated by: americks +# +# Generated on: 5/18/2022 +# + +@{ + +# Script module or binary module file associated with this manifest. +# RootModule = '' + +# Version number of this module. +ModuleVersion = '1..0.0' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '4f56ed2b-72af-4c29-bda6-ef3dc91c1604' + +# Author of this module +Author = 'americks' + +# Company or vendor of this module +CompanyName = 'Unknown' + +# Copyright statement for this module +Copyright = '(c) americks. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'incorrectmoduleversion module' + +# Minimum version of the PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.0.0.0'; }) + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = '*' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + From f15f79074afd0a15042216f987ef3ea6d6d981da Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 19 May 2022 10:57:36 -0400 Subject: [PATCH 143/276] Publish-PSResource Script publishing support (#642) support/bugfixes for publishing scripts --- src/code/PublishPSResource.cs | 439 +++++++++++------- test/PSGetTestUtils.psm1 | 28 +- test/PublishPSResource.Tests.ps1 | 118 ++++- .../InvalidScriptMissingAuthor.ps1 | 43 ++ .../InvalidScriptMissingDescription.ps1 | 42 ++ ...idScriptMissingDescriptionCommentBlock.ps1 | 37 ++ .../testScripts/InvalidScriptMissingGuid.ps1 | 43 ++ .../InvalidScriptMissingVersion.ps1 | 43 ++ 8 files changed, 610 insertions(+), 183 deletions(-) create mode 100644 test/testFiles/testScripts/InvalidScriptMissingAuthor.ps1 create mode 100644 test/testFiles/testScripts/InvalidScriptMissingDescription.ps1 create mode 100644 test/testFiles/testScripts/InvalidScriptMissingDescriptionCommentBlock.ps1 create mode 100644 test/testFiles/testScripts/InvalidScriptMissingGuid.ps1 create mode 100644 test/testFiles/testScripts/InvalidScriptMissingVersion.ps1 diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 8ff51d999..f80f0ca5c 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -18,6 +18,7 @@ using System.Management.Automation; using System.Management.Automation.Language; using System.Net.Http; +using System.Text.RegularExpressions; using System.Threading; using System.Xml; @@ -50,28 +51,9 @@ public sealed class PublishPSResource : PSCmdlet /// Specifies the path to the resource that you want to publish. This parameter accepts the path to the folder that contains the resource. /// Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). /// - [Parameter] + [Parameter (Mandatory = true)] [ValidateNotNullOrEmpty] - public string Path - { - get - { return _path; } - - set - { - string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - - if (Directory.Exists(resolvedPath)) - { - _path = resolvedPath; - } - else if (File.Exists(resolvedPath) && resolvedPath.EndsWith(PSDataFileExt, StringComparison.OrdinalIgnoreCase)) - { - _path = resolvedPath; - } - } - } - private string _path; + public string Path { get; set; } /// /// Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the @@ -79,36 +61,7 @@ public string Path /// [Parameter] [ValidateNotNullOrEmpty] - public string DestinationPath - { - get - { return _destinationPath; } - - set - { - string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - - if (Directory.Exists(resolvedPath)) - { - _destinationPath = resolvedPath; - } - else - { - try - { - Directory.CreateDirectory(value); - } - catch (Exception e) - { - var exMessage = string.Format("Destination path does not exist and cannot be created: {0}", e.Message); - var ex = new ArgumentException(exMessage); - var InvalidDestinationPath = new ErrorRecord(ex, "InvalidDestinationPath", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(InvalidDestinationPath); - } - } - } - } - private string _destinationPath; + public string DestinationPath { get; set; } /// /// Specifies a user account that has rights to a specific repository (used for finding dependencies). @@ -162,12 +115,14 @@ public PSCredential ProxyCredential { #region Members + private string _path; private CancellationToken _cancellationToken; private NuGetVersion _pkgVersion; private string _pkgName; private static char[] _PathSeparators = new[] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; public const string PSDataFileExt = ".psd1"; public const string PSScriptFileExt = ".ps1"; + private const string PSScriptInfoCommentString = "<#PSScriptInfo"; #endregion @@ -180,9 +135,51 @@ protected override void BeginProcessing() // Create a respository story (the PSResourceRepository.xml file) if it does not already exist // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); + + string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path).First().Path; + + if (Directory.Exists(resolvedPath) || + (File.Exists(resolvedPath) && resolvedPath.EndsWith(PSScriptFileExt, StringComparison.OrdinalIgnoreCase))) + { + // condition 1: we point to a folder when publishing a module + // condition 2: we point to a .ps1 file directly when publishing a script, but not to .psd1 file (for publishing a module) + _path = resolvedPath; + } + else + { + // unsupported file path + var exMessage = string.Format("Either the path to the resource to publish does not exist or is not in the correct format, for scripts point to .ps1 file and for modules point to folder containing .psd1"); + var ex = new ArgumentException(exMessage); + var InvalidSourcePathError = new ErrorRecord(ex, "InvalidSourcePath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidSourcePathError); + } + + if (!String.IsNullOrEmpty(DestinationPath)) + { + string resolvedDestinationPath = SessionState.Path.GetResolvedPSPathFromPSPath(DestinationPath).First().Path; + + if (Directory.Exists(resolvedDestinationPath)) + { + DestinationPath = resolvedDestinationPath; + } + else + { + try + { + Directory.CreateDirectory(resolvedDestinationPath); + } + catch (Exception e) + { + var exMessage = string.Format("Destination path does not exist and cannot be created: {0}", e.Message); + var ex = new ArgumentException(exMessage); + var InvalidDestinationPath = new ErrorRecord(ex, "InvalidDestinationPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidDestinationPath); + } + } + } } - protected override void ProcessRecord() + protected override void EndProcessing() { // Returns the name of the file or the name of the directory, depending on path var pkgFileOrDir = new DirectoryInfo(_path); @@ -195,41 +192,21 @@ protected override void ProcessRecord() } string resourceFilePath; - Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); + Hashtable parsedMetadata; if (isScript) { resourceFilePath = pkgFileOrDir.FullName; // Check that script metadata is valid - // ParseScriptMetadata will write non-terminating error if it's unsuccessful in parsing - parsedMetadataHash = ParseScriptMetadata(resourceFilePath); - - // Check that the value is valid input - // If it does not contain 'Version' or the Version empty or whitespace, write error - if (!parsedMetadataHash.ContainsKey("Version") || String.IsNullOrWhiteSpace(parsedMetadataHash["Version"].ToString())) - { - var message = "No version was provided in the script metadata. Script metadata must specify a version, author and description."; - var ex = new ArgumentException(message); - var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); - WriteError(InvalidScriptMetadata); - - return; - } - if (!parsedMetadataHash.ContainsKey("Author") || String.IsNullOrWhiteSpace(parsedMetadataHash["Author"].ToString())) + if (!TryParseScriptMetadata( + out parsedMetadata, + resourceFilePath, + out ErrorRecord[] errors)) { - var message = "No author was provided in the script metadata. Script metadata must specify a version, author and description."; - var ex = new ArgumentException(message); - var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); - WriteError(InvalidScriptMetadata); - - return; - } - if (!parsedMetadataHash.ContainsKey("Description") || String.IsNullOrWhiteSpace(parsedMetadataHash["Description"].ToString())) - { - var message = "No description was provided in the script metadata. Script metadata must specify a version, author and description."; - var ex = new ArgumentException(message); - var InvalidScriptMetadata = new ErrorRecord(ex, "InvalidScriptMetadata", ErrorCategory.InvalidData, null); - WriteError(InvalidScriptMetadata); + foreach (ErrorRecord err in errors) + { + WriteError(err); + } return; } @@ -241,6 +218,7 @@ protected override void ProcessRecord() { _pkgName = pkgFileOrDir.Name; resourceFilePath = System.IO.Path.Combine(_path, _pkgName + PSDataFileExt); + parsedMetadata = new Hashtable(); // Validate that there's a module manifest if (!File.Exists(resourceFilePath)) @@ -290,7 +268,7 @@ protected override void ProcessRecord() outputDir: outputDir, filePath: resourceFilePath, isScript: isScript, - parsedMetadataHash: parsedMetadataHash, + parsedMetadataHash: parsedMetadata, requiredModules: out dependencies); } catch (Exception e) @@ -321,6 +299,16 @@ protected override void ProcessRecord() return; } + else if(repository.Uri.Scheme == Uri.UriSchemeFile && !repository.Uri.IsUnc && !Directory.Exists(repository.Uri.LocalPath)) + { + // this check to ensure valid local path is not for UNC paths (which are server based, instead of Drive based) + var message = String.Format("The repository '{0}' with uri: {1} is not a valid folder path which exists. If providing a file based repository, provide a repository with a path that exists.", Repository, repository.Uri.AbsoluteUri); + var ex = new ArgumentException(message); + var fileRepositoryPathDoesNotExistError = new ErrorRecord(ex, "repositoryPathDoesNotExist", ErrorCategory.ObjectNotFound, null); + WriteError(fileRepositoryPathDoesNotExistError); + + return; + } // Check if dependencies already exist within the repo if: // 1) the resource to publish has dependencies and @@ -337,7 +325,7 @@ protected override void ProcessRecord() if (isScript) { // copy the script file to the temp directory - File.Copy(_path, System.IO.Path.Combine(outputDir, _pkgName + PSDataFileExt), true); + File.Copy(_path, System.IO.Path.Combine(outputDir, _pkgName + PSScriptFileExt), true); } else { @@ -366,35 +354,24 @@ protected override void ProcessRecord() var outputNupkgDir = System.IO.Path.Combine(outputDir, "nupkg"); - // pack into a nupkg - try + // pack into .nupkg + if (!PackNupkg(outputDir, outputNupkgDir, nuspec, out ErrorRecord packNupkgError)) { - if (!PackNupkg(outputDir, outputNupkgDir, nuspec)) - { - return; - } - } - catch (Exception e) - { - var message = string.Format("Error packing into .nupkg: '{0}'.", e.Message); - var ex = new ArgumentException(message); - var ErrorPackingIntoNupkg = new ErrorRecord(ex, "ErrorPackingIntoNupkg", ErrorCategory.NotSpecified, null); - WriteError(ErrorPackingIntoNupkg); - - // exit process record + WriteError(packNupkgError); + // exit out of processing return; } // If -DestinationPath is specified then also publish the .nupkg there - if (!string.IsNullOrWhiteSpace(_destinationPath)) + if (!string.IsNullOrWhiteSpace(DestinationPath)) { try { var nupkgName = _pkgName + "." + _pkgVersion.ToNormalizedString() + ".nupkg"; - File.Copy(System.IO.Path.Combine(outputNupkgDir, nupkgName), System.IO.Path.Combine(_destinationPath, nupkgName)); + File.Copy(System.IO.Path.Combine(outputNupkgDir, nupkgName), System.IO.Path.Combine(DestinationPath, nupkgName)); } catch (Exception e) { - var message = string.Format("Error moving .nupkg into destination path '{0}' due to: '{1}'.", _destinationPath, e.Message); + var message = string.Format("Error moving .nupkg into destination path '{0}' due to: '{1}'.", DestinationPath, e.Message); var ex = new ArgumentException(message); var ErrorMovingNupkg = new ErrorRecord(ex, "ErrorMovingNupkg", ErrorCategory.NotSpecified, null); @@ -405,10 +382,15 @@ protected override void ProcessRecord() } } - // This call does not throw any exceptions, but it will write unsuccessful responses to the console string repositoryUri = repository.Uri.AbsoluteUri; - PushNupkg(outputNupkgDir, repository.Name, repositoryUri); - + + // This call does not throw any exceptions, but it will write unsuccessful responses to the console + if (!PushNupkg(outputNupkgDir, repository.Name, repositoryUri, out ErrorRecord pushNupkgError)) + { + WriteError(pushNupkgError); + // exit out of processing + return; + } } finally { @@ -416,8 +398,8 @@ protected override void ProcessRecord() Utils.DeleteDirectory(outputDir); } - } + } #endregion #region Private methods @@ -737,9 +719,15 @@ private Hashtable ParseRequiredModules(Hashtable parsedMetadataHash) return dependenciesHash; } - private Hashtable ParseScriptMetadata(string filePath) + private bool TryParseScriptMetadata( + out Hashtable parsedMetadata, + string filePath, + out ErrorRecord[] errors) { - // parse .ps1 - example .ps1 metadata: + parsedMetadata = new Hashtable(); + List parseMetadataErrors = new List(); + + // a valid example script will have this format: /* <#PSScriptInfo .VERSION 1.6 .GUID abf490023 - 9128 - 4323 - sdf9a - jf209888ajkl @@ -748,8 +736,9 @@ .COMPANYNAME Microsoft .COPYRIGHT .TAGS Windows MacOS #> - + <# + .SYNOPSIS Synopsis description here .DESCRIPTION @@ -757,54 +746,154 @@ Description here .PARAMETER Name .EXAMPLE Example cmdlet here + #> */ - // We're retrieving all the comments within a script and grabbing all the key/value pairs - // because there's no standard way to create metadata for a script. - Hashtable parsedMetadataHash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); - // parse comments out - Parser.ParseFile( + // Parse the script file + var ast = Parser.ParseFile( filePath, out System.Management.Automation.Language.Token[] tokens, - out ParseError[] errors); + out ParseError[] parserErrors); - if (errors.Length > 0) + if (parserErrors.Length > 0) { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", filePath); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - WriteError(psdataParseError); - } - else - { - // Parse the script metadata located in comments - List parsedComments = new List(); - foreach (var token in tokens) + foreach (ParseError err in parserErrors) { - if (token.Kind == TokenKind.Comment) + // we ignore WorkFlowNotSupportedInPowerShellCore errors, as this is common in scripts currently on PSGallery + if (!String.Equals(err.ErrorId, "WorkflowNotSupportedInPowerShellCore", StringComparison.OrdinalIgnoreCase)) { - // expecting only one or two comments - var commentText = token.Text; - parsedComments.AddRange(commentText.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries)); + var message = String.Format("Could not parse '{0}' as a PowerShell script file due to {1}.", filePath, err.Message); + var ex = new ArgumentException(message); + var psScriptFileParseError = new ErrorRecord(ex, err.ErrorId, ErrorCategory.ParserError, null); + parseMetadataErrors.Add(psScriptFileParseError); } } - foreach (var line in parsedComments) + errors = parseMetadataErrors.ToArray(); + return false; + } + + if (ast == null) + { + var astNullMessage = String.Format(".ps1 file was parsed but AST was null"); + var astNullEx = new ArgumentException(astNullMessage); + var astCouldNotBeCreatedError = new ErrorRecord(astNullEx, "ASTCouldNotBeCreated", ErrorCategory.ParserError, null); + + parseMetadataErrors.Add(astCouldNotBeCreatedError); + errors = parseMetadataErrors.ToArray(); + return false; + + } + + // Get the block/group comment beginning with <#PSScriptInfo + List commentTokens = tokens.Where(a => String.Equals(a.Kind.ToString(), "Comment", StringComparison.OrdinalIgnoreCase)).ToList(); + string commentPattern = PSScriptInfoCommentString; + Regex rg = new Regex(commentPattern); + List psScriptInfoCommentTokens = commentTokens.Where(a => rg.IsMatch(a.Extent.Text)).ToList(); + + if (psScriptInfoCommentTokens.Count() == 0 || psScriptInfoCommentTokens[0] == null) + { + var message = String.Format("PSScriptInfo comment was missing or could not be parsed"); + var ex = new ArgumentException(message); + var psCommentMissingError = new ErrorRecord(ex, "psScriptInfoCommentMissingError", ErrorCategory.ParserError, null); + parseMetadataErrors.Add(psCommentMissingError); + errors = parseMetadataErrors.ToArray(); + return false; + } + + string[] commentLines = Regex.Split(psScriptInfoCommentTokens[0].Text, "[\r\n]").Where(x => !String.IsNullOrEmpty(x)).ToArray(); + string keyName = String.Empty; + string value = String.Empty; + + /** + If comment line count is not more than two, it doesn't have the any metadata property + comment block would look like: + <#PSScriptInfo + #> + */ + + if (commentLines.Count() > 2) + { + for (int i = 1; i < commentLines.Count(); i++) { - if (line.StartsWith(".")) + string line = commentLines[i]; + if (String.IsNullOrEmpty(line)) { - char[] TrimBeginning = { '.', ' ' }; - var newlist = line.Split(new char[] { ' ' }); + continue; + } - var key = newlist[0].TrimStart(TrimBeginning); - var value = newlist.Length > 1 ? newlist[1].Trim() : string.Empty; - parsedMetadataHash.Add(key, value); + // A line is starting with . conveys a new metadata property + if (line.Trim().StartsWith(".")) + { + string[] parts = line.Trim().TrimStart('.').Split(); + keyName = parts[0].ToLower(); + value = parts.Count() > 1 ? String.Join(" ", parts.Skip(1)) : String.Empty; + parsedMetadata.Add(keyName, value); } } } - return parsedMetadataHash; + // get .DESCRIPTION comment + CommentHelpInfo scriptCommentInfo = ast.GetHelpContent(); + if (scriptCommentInfo == null) + { + var message = String.Format("PSScript file is missing the required Description comment block in the script contents."); + var ex = new ArgumentException(message); + var psScriptMissingHelpContentCommentBlockError = new ErrorRecord(ex, "PSScriptMissingHelpContentCommentBlock", ErrorCategory.ParserError, null); + parseMetadataErrors.Add(psScriptMissingHelpContentCommentBlockError); + errors = parseMetadataErrors.ToArray(); + return false; + } + + if (!String.IsNullOrEmpty(scriptCommentInfo.Description) && !scriptCommentInfo.Description.Contains("<#") && !scriptCommentInfo.Description.Contains("#>")) + { + parsedMetadata.Add("description", scriptCommentInfo.Description); + } + else + { + var message = String.Format("PSScript is missing the required Description property or Description value contains '<#' or '#>' which is invalid"); + var ex = new ArgumentException(message); + var psScriptMissingDescriptionOrInvalidPropertyError = new ErrorRecord(ex, "MissingOrInvalidDescriptionInScriptMetadata", ErrorCategory.ParserError, null); + parseMetadataErrors.Add(psScriptMissingDescriptionOrInvalidPropertyError); + errors = parseMetadataErrors.ToArray(); + return false; + } + + + // Check that the mandatory properites for a script are there (version, author, guid, in addition to description) + if (!parsedMetadata.ContainsKey("version") || String.IsNullOrWhiteSpace(parsedMetadata["version"].ToString())) + { + var message = "No version was provided in the script metadata. Script metadata must specify a version, author, description, and Guid."; + var ex = new ArgumentException(message); + var MissingVersionInScriptMetadataError = new ErrorRecord(ex, "MissingVersionInScriptMetadata", ErrorCategory.InvalidData, null); + parseMetadataErrors.Add(MissingVersionInScriptMetadataError); + errors = parseMetadataErrors.ToArray(); + return false; + } + + if (!parsedMetadata.ContainsKey("author") || String.IsNullOrWhiteSpace(parsedMetadata["author"].ToString())) + { + var message = "No author was provided in the script metadata. Script metadata must specify a version, author, description, and Guid."; + var ex = new ArgumentException(message); + var MissingAuthorInScriptMetadataError = new ErrorRecord(ex, "MissingAuthorInScriptMetadata", ErrorCategory.InvalidData, null); + parseMetadataErrors.Add(MissingAuthorInScriptMetadataError); + errors = parseMetadataErrors.ToArray(); + return false; + } + + if (!parsedMetadata.ContainsKey("guid") || String.IsNullOrWhiteSpace(parsedMetadata["guid"].ToString())) + { + var message = "No guid was provided in the script metadata. Script metadata must specify a version, author, description, and Guid."; + var ex = new ArgumentException(message); + var MissingGuidInScriptMetadataError = new ErrorRecord(ex, "MissingGuidInScriptMetadata", ErrorCategory.InvalidData, null); + parseMetadataErrors.Add(MissingGuidInScriptMetadataError); + errors = parseMetadataErrors.ToArray(); + return false; + } + + errors = parseMetadataErrors.ToArray(); + return true; } private bool CheckDependenciesExist(Hashtable dependencies, string repositoryName) @@ -851,11 +940,13 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam return true; } - private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFile) + private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFile, out ErrorRecord error) { - // Pack the module or script into a nupkg given a nuspec. + // Pack the module or script into a nupkg given a nuspec. var builder = new PackageBuilder(); - var runner = new PackCommandRunner( + try + { + var runner = new PackCommandRunner( new PackArgs { CurrentDirectory = outputDir, @@ -867,21 +958,37 @@ private bool PackNupkg(string outputDir, string outputNupkgDir, string nuspecFil }, MSBuildProjectFactory.ProjectCreator, builder); - - bool success = runner.RunPackageBuild(); - if (success) - { - WriteVerbose("Successfully packed the resource into a .nupkg"); + bool success = runner.RunPackageBuild(); + + if (success) + { + WriteVerbose("Successfully packed the resource into a .nupkg"); + } + else + { + var message = String.Format("Not able to successfully pack the resource into a .nupkg"); + var ex = new InvalidOperationException(message); + var failedToPackIntoNupkgError = new ErrorRecord(ex, "failedToPackIntoNupkg", ErrorCategory.ObjectNotFound, null); + error = failedToPackIntoNupkgError; + return false; + } } - else + catch (Exception e) { - WriteVerbose("Not able to successfully pack the resource into a .nupkg"); + var message = string.Format("Unexpectd error packing into .nupkg: '{0}'.", e.Message); + var ex = new ArgumentException(message); + var ErrorPackingIntoNupkg = new ErrorRecord(ex, "ErrorPackingIntoNupkg", ErrorCategory.NotSpecified, null); + + error = ErrorPackingIntoNupkg; + // exit process record + return false; } - return success; + error = null; + return true; } - private void PushNupkg(string outputNupkgDir, string repoName, string repoUri) + private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, out ErrorRecord error) { // Push the nupkg to the appropriate repository // Pkg version is parsed from .ps1 file or .psd1 file @@ -895,7 +1002,7 @@ private void PushNupkg(string outputNupkgDir, string repoName, string repoUri) var settings = NuGet.Configuration.Settings.LoadDefaultSettings(null, null, null); ILogger log = new NuGetLogger(); - var success = true; + var success = false; try { PushRunner.Run( @@ -916,6 +1023,7 @@ private void PushNupkg(string outputNupkgDir, string repoName, string repoUri) } catch (HttpRequestException e) { + WriteVerbose(string.Format("Not able to publish resource to '{0}'", repoUri)); // look in PS repo for how httpRequestExceptions are handled // Unfortunately there is no response message are no status codes provided with the exception and no @@ -927,49 +1035,48 @@ private void PushNupkg(string outputNupkgDir, string repoName, string repoUri) var message = String.Format("{0} Please try running again with the -ApiKey parameter and specific API key for the repository specified.", e.Message); ex = new ArgumentException(message); var ApiKeyError = new ErrorRecord(ex, "ApiKeyError", ErrorCategory.AuthenticationError, null); - WriteError(ApiKeyError); + error = ApiKeyError; } else { var Error401 = new ErrorRecord(ex, "401Error", ErrorCategory.PermissionDenied, null); - WriteError(Error401); + error = Error401; } } else if (e.Message.Contains("403")) { var Error403 = new ErrorRecord(ex, "403Error", ErrorCategory.PermissionDenied, null); - WriteError(Error403); + error = Error403; } else if (e.Message.Contains("409")) { var Error409 = new ErrorRecord(ex, "409Error", ErrorCategory.PermissionDenied, null); - WriteError(Error409); + error = Error409; } else { var HTTPRequestError = new ErrorRecord(ex, "HTTPRequestError", ErrorCategory.PermissionDenied, null); - WriteError(HTTPRequestError); + error = HTTPRequestError; } - success = false; + return success; } catch (Exception e) { + WriteVerbose(string.Format("Not able to publish resource to '{0}'", repoUri)); var ex = new ArgumentException(e.Message); var PushNupkgError = new ErrorRecord(ex, "PushNupkgError", ErrorCategory.InvalidResult, null); - WriteError(PushNupkgError); + error = PushNupkgError; - success = false; + return success; } - if (success) - { - WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUri)); - } - else - { - WriteVerbose(string.Format("Not able to publish resource to '{0}'", repoUri)); - } + + WriteVerbose(string.Format("Successfully published the resource to '{0}'", repoUri)); + error = null; + success = true; + return success; + } } diff --git a/test/PSGetTestUtils.psm1 b/test/PSGetTestUtils.psm1 index 8982e6af7..e72984f60 100644 --- a/test/PSGetTestUtils.psm1 +++ b/test/PSGetTestUtils.psm1 @@ -315,18 +315,22 @@ function Get-ScriptResourcePublishedToLocalRepoTestDrive { Param( [string] - $scriptName + $scriptName, + + [string] + $scriptRepoName, + + [string] + $scriptVersion ) Get-TestDriveSetUp $scriptFilePath = Join-Path -Path $script:testIndividualResourceFolder -ChildPath "$scriptName.ps1" $null = New-Item -Path $scriptFilePath -ItemType File -Force - $version = "1.0.0" $params = @{ - #Path = $scriptFilePath - Version = $version - #GUID = + Version = $scriptVersion + GUID = [guid]::NewGuid() Author = 'Jane' CompanyName = 'Microsoft Corporation' Copyright = '(c) 2020 Microsoft Corporation. All rights reserved.' @@ -334,14 +338,13 @@ function Get-ScriptResourcePublishedToLocalRepoTestDrive LicenseUri = "https://$scriptName.com/license" IconUri = "https://$scriptName.com/icon" ProjectUri = "https://$scriptName.com" - Tags = @('Tag1','Tag2', "Tag-$scriptName-$version") + Tags = @('Tag1','Tag2', "Tag-$scriptName-$scriptVersion") ReleaseNotes = "$scriptName release notes" } $scriptMetadata = Create-PSScriptMetadata @params Set-Content -Path $scriptFilePath -Value $scriptMetadata - - Publish-PSResource -path $scriptFilePath -Repository psgettestlocal + Publish-PSResource -Path $scriptFilePath -Repository $scriptRepoName -Verbose } function Get-CommandResourcePublishedToLocalRepoTestDrive @@ -507,8 +510,6 @@ function Create-PSScriptMetadata .COPYRIGHT$(if ($Copyright) {" $Copyright"}) -.DESCRIPTION$(if ($Description) {" $Description"}) - .TAGS$(if ($Tags) {" $Tags"}) .LICENSEURI$(if ($LicenseUri) {" $LicenseUri"}) @@ -528,6 +529,13 @@ $($ReleaseNotes -join "`r`n") .PRIVATEDATA$(if ($PrivateData) {" $PrivateData"}) +#> + +<# + +.DESCRIPTION +$(if ($Description) {" $Description"}) + #> "@ return $PSScriptInfoString diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index 615271346..f2368978c 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -41,20 +41,32 @@ Describe "Test Publish-PSResource" { $script:destinationPath = [IO.Path]::GetFullPath((Join-Path -Path $TestDrive -ChildPath "tmpDestinationPath")) New-Item $script:destinationPath -ItemType directory -Force - # Path to folder, within our test folder, where we store invalid module files used for testing + #Create folder where we shall place all script files to be published for these tests + $script:tmpScriptsFolderPath = Join-Path -Path $TestDrive -ChildPath "tmpScriptsPath" + if(!(Test-Path $script:tmpScriptsFolderPath)) + { + New-Item -Path $script:tmpScriptsFolderPath -ItemType Directory -Force + } + + # Path to folder, within our test folder, where we store invalid module and script files used for testing $script:testFilesFolderPath = Join-Path $psscriptroot -ChildPath "testFiles" + + # Path to specifically to that invalid test modules folder $script:testModulesFolderPath = Join-Path $testFilesFolderPath -ChildPath "testModules" + + # Path to specifically to that invalid test scripts folder + $script:testScriptsFolderPath = Join-Path $testFilesFolderPath -ChildPath "testScripts" } AfterAll { - # Get-RevertPSResourceRepositoryFile + Get-RevertPSResourceRepositoryFile } AfterEach { - # Delete all contents of the repository without deleting the repository directory itself - # $pkgsToDelete = Join-Path -Path "$script:repositoryPath" -ChildPath "*" - # Remove-Item $pkgsToDelete -Recurse + # Delete all contents of the repository without deleting the repository directory itself + $pkgsToDelete = Join-Path -Path "$script:repositoryPath" -ChildPath "*" + Remove-Item $pkgsToDelete -Recurse - # $pkgsToDelete = Join-Path -Path "$script:repositoryPath2" -ChildPath "*" - # Remove-Item $pkgsToDelete -Recurse + $pkgsToDelete = Join-Path -Path "$script:repositoryPath2" -ChildPath "*" + Remove-Item $pkgsToDelete -Recurse } It "Publish a module with -Path to the highest priority repo" { @@ -290,6 +302,98 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } + It "publish a script locally"{ + $scriptName = "PSGetTestScript" + $scriptVersion = "1.0.0" + + $params = @{ + Version = $scriptVersion + GUID = [guid]::NewGuid() + Author = 'Jane' + CompanyName = 'Microsoft Corporation' + Copyright = '(c) 2020 Microsoft Corporation. All rights reserved.' + Description = "Description for the $scriptName script" + LicenseUri = "https://$scriptName.com/license" + IconUri = "https://$scriptName.com/icon" + ProjectUri = "https://$scriptName.com" + Tags = @('Tag1','Tag2', "Tag-$scriptName-$scriptVersion") + ReleaseNotes = "$scriptName release notes" + } + + $scriptPath = (Join-Path -Path $script:tmpScriptsFolderPath -ChildPath "$scriptName.ps1") + New-ScriptFileInfo @params -Path $scriptPath + + Publish-PSResource -Path $scriptPath + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + } + + It "should write error and not publish script when Author property is missing" { + $scriptName = "InvalidScriptMissingAuthor.ps1" + $scriptVersion = "1.0.0" + + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingAuthorInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + + $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + Test-Path -Path $publishedPath | Should -Be $false + } + + It "should write error and not publish script when Version property is missing" { + $scriptName = "InvalidScriptMissingVersion.ps1" + + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingVersionInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + + $publishedPkgs = Get-ChildItem -Path $script:repositoryPath -Filter *.nupkg + $publishedPkgs.Count | Should -Be 0 + } + + It "should write error and not publish script when Guid property is missing" { + $scriptName = "InvalidScriptMissingGuid.ps1" + $scriptVersion = "1.0.0" + + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingGuidInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + + $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + Test-Path -Path $publishedPath | Should -Be $false + } + + It "should write error and not publish script when Description property is missing" { + $scriptName = "InvalidScriptMissingDescription.ps1" + $scriptVersion = "1.0.0" + + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingOrInvalidDescriptionInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + + $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + Test-Path -Path $publishedPath | Should -Be $false + } + + It "should write error and not publish script when Description block altogether is missing" { + # we expect .ps1 files to have a separate comment block for .DESCRIPTION property, not to be included in the PSScriptInfo commment block + $scriptName = "InvalidScriptMissingDescriptionCommentBlock.ps1" + $scriptVersion = "1.0.0" + + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "PSScriptMissingHelpContentCommentBlock,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + + $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + Test-Path -Path $publishedPath | Should -Be $false + } + It "Publish a module with that has an invalid version format, should throw" { $moduleName = "incorrectmoduleversion" $incorrectmoduleversion = Join-Path -Path $script:testModulesFolderPath -ChildPath $moduleName diff --git a/test/testFiles/testScripts/InvalidScriptMissingAuthor.ps1 b/test/testFiles/testScripts/InvalidScriptMissingAuthor.ps1 new file mode 100644 index 000000000..11ecd964c --- /dev/null +++ b/test/testFiles/testScripts/InvalidScriptMissingAuthor.ps1 @@ -0,0 +1,43 @@ + +<#PSScriptInfo + +.VERSION 1.0 + +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd + +.AUTHOR + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + this is a test for a script that will be published remotely + +#> +Param() + + diff --git a/test/testFiles/testScripts/InvalidScriptMissingDescription.ps1 b/test/testFiles/testScripts/InvalidScriptMissingDescription.ps1 new file mode 100644 index 000000000..cdfed58dc --- /dev/null +++ b/test/testFiles/testScripts/InvalidScriptMissingDescription.ps1 @@ -0,0 +1,42 @@ + +<#PSScriptInfo + +.VERSION 1.0 + +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd + +.AUTHOR annavied + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + +#> +Param() + + diff --git a/test/testFiles/testScripts/InvalidScriptMissingDescriptionCommentBlock.ps1 b/test/testFiles/testScripts/InvalidScriptMissingDescriptionCommentBlock.ps1 new file mode 100644 index 000000000..b3cd98e25 --- /dev/null +++ b/test/testFiles/testScripts/InvalidScriptMissingDescriptionCommentBlock.ps1 @@ -0,0 +1,37 @@ + +<#PSScriptInfo + +.VERSION 1.0 + +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd + +.AUTHOR annavied + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + +#> + +Param() + + diff --git a/test/testFiles/testScripts/InvalidScriptMissingGuid.ps1 b/test/testFiles/testScripts/InvalidScriptMissingGuid.ps1 new file mode 100644 index 000000000..7cf637efc --- /dev/null +++ b/test/testFiles/testScripts/InvalidScriptMissingGuid.ps1 @@ -0,0 +1,43 @@ + +<#PSScriptInfo + +.VERSION 1.0 + +.GUID + +.AUTHOR annavied + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + this is a test for a script that will be published remotely + +#> +Param() + + diff --git a/test/testFiles/testScripts/InvalidScriptMissingVersion.ps1 b/test/testFiles/testScripts/InvalidScriptMissingVersion.ps1 new file mode 100644 index 000000000..1c05323f3 --- /dev/null +++ b/test/testFiles/testScripts/InvalidScriptMissingVersion.ps1 @@ -0,0 +1,43 @@ + +<#PSScriptInfo + +.VERSION + +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd + +.AUTHOR annavied + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + this is a test for a script that will be published remotely + +#> +Param() + + From 0dca492844f186de2c3838a0a61ba1b2916c07e7 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Fri, 20 May 2022 09:13:03 -0700 Subject: [PATCH 144/276] Update Install-PSResource.md --- help/Install-PSResource.md | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index f7321bf41..8c4f9b1d2 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -24,6 +24,12 @@ Install-PSResource [-Name] [-Version ] [-Prerelease] Install-PSResource [-InputObject ] [-Credential ] [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] [] ``` + +### RequiredResourceFileParameterSet +``` +Install-PSResource [-RequiredResourceFile ] [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] +``` ## DESCRIPTION The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. @@ -59,6 +65,13 @@ PS C:\> Install-PSResource Az -Reinstall ``` Installs the Az module and will write over any previously installed version if it is already installed. + +### Example 4 +```powershell +PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 +``` + +Installs the PSResources specified in the psd1 file. ## PARAMETERS @@ -131,6 +144,54 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -RequiredResourceFile +Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + +The psd1 will take a hashtable format with the module attributes like the following example +```Powershell + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} +} +``` +json files will take the following example format +```json +{ + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} +} +``` + +```yaml +Type: System.String[] +Parameter Sets: RequiredResourceFileParameterSet +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + ### -Credential Optional credentials to be used when accessing a repository. From aa2b561beb0216dc21e8ec5c49f53c6ca2ae45d5 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 08:26:24 -0700 Subject: [PATCH 145/276] Update Install-PSResource.md --- help/Install-PSResource.md | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 8c4f9b1d2..5d600ff04 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -25,6 +25,12 @@ Install-PSResource [-InputObject ] [-Credential ] [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] [] ``` +### RequiredResourceParameterSet +``` +Install-PSResource [-RequiredResource ] [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] +``` + ### RequiredResourceFileParameterSet ``` Install-PSResource [-RequiredResourceFile ] [-Credential ] [-Scope ] [-TrustRepository] @@ -72,6 +78,26 @@ PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 ``` Installs the PSResources specified in the psd1 file. + + ### Example 5 +```powershell +PS C:\> Install-PSResource -RequiredResource @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} +} +``` + +Installs the PSResources specified in the hashtable. ## PARAMETERS @@ -144,6 +170,54 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -RequiredResource +A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + +The hashtable will take a format with the module attributes like the following example +```Powershell + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} +} +``` +A json string will take the following example format +```json +{ + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} +} +``` + +```yaml +Type: RequiredResource +Parameter Sets: RequiredResource +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + ### -RequiredResourceFile Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. From d0d8db1f2988719a2e4fb18cf1c2438bae0397fc Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 08:26:53 -0700 Subject: [PATCH 146/276] Update Install-PSResource.md --- help/Install-PSResource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 5d600ff04..0b4274322 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -14,7 +14,7 @@ Installs resources (modules and scripts) from a registered repository onto the m ### NameParameterSet ``` -Install-PSResource [-Name] [-Version ] [-Prerelease] +Install-PSResource [-Name ] [-Version ] [-Prerelease] [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` From ec871296662569b8d399d57f8228457500006a4a Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 08:30:00 -0700 Subject: [PATCH 147/276] Update Find-PSResource.md --- help/Find-PSResource.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index e2a9d3371..6e9b7d5b4 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -118,6 +118,13 @@ PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. +### Example 7 +```powershell +PS C:\> Find-PSResource -Name * +``` + +This will search all PSResources from registered PSResourceRepositories. + ## PARAMETERS ### -Credential From c17b29f3ebcc6f417a5e102dfba713b23fdbd42a Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 08:42:34 -0700 Subject: [PATCH 148/276] Update Find-PSResource.md --- help/Find-PSResource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index 6e9b7d5b4..02342a805 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -275,7 +275,7 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -Confirm From a09ac5fc036471a0c93853c65413f8cc415fae31 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 10:38:13 -0700 Subject: [PATCH 149/276] Update PowerShellGet.dll-Help.xml --- help/en-US/PowerShellGet.dll-Help.xml | 4112 ++++++++++++------------- 1 file changed, 1957 insertions(+), 2155 deletions(-) diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 5e215e596..6258499a0 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -1,4 +1,4 @@ - + @@ -6,20 +6,20 @@ Find PSResource - {{ Fill in the Synopsis }} + Searches for packages from a repository (local or remote), based on `-Name` and other package properties. - {{ Fill in the Description }} + The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. Find-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card character '*'. + System.String[] System.String[] @@ -27,11 +27,11 @@ None - + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -39,22 +39,22 @@ None - + IncludeDependencies - - {{ Fill IncludeDependencies Description }} - + + When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + System.Management.Automation.SwitchParameter False - + ModuleName - - {{ Fill ModuleName Description }} - + + Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + System.String System.String @@ -64,20 +64,20 @@ Prerelease - - {{ Fill Prerelease Description }} - + + When specified, includes prerelease versions in search results returned. + System.Management.Automation.SwitchParameter False - + Repository - - {{ Fill Repository Description }} - + + 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. + System.String[] System.String[] @@ -85,11 +85,11 @@ None - - Tags - - {{ Fill Tags Description }} - + + Tag + + Filters search results for resources that include one or more of the specified tags. + System.String[] System.String[] @@ -97,30 +97,30 @@ None - + Type - - {{ Fill Type Description }} - + + Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + Module Script DscResource - RoleCapability Command - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] None - + Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -130,9 +130,9 @@ Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -141,9 +141,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -153,11 +153,11 @@ - + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -165,11 +165,11 @@ None - + IncludeDependencies - - {{ Fill IncludeDependencies Description }} - + + When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -177,11 +177,11 @@ False - + ModuleName - - {{ Fill ModuleName Description }} - + + Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + System.String System.String @@ -189,11 +189,11 @@ None - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card character '*'. + System.String[] System.String[] @@ -203,9 +203,9 @@ Prerelease - - {{ Fill Prerelease Description }} - + + When specified, includes prerelease versions in search results returned. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -213,11 +213,11 @@ False - + Repository - - {{ Fill Repository Description }} - + + 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. + System.String[] System.String[] @@ -225,11 +225,11 @@ None - - Tags - - {{ Fill Tags Description }} - + + Tag + + Filters search results for resources that include one or more of the specified tags. + System.String[] System.String[] @@ -237,23 +237,24 @@ None - + Type - - {{ Fill Type Description }} - - System.String[] + + Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] None - + Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -263,9 +264,9 @@ Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -275,9 +276,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -295,35 +296,11 @@ - - - System.String - - - - - - - - System.Management.Automation.PSCredential - - - - - - - - System.Management.Automation.SwitchParameter - - - - - - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo @@ -338,9 +315,79 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... - {{ Add example description here }} + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". + + + + -------------------------- Example 2 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... + + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". + + + + -------------------------- Example 3 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... + + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". + + + + -------------------------- Example 4 -------------------------- + PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery + Get-TargetResource 1.0.0.4 WindowsDefender PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery + Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery + Get-TargetResource 1.2.0.0 cRegFile PSGallery + Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery + Get-TargetResource 1.0.0.0 cVNIC PSGallery + Get-TargetResource 1.1.17.0 supVsts PSGallery + + This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + + + + -------------------------- Example 5 -------------------------- + PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + + This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + + This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. + + + + -------------------------- Example 7 -------------------------- + PS C:\> Find-PSResource -Name * + + This will search all PSResources from registered PSResourceRepositories. @@ -357,20 +404,20 @@ Get PSResource - {{ Fill in the Synopsis }} + Returns resources (modules and scripts) installed on the machine via PowerShellGet. - {{ Fill in the Description }} + The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. Get-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card characters or a null value. + System.String[] System.String[] @@ -380,9 +427,9 @@ Path - - {{ Fill Path Description }} - + + Specifies the path to search in. + System.String System.String @@ -392,9 +439,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -402,36 +450,30 @@ None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + Scope + + Specifies the scope of the resource. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card characters or a null value. + System.String[] System.String[] @@ -441,9 +483,9 @@ Path - - {{ Fill Path Description }} - + + Specifies the path to search in. + System.String System.String @@ -453,9 +495,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -463,51 +506,21 @@ None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter + + Scope + + Specifies the scope of the resource. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - - - - System.String[] - - - - - - - - - - System.Object - - - - - - + + @@ -516,18 +529,62 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResource Az + + This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResource Az -version "1.0.0" + + This will return version 1.0.0 of the Az module. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" + + This will return all versions of the Az module within the specified range. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Get-PSResource Az -version "4.0.1-preview" + + Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. + + + + -------------------------- Example 5 -------------------------- + PS C:\> Get-PSResource Az -version "4.0.1" + + Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] + + Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Get-PSResource Az -Path . + + This will return all versions of the Az module that have been installed in the current directory. + + + + -------------------------- Example 7 -------------------------- + PS C:\> Get-PSResource - {{ Add example description here }} + This will return all versions and scripts installed on the machine. - - - <add> - - - + @@ -535,88 +592,42 @@ Get PSResourceRepository - {{ Fill in the Synopsis }} + Finds and returns registered repository information. - {{ Fill in the Description }} + The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. Get-PSResourceRepository - + Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + + String[] - System.String[] + String[] None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - + Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + + String[] - System.String[] + String[] None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - @@ -631,7 +642,7 @@ - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo @@ -640,24 +651,56 @@ - + If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*Gallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 - {{ Add example description here }} + This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. - - - <add> - - - + @@ -665,20 +708,20 @@ Install PSResource - {{ Fill in the Synopsis }} + Installs resources (modules and scripts) from a registered repository onto the machine. - {{ Fill in the Description }} + The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. Install-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to install. Does not accept wildcard characters or a null value. + System.String[] System.String[] @@ -687,21 +730,46 @@ None - AcceptLicense - - {{ Fill AcceptLicense Description }} - + Version + + Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String - System.Management.Automation.SwitchParameter + System.String + + + None + + + Prerelease + + When specified, includes prerelease versions in search results returned. + + + System.Management.Automation.SwitchParameter False - + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -710,10 +778,26 @@ None - NoClobber - - {{ Fill NoClobber Description }} - + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -721,10 +805,10 @@ False - Prerelease - - {{ Fill Prerelease Description }} - + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + System.Management.Automation.SwitchParameter @@ -733,9 +817,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses installation progress bar. + System.Management.Automation.SwitchParameter @@ -743,10 +827,10 @@ False - Reinstall - - {{ Fill Reinstall Description }} - + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + System.Management.Automation.SwitchParameter @@ -754,38 +838,32 @@ False - Repository - - {{ Fill Repository Description }} - - System.String[] + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - Scope - - {{ Fill Scope Description }} - - - CurrentUser - AllUsers - - System.String + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + - System.String + System.Management.Automation.SwitchParameter - None + False - TrustRepository - - {{ Fill TrustRepository Description }} - + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + System.Management.Automation.SwitchParameter @@ -793,34 +871,33 @@ False - Type - - {{ Fill Type Description }} - - System.String[] + PassThru + + Passes the resource installed to the console. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - - Version - - {{ Fill Version Description }} - - System.String + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -829,9 +906,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -841,22 +918,54 @@ Install-PSResource - - AcceptLicense - - {{ Fill AcceptLicense Description }} - - - System.Management.Automation.SwitchParameter + + RequiredResource + + A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + The hashtable will take a format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + A json string will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + RequiredResource + + RequiredResource - False + None - + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -865,10 +974,26 @@ None - NoClobber - - {{ Fill NoClobber Description }} - + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -876,10 +1001,10 @@ False - Prerelease - - {{ Fill Prerelease Description }} - + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + System.Management.Automation.SwitchParameter @@ -888,9 +1013,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses installation progress bar. + System.Management.Automation.SwitchParameter @@ -898,10 +1023,10 @@ False - Reinstall - - {{ Fill Reinstall Description }} - + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + System.Management.Automation.SwitchParameter @@ -909,10 +1034,122 @@ False - Repository - - {{ Fill Repository Description }} - + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Install-PSResource + + RequiredResourceFile + + Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + The psd1 will take a hashtable format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + json files will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + System.String[] System.String[] @@ -921,38 +1158,38 @@ None - RequiredResourceFile - - {{ Fill RequiredResourceFile Description }} - - System.String + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None Scope - - {{ Fill Scope Description }} - + + Specifies the scope under which a user has access. + CurrentUser AllUsers - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None TrustRepository - - {{ Fill TrustRepository Description }} - + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -960,96 +1197,99 @@ False - Type - - {{ Fill Type Description }} - - System.String[] + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + Quiet + + Supresses installation progress bar. + System.Management.Automation.SwitchParameter False - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + System.Management.Automation.SwitchParameter False - - - Install-PSResource - - InputObject - - {{ Fill InputObject Description }} - - System.Object[] + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + - System.Object[] + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + System.Management.Automation.SwitchParameter False - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + System.Management.Automation.SwitchParameter False - - - Install-PSResource - RequiredResource - - {{ Fill RequiredResource Description }} - - System.Object + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -1058,9 +1298,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -1070,47 +1310,11 @@ - - AcceptLicense - - {{ Fill AcceptLicense Description }} - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - InputObject - - {{ Fill InputObject Description }} - - System.Object[] - - System.Object[] - - - None - - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to install. Does not accept wildcard characters or a null value. + System.String[] System.String[] @@ -1119,22 +1323,23 @@ None - NoClobber - - {{ Fill NoClobber Description }} - - System.Management.Automation.SwitchParameter + Version + + Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String - System.Management.Automation.SwitchParameter + System.String - False + None Prerelease - - {{ Fill Prerelease Description }} - + + When specified, includes prerelease versions in search results returned. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1143,34 +1348,96 @@ False - Quiet - - {{ Fill Quiet Description }} - - System.Management.Automation.SwitchParameter + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None - - Reinstall - - {{ Fill Reinstall Description }} - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter + + RequiredResource + + A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + The hashtable will take a format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + A json string will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + RequiredResource + + RequiredResource - False + None - - Repository - - {{ Fill Repository Description }} - + + RequiredResourceFile + + Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + The psd1 will take a hashtable format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + json files will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + System.String[] System.String[] @@ -1179,46 +1446,46 @@ None - RequiredResource - - {{ Fill RequiredResource Description }} - - System.Object + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential - System.Object + System.Management.Automation.PSCredential None - RequiredResourceFile - - {{ Fill RequiredResourceFile Description }} - - System.String + Scope + + Specifies the scope under which a user has access. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - Scope - - {{ Fill Scope Description }} - - System.String + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter - None + False - TrustRepository - - {{ Fill TrustRepository Description }} - + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1227,34 +1494,34 @@ False - Type - - {{ Fill Type Description }} - - System.String[] + Quiet + + Supresses installation progress bar. + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False - Version - - {{ Fill Version Description }} - - System.String + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1262,11 +1529,11 @@ False - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1274,43 +1541,69 @@ False - - - + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter + + False + + + PassThru - + Passes the resource installed to the console. - - + System.Management.Automation.SwitchParameter - System.Object[] + System.Management.Automation.SwitchParameter + + False + + + InputObject - + Used for pipeline input. - - + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.Management.Automation.PSCredential + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + None + + + Confirm - + Prompts you for confirmation before running the cmdlet. - - - - + System.Management.Automation.SwitchParameter - System.Object + System.Management.Automation.SwitchParameter + + False + + + WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - - + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + @@ -1319,555 +1612,67 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Install-PSResource Az - {{ Add example description here }} + Installs the Az module. - - - - <add> - - - - - - - Publish-PSResource - Publish - PSResource - - {{ Fill in the Synopsis }} - - - - {{ Fill in the Description }} - - - - Publish-PSResource - - Path - - {{ Fill Path Description }} - - System.String - - System.String - - - None - - - APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - Nuspec - - {{ Fill Nuspec Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - - System.String - - System.String - - - None - - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - - System.String - - System.String - - - None - - - Repository - - {{ Fill Repository Description }} - - System.String - - System.String - - - None - - - SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - - - System.Management.Automation.SwitchParameter - - - False - - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - Publish-PSResource - - APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - LiteralPath - - {{ Fill LiteralPath Description }} - - System.String - - System.String - - - None - - - Nuspec - - {{ Fill Nuspec Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - - System.String - - System.String - - - None - - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - - System.String - - System.String - - - None - - - Repository - - {{ Fill Repository Description }} - - System.String - - System.String - - - None - - - SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - - - System.Management.Automation.SwitchParameter - - - False - - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - Publish-PSResource - - APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - - System.String - - System.String - - - None - - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - - System.String - - System.String - - - None - - - Repository - - {{ Fill Repository Description }} - - System.String - - System.String - - - None - - - SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - - - System.Management.Automation.SwitchParameter - - - False - - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - + + -------------------------- Example 2 -------------------------- + PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" + + Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Install-PSResource Az -Repository PSGallery + + Installs the latest stable Az module from the PowerShellGallery. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Install-PSResource Az -Reinstall + + Installs the Az module and will write over any previously installed version if it is already installed. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 + + Installs the PSResources specified in the psd1 file. + + + + + + Online Version: + + + + + + + Publish-PSResource + Publish + PSResource + + Publishes a specified module from the local computer to PSResource repository. + + + + The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. + + Publish-PSResource - - APIKey - - {{ Fill APIKey Description }} - + + Path + + When specified, includes prerelease versions in search. + System.String System.String @@ -1876,22 +1681,10 @@ None - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - + APIKey + + Specifies the API key that you want to use to publish a resource to the online gallery. + System.String System.String @@ -1900,22 +1693,22 @@ None - Exclude - - {{ Fill Exclude Description }} - - System.String[] + Repository + + Specifies the repository to publish to. + + System.String - System.String[] + System.String None - - Nuspec - - {{ Fill Nuspec Description }} - + + DestinationPath + + Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + System.String System.String @@ -1924,22 +1717,22 @@ None - Repository - - {{ Fill Repository Description }} - - System.String + Credential + + Specifies a user account that has rights to a specific repository (used for finding dependencies). + + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - + + Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + System.Management.Automation.SwitchParameter @@ -1948,9 +1741,9 @@ Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -1959,9 +1752,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -1973,81 +1766,9 @@ APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - LiteralPath - - {{ Fill LiteralPath Description }} - + + Specifies the API key that you want to use to publish a resource to the online gallery. + System.String System.String @@ -2056,10 +1777,10 @@ None - Nuspec - - {{ Fill Nuspec Description }} - + Repository + + Specifies the repository to publish to. + System.String System.String @@ -2067,23 +1788,11 @@ None - + Path - - {{ Fill Path Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - + + When specified, includes prerelease versions in search. + System.String System.String @@ -2091,11 +1800,11 @@ None - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - + + DestinationPath + + Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + System.String System.String @@ -2104,22 +1813,22 @@ None - Repository - - {{ Fill Repository Description }} - - System.String + Credential + + Specifies a user account that has rights to a specific repository (used for finding dependencies). + + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - + + Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2127,23 +1836,11 @@ False - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2153,9 +1850,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2164,26 +1861,8 @@ False - - - - System.String - - - - - - - - - - System.Object - - - - - - + + @@ -2192,15 +1871,22 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Publish-PSResource -Path c:\Test-Module + + This will publish the module 'Test-Module' to the highest priority repository + + + + -------------------------- Example 2 -------------------------- + PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' - {{ Add example description here }} + This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. - <add> + Online Version: @@ -2211,260 +1897,233 @@ Register PSResourceRepository - {{ Fill in the Synopsis }} + Registers a repository for PowerShell resources. - {{ Fill in the Description }} + The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. Register-PSResourceRepository Name - - {{ Fill Name Description }} - - System.String + + Name of the repository to be registered. Cannot be "PSGallery". + + String - System.String + String None - URL - - {{ Fill URL Description }} - - System.Uri - - System.Uri - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential + Uri + + Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + + String - System.Management.Automation.PSCredential + String None Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 - System.Uri + Int32 - None + 50 - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + Trusted + + Specifies whether the repository should be trusted. + - System.Management.Automation.PSCredential + SwitchParameter - None + False - Trusted - - {{ Fill Trusted Description }} - + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Management.Automation.SwitchParameter + PSCredentialInfo - False + None Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + - System.Management.Automation.SwitchParameter + SwitchParameter False - - - Register-PSResourceRepository - Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + PassThru + + When specified, displays the succcessfully registered repository and its information. + - System.Uri + SwitchParameter - None + False - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + + Register-PSResourceRepository + + Priority + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 - System.Management.Automation.PSCredential + Int32 - None + 50 PSGallery - - {{ Fill PSGallery Description }} - + + When specified, registers PSGallery repository. + - System.Management.Automation.SwitchParameter + SwitchParameter False Trusted - - {{ Fill Trusted Description }} - + + Specifies whether the repository should be trusted. + - System.Management.Automation.SwitchParameter + SwitchParameter False Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + - System.Management.Automation.SwitchParameter + SwitchParameter False - - - Register-PSResourceRepository - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + + PassThru + + When specified, displays the succcessfully registered repository and its information. + - System.Uri + SwitchParameter - None + False - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + + Register-PSResourceRepository + + Repository + + Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + + Hashtable[] - System.Management.Automation.PSCredential + Hashtable[] None - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] + + Trusted + + Specifies whether the repository should be trusted. + - System.Collections.Generic.List`1[System.Collections.Hashtable] + SwitchParameter - None + False Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + + SwitchParameter + + + False + + + PassThru + + When specified, displays the succcessfully registered repository and its information. + - System.Management.Automation.SwitchParameter + SwitchParameter False @@ -2472,151 +2131,132 @@ - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - Name - - {{ Fill Name Description }} - - System.String + + Name of the repository to be registered. Cannot be "PSGallery". + + String - System.String + String None Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri - - System.Uri - - - None - - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 - System.Management.Automation.PSCredential + Int32 - None + 50 PSGallery - - {{ Fill PSGallery Description }} - - System.Management.Automation.SwitchParameter + + When specified, registers PSGallery repository. + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] + + Repository + + Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + + Hashtable[] - System.Collections.Generic.List`1[System.Collections.Hashtable] + Hashtable[] None Trusted - - {{ Fill Trusted Description }} - - System.Management.Automation.SwitchParameter + + Specifies whether the repository should be trusted. + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - URL - - {{ Fill URL Description }} - - System.Uri + Uri + + Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + + String + + String + + + None + + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Uri + PSCredentialInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - - - - - System.Management.Automation.PSCredential - + + PassThru - + When specified, displays the succcessfully registered repository and its information. - + SwitchParameter + + SwitchParameter + + + False + + + - System.Uri + System.String @@ -2626,7 +2266,7 @@ - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) @@ -2635,24 +2275,49 @@ - + Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. + Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). + Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + + This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Register-PSResourceRepository -PSGallery +PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. + + + + -------------------------- Example 3 -------------------------- + PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} +PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables +PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir False 50 - {{ Add example description here }} + This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. - - - <add> - - - + @@ -2660,20 +2325,20 @@ Save PSResource - {{ Fill in the Synopsis }} + Saves resources (modules and scripts) from a registered repository onto the machine. - {{ Fill in the Description }} + The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. Save-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to save. Does not accept wildcard characters or a null value. + System.String[] System.String[] @@ -2682,21 +2347,46 @@ None - AsNupkg - - {{ Fill AsNupkg Description }} - + Version + + Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + Specifies to include prerelease versions. + System.Management.Automation.SwitchParameter False - + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -2704,11 +2394,22 @@ None + + AsNupkg + + Saves the resource as a zipped .nupkg file. + + + System.Management.Automation.SwitchParameter + + + False + IncludeXML - - {{ Fill IncludeXML Description }} - + + Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + System.Management.Automation.SwitchParameter @@ -2717,9 +2418,9 @@ Path - - {{ Fill Path Description }} - + + Specifies the path to save the resource to. + System.String System.String @@ -2728,10 +2429,10 @@ None - Prerelease - - {{ Fill Prerelease Description }} - + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -2739,34 +2440,66 @@ False - Repository - - {{ Fill Repository Description }} - - System.String[] + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - Version - - {{ Fill Version Description }} - - System.String + PassThru + + Passes the resource saved to the console. + - System.String + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses progress information. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -2775,9 +2508,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -2787,11 +2520,36 @@ + + Name + + Name of a resource or resources to save. Does not accept wildcard characters or a null value. + + System.String[] + + System.String[] + + + None + - AsNupkg - - {{ Fill AsNupkg Description }} - + Version + + Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + Specifies to include prerelease versions. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2799,11 +2557,23 @@ False - + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -2812,10 +2582,10 @@ None - IncludeXML - - {{ Fill IncludeXML Description }} - + AsNupkg + + Saves the resource as a zipped .nupkg file. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2823,23 +2593,23 @@ False - - Name - - {{ Fill Name Description }} - - System.String[] + + IncludeXML + + Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False Path - - {{ Fill Path Description }} - + + Specifies the path to save the resource to. + System.String System.String @@ -2848,10 +2618,10 @@ None - Prerelease - - {{ Fill Prerelease Description }} - + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2860,34 +2630,70 @@ False - Repository - - {{ Fill Repository Description }} - - System.String[] + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False + + + PassThru + + Passes the resource saved to the console. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses progress information. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False - - Version - - {{ Fill Version Description }} - - System.String + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2897,9 +2703,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2908,42 +2714,8 @@ False - - - - System.String[] - - - - - - - - System.Management.Automation.PSCredential - - - - - - - - System.String - - - - - - - - - - System.Object - - - - - - + + @@ -2952,15 +2724,36 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Save-PSResource -Name Az - {{ Add example description here }} + Saves the Az module + + + + -------------------------- Example 2 -------------------------- + PS C:\> Save-PSResource -Name Az -Repository PSGallery + + Saves the Az module found in the PowerShellGallery + + + + -------------------------- Example 3 -------------------------- + PS C:\> Save-PSResource Az -AsNupkg + + Saves the Az module as a .nupkg file + + + + -------------------------- Example 4 -------------------------- + PS C:\> Save-PSResource Az -IncludeXML + + Saves the Az module and includes the PowerShellGet XML metadata - <add> + Online Version: @@ -2971,20 +2764,20 @@ Set PSResourceRepository - {{ Fill in the Synopsis }} + Sets information for a registered repository. - {{ Fill in the Description }} + The Set-PSResourceRepository cmdlet sets information for a registered repository. Set-PSResourceRepository - + Name - - {{ Fill Name Description }} - + + Specifies the name of the repository to be set. + System.String System.String @@ -2992,23 +2785,11 @@ None - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - + Priority - - {{ Fill Priority Description }} - + + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + System.Int32 System.Int32 @@ -3016,131 +2797,58 @@ None - - Proxy - - {{ Fill Proxy Description }} - - System.Uri - - System.Uri - - - None - - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - Trusted - - {{ Fill Trusted Description }} - + + Specifies whether the repository should be trusted. + System.Management.Automation.SwitchParameter False - - URL - - {{ Fill URL Description }} - - System.Uri + + Uri + + Specifies the location of the repository to be set. + + String - System.Uri + String None - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Management.Automation.SwitchParameter + PSCredentialInfo - False + None - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + PassThru + + When specified, displays the succcessfully registered repository and its information + System.Management.Automation.SwitchParameter False - - - Set-PSResourceRepository - - Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri - - System.Uri - - - None - - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] - - System.Collections.Generic.List`1[System.Collections.Hashtable] - - - None - Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -3149,9 +2857,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -3161,23 +2869,11 @@ - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - + Name - - {{ Fill Name Description }} - + + Specifies the name of the repository to be set. + System.String System.String @@ -3185,11 +2881,11 @@ None - + Priority - - {{ Fill Priority Description }} - + + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + System.Int32 System.Int32 @@ -3197,47 +2893,48 @@ None - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + + Trusted + + Specifies whether the repository should be trusted. + + System.Management.Automation.SwitchParameter - System.Uri + System.Management.Automation.SwitchParameter - None + False - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + Uri + + Specifies the location of the repository to be set. + + String - System.Management.Automation.PSCredential + String None - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Collections.Generic.List`1[System.Collections.Hashtable] + PSCredentialInfo None - - Trusted - - {{ Fill Trusted Description }} - + + PassThru + + When specified, displays the succcessfully registered repository and its information + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3245,23 +2942,11 @@ False - - URL - - {{ Fill URL Description }} - - System.Uri - - System.Uri - - - None - Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3271,9 +2956,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3293,31 +2978,7 @@ - System.Uri - - - - - - - - System.Management.Automation.PSCredential - - - - - - - - System.Collections.Generic.List`1[[System.Collections.Hashtable, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] - - - - - - - - System.Int32 + System.Collections.Hashtable[] @@ -3327,7 +2988,7 @@ - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) @@ -3342,18 +3003,53 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery file:///c:/code/testdir False 50 + + This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 25 + + This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + +PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} + +PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 50 + PoshTestGallery file:///c:/code/testdir False 50 - {{ Add example description here }} + This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. - - - <add> - - - + @@ -3361,20 +3057,20 @@ Uninstall PSResource - {{ Fill in the Synopsis }} + Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. - {{ Fill in the Description }} + The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. Uninstall-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources that has been installed. Accepts wild card characters. + System.String[] System.String[] @@ -3382,56 +3078,62 @@ None - - Force - - {{ Fill Force Description }} - + + Version + + Specifies the version of the resource to be uninstalled. + + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - PrereleaseOnly - - {{ Fill PrereleaseOnly Description }} - + Scope + + Specifies the scope of the resource to uninstall. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - Version - - {{ Fill Version Description }} - - System.String + SkipDependencyCheck + + Skips check to see if other resources are dependent on the resource being uninstalled. + - System.String + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - False + None WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -3441,35 +3143,47 @@ - - Force - - {{ Fill Force Description }} - - System.Management.Automation.SwitchParameter + + Name + + Name of a resource or resources that has been installed. Accepts wild card characters. + + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None + + + Version + + Specifies the version of the resource to be uninstalled. + + System.String + + System.String + + + None - - Name - - {{ Fill Name Description }} - - System.String[] + + Scope + + Specifies the scope of the resource to uninstall. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - PrereleaseOnly - - {{ Fill PrereleaseOnly Description }} - + SkipDependencyCheck + + Skips check to see if other resources are dependent on the resource being uninstalled. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3477,35 +3191,23 @@ False - - Version - - {{ Fill Version Description }} - - System.String + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3514,26 +3216,8 @@ False - - - - System.String[] - - - - - - - - - - System.Object - - - - - - + + @@ -3542,18 +3226,41 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Uninstall-PSResource Az + + Uninstalls the latest version of the Az module. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "1.0.0" + + Uninstalls version 1.0.0 of the Az module. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" + + Uninstalls all versions within the specified version range. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" + + Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease - {{ Add example description here }} + Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. - - - <add> - - - + @@ -3561,45 +3268,56 @@ Unregister PSResourceRepository - {{ Fill in the Synopsis }} + Un-registers a repository from the repository store. - {{ Fill in the Description }} + The Unregister-PSResourceRepository cmdlet unregisters a repository. Unregister-PSResourceRepository Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + + String[] - System.String[] + String[] None + + PassThru + + Passes the resource installed to the console. + + + SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + - System.Management.Automation.SwitchParameter + SwitchParameter False @@ -3609,36 +3327,48 @@ Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + + String[] - System.String[] + String[] None + + PassThru + + Passes the resource installed to the console. + + SwitchParameter + + SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False @@ -3654,16 +3384,7 @@ - - - - System.Object - - - - - - + @@ -3672,18 +3393,34 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> + + In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 + +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" +PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 - {{ Add example description here }} + In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. - - - <add> - - - + @@ -3691,43 +3428,43 @@ Update PSResource - {{ Fill in the Synopsis }} + Updates a package already installed on the user's machine. - {{ Fill in the Description }} + The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. It updates an already installed package based on the `-Name` parameter argument. It does not return an object. Other parameters allow the package to be updated to be further filtered. Update-PSResource - + Name - - {{ Fill Name Description }} - + + Specifies name of a resource or resources to update. + System.String[] System.String[] - None + "*" AcceptLicense - - {{ Fill AcceptLicense Description }} - + + For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + System.Management.Automation.SwitchParameter False - + Credential - - {{ Fill Credential Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -3735,22 +3472,11 @@ None - - NoClobber - - {{ Fill NoClobber Description }} - - - System.Management.Automation.SwitchParameter - - - False - Prerelease - - {{ Fill Prerelease Description }} - + + When specified, allows updating to a prerelease version. + System.Management.Automation.SwitchParameter @@ -3759,9 +3485,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses progress information. + System.Management.Automation.SwitchParameter @@ -3770,9 +3496,9 @@ Repository - - {{ Fill Repository Description }} - + + Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + System.String[] System.String[] @@ -3782,25 +3508,25 @@ Scope - - {{ Fill Scope Description }} - + + Specifies the scope of the resource to update. + CurrentUser AllUsers - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None TrustRepository - - {{ Fill TrustRepository Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.SwitchParameter @@ -3809,9 +3535,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -3819,11 +3546,55 @@ None + + Force + + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource updated to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipdependencyCheck + + Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -3832,9 +3603,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -3846,9 +3617,9 @@ AcceptLicense - - {{ Fill AcceptLicense Description }} - + + For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3856,11 +3627,11 @@ False - + Credential - - {{ Fill Credential Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -3868,35 +3639,23 @@ None - + Name - - {{ Fill Name Description }} - + + Specifies name of a resource or resources to update. + System.String[] System.String[] - None - - - NoClobber - - {{ Fill NoClobber Description }} - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False + "*" Prerelease - - {{ Fill Prerelease Description }} - + + When specified, allows updating to a prerelease version. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3906,9 +3665,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses progress information. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3918,9 +3677,9 @@ Repository - - {{ Fill Repository Description }} - + + Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + System.String[] System.String[] @@ -3930,21 +3689,21 @@ Scope - - {{ Fill Scope Description }} - - System.String + + Specifies the scope of the resource to update. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None TrustRepository - - {{ Fill TrustRepository Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3954,9 +3713,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -3964,11 +3724,59 @@ None + + Force + + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource updated to the console. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + SkipdependencyCheck + + Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3978,9 +3786,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3998,25 +3806,8 @@ - - - System.Management.Automation.PSCredential - - - - - - - - - System.Object - - - - - - + @@ -4025,9 +3816,20 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Update-PSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.2.0 test + +PS C:\> Update-PSResource -Name "TestModule" + +PS C:\> Update-PSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.3.0 test + TestModule 1.2.0 test - {{ Add example description here }} + In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. From d020296d165d124c2d91c79fdb497f1b8cf6f43f Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 10:42:09 -0700 Subject: [PATCH 150/276] Update Get-PSResource.md --- help/Get-PSResource.md | 1 + 1 file changed, 1 insertion(+) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index cc79f9213..8d5384e0a 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -145,6 +145,7 @@ Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: Falsef +``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). From 8e163689fb94adadc0d3d05e686388b66682f34f Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 10:42:22 -0700 Subject: [PATCH 151/276] Update Get-PSResource.md --- help/Get-PSResource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index 8d5384e0a..23df4b701 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -144,7 +144,7 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: Falsef +Accept wildcard characters: False ``` ### CommonParameters From a150a8d58318a150323f8d87dfd3e0ffddd022f4 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 10:43:26 -0700 Subject: [PATCH 152/276] Update Install-PSResource.md --- help/Install-PSResource.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 0b4274322..7ff060471 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -400,7 +400,8 @@ Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False - +``` + ### -PassThru Passes the resource installed to the console. From ef930d8a0f0ecf4230a92d24f77ad9d13640ae49 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 23 May 2022 10:46:10 -0700 Subject: [PATCH 153/276] Update Update-PSResource.md --- help/Update-PSResource.md | 1 + 1 file changed, 1 insertion(+) diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 62d2e6a78..1471e002a 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -234,6 +234,7 @@ Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False +``` ### -SkipdependencyCheck Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. From 47dcfe0d4d327c50ff835a914b6404894dbd4529 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 24 May 2022 13:29:38 -0700 Subject: [PATCH 154/276] Update Install-PSResource.md --- help/Install-PSResource.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 7ff060471..042e305b8 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -16,7 +16,7 @@ Installs resources (modules and scripts) from a registered repository onto the m ``` Install-PSResource [-Name ] [-Version ] [-Prerelease] [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet @@ -381,20 +381,6 @@ Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` -### -AuthenticodeCheck -Does a check to to validate signed files and catalog files on Windows. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: - Required: False Position: Named Default value: None From bb5beeb01e9c4a5464c9f27cea73b5478a9df0e4 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 24 May 2022 13:30:17 -0700 Subject: [PATCH 155/276] Update Save-PSResource.md --- help/Save-PSResource.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 4071ae0ea..2809af983 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -15,7 +15,7 @@ Saves resources (modules and scripts) from a registered repository onto the mach ### NameParameterSet ``` Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] + [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet @@ -199,20 +199,7 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - ### -AuthenticodeCheck -Does a check to to validate signed files and catalog files on Windows. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False - + ### -PassThru Passes the resource saved to the console. From 1cee1c5079591255c5dcf57a9f380b43194019dc Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 24 May 2022 13:31:03 -0700 Subject: [PATCH 156/276] Update Update-PSResource.md --- help/Update-PSResource.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 1471e002a..167a60673 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -15,7 +15,7 @@ Updates a package already installed on the user's machine. ### NameParameterSet (Default) ``` Update-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-AuthenticodeCheck] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] + [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -215,20 +215,6 @@ Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` -### -AuthenticodeCheck -Does a check to to validate signed files and catalog files on Windows. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: - Required: False Position: Named Default value: None From 0991d595f13f8de5857a8b387851644bfe1a4d46 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 25 May 2022 01:36:05 -0400 Subject: [PATCH 157/276] Help updates for Preview 13 release (#651) --- help/Find-PSResource.md | 9 +- help/Get-PSResource.md | 17 +- help/Install-PSResource.md | 143 +- help/Register-PSResourceRepository.md | 20 +- help/Save-PSResource.md | 2 +- help/Set-PSResourceRepository.md | 20 +- help/Uninstall-PSResource.md | 17 +- help/en-US/PowerShellGet.dll-Help.xml | 4112 ++++++++++++------------- 8 files changed, 2175 insertions(+), 2165 deletions(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index e2a9d3371..02342a805 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -118,6 +118,13 @@ PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. +### Example 7 +```powershell +PS C:\> Find-PSResource -Name * +``` + +This will search all PSResources from registered PSResourceRepositories. + ## PARAMETERS ### -Credential @@ -268,7 +275,7 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -Confirm diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index a04868f42..23df4b701 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -13,7 +13,7 @@ Returns resources (modules and scripts) installed on the machine via PowerShellG ## SYNTAX ``` -Get-PSResource [[-Name] ] [-Version ] [-Path ] [] +Get-PSResource [[-Name] ] [-Version ] [-Path ] [-Scope ] [] ``` ## DESCRIPTION @@ -125,6 +125,21 @@ Type: System.String Parameter Sets: NameParameterSet Aliases: +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` +### -Scope +Specifies the scope of the resource. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: (All) +Aliases: +Accepted values: CurrentUser, AllUsers + Required: False Position: Named Default value: None diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 8272e9fbc..042e305b8 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -14,7 +14,7 @@ Installs resources (modules and scripts) from a registered repository onto the m ### NameParameterSet ``` -Install-PSResource [-Name] [-Version ] [-Prerelease] +Install-PSResource [-Name ] [-Version ] [-Prerelease] [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` @@ -22,7 +22,19 @@ Install-PSResource [-Name] [-Version ] [-Prerelease] ### InputObjectParameterSet ``` Install-PSResource [-InputObject ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] [] +``` + +### RequiredResourceParameterSet +``` +Install-PSResource [-RequiredResource ] [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] +``` + +### RequiredResourceFileParameterSet +``` +Install-PSResource [-RequiredResourceFile ] [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -59,6 +71,33 @@ PS C:\> Install-PSResource Az -Reinstall ``` Installs the Az module and will write over any previously installed version if it is already installed. + +### Example 4 +```powershell +PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 +``` + +Installs the PSResources specified in the psd1 file. + + ### Example 5 +```powershell +PS C:\> Install-PSResource -RequiredResource @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} +} +``` + +Installs the PSResources specified in the hashtable. ## PARAMETERS @@ -131,6 +170,102 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -RequiredResource +A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + +The hashtable will take a format with the module attributes like the following example +```Powershell + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} +} +``` +A json string will take the following example format +```json +{ + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} +} +``` + +```yaml +Type: RequiredResource +Parameter Sets: RequiredResource +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -RequiredResourceFile +Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + +The psd1 will take a hashtable format with the module attributes like the following example +```Powershell + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} +} +``` +json files will take the following example format +```json +{ + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} +} +``` + +```yaml +Type: System.String[] +Parameter Sets: RequiredResourceFileParameterSet +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + ### -Credential Optional credentials to be used when accessing a repository. @@ -252,7 +387,7 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - + ### -PassThru Passes the resource installed to the console. @@ -322,4 +457,4 @@ None ## NOTES -## RELATED LINKS \ No newline at end of file +## RELATED LINKS diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index 9b5cc7855..183f58259 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -14,7 +14,7 @@ Registers a repository for PowerShell resources. ### NameParameterSet (Default) ``` -Register-PSResourceRepository [-Name] [-Uri] [-Trusted] [-Priority ] [-PassThru] +Register-PSResourceRepository [-Name ] [-Uri ] [CredentialInfo ] [-Trusted] [-Priority ] [-PassThru] [-WhatIf] [-Confirm] [] ``` @@ -164,6 +164,24 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` +### -CredentialInfo +Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. +Takes a PSCredentialInfo Objects which takes in a vault name and secret name. +This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + +`New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + +```yaml +Type: PSCredentialInfo +Parameter Sets: NameParameterSet +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` ### -Confirm Prompts you for confirmation before running the cmdlet. diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 8e9f667af..2809af983 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -199,7 +199,7 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - + ### -PassThru Passes the resource saved to the console. diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index 90eba5cb6..042a56113 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -14,7 +14,7 @@ Sets information for a registered repository. ### NameParameterSet (Default) ``` -Set-PSResourceRepository [-Name] [-Uri ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository [-Name] [-Uri ][CredentialInfo ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet @@ -129,6 +129,24 @@ Type: String Parameter Sets: NameParameterSet Aliases: +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` +### -CredentialInfo +Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. +Takes a PSCredentialInfo Objects which takes in a vault name and secret name. +This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + +`New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + +```yaml +Type: PSCredentialInfo +Parameter Sets: NameParameterSet +Aliases: + Required: False Position: Named Default value: None diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index 45cb44a4a..a833341b3 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -14,7 +14,7 @@ Uninstalls a resource (module or script) that has been installed on the machine ### NameParameterSet ``` -Uninstall-PSResource [-Name] [-Version ] [-SkipDependencyCheck] [-WhatIf] [] +Uninstall-PSResource [-Name] [-Version ] [-Scope ] [-SkipDependencyCheck] [-WhatIf] [] ``` ### InputObjectParameterSet @@ -98,6 +98,21 @@ Accept pipeline input: True Accept wildcard characters: False ``` +### -Scope +Specifies the scope of the resource to uninstall. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: (All) +Aliases: +Accepted values: CurrentUser, AllUsers + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False + ### -SkipDependencyCheck Skips check to see if other resources are dependent on the resource being uninstalled. diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 5e215e596..6258499a0 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -1,4 +1,4 @@ - + @@ -6,20 +6,20 @@ Find PSResource - {{ Fill in the Synopsis }} + Searches for packages from a repository (local or remote), based on `-Name` and other package properties. - {{ Fill in the Description }} + The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. Find-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card character '*'. + System.String[] System.String[] @@ -27,11 +27,11 @@ None - + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -39,22 +39,22 @@ None - + IncludeDependencies - - {{ Fill IncludeDependencies Description }} - + + When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + System.Management.Automation.SwitchParameter False - + ModuleName - - {{ Fill ModuleName Description }} - + + Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + System.String System.String @@ -64,20 +64,20 @@ Prerelease - - {{ Fill Prerelease Description }} - + + When specified, includes prerelease versions in search results returned. + System.Management.Automation.SwitchParameter False - + Repository - - {{ Fill Repository Description }} - + + 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. + System.String[] System.String[] @@ -85,11 +85,11 @@ None - - Tags - - {{ Fill Tags Description }} - + + Tag + + Filters search results for resources that include one or more of the specified tags. + System.String[] System.String[] @@ -97,30 +97,30 @@ None - + Type - - {{ Fill Type Description }} - + + Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + Module Script DscResource - RoleCapability Command - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] None - + Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -130,9 +130,9 @@ Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -141,9 +141,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -153,11 +153,11 @@ - + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -165,11 +165,11 @@ None - + IncludeDependencies - - {{ Fill IncludeDependencies Description }} - + + When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -177,11 +177,11 @@ False - + ModuleName - - {{ Fill ModuleName Description }} - + + Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + System.String System.String @@ -189,11 +189,11 @@ None - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card character '*'. + System.String[] System.String[] @@ -203,9 +203,9 @@ Prerelease - - {{ Fill Prerelease Description }} - + + When specified, includes prerelease versions in search results returned. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -213,11 +213,11 @@ False - + Repository - - {{ Fill Repository Description }} - + + 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. + System.String[] System.String[] @@ -225,11 +225,11 @@ None - - Tags - - {{ Fill Tags Description }} - + + Tag + + Filters search results for resources that include one or more of the specified tags. + System.String[] System.String[] @@ -237,23 +237,24 @@ None - + Type - - {{ Fill Type Description }} - - System.String[] + + Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] None - + Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -263,9 +264,9 @@ Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -275,9 +276,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -295,35 +296,11 @@ - - - System.String - - - - - - - - System.Management.Automation.PSCredential - - - - - - - - System.Management.Automation.SwitchParameter - - - - - - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo @@ -338,9 +315,79 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... - {{ Add example description here }} + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". + + + + -------------------------- Example 2 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... + + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". + + + + -------------------------- Example 3 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... + + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". + + + + -------------------------- Example 4 -------------------------- + PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery + Get-TargetResource 1.0.0.4 WindowsDefender PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery + Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery + Get-TargetResource 1.2.0.0 cRegFile PSGallery + Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery + Get-TargetResource 1.0.0.0 cVNIC PSGallery + Get-TargetResource 1.1.17.0 supVsts PSGallery + + This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + + + + -------------------------- Example 5 -------------------------- + PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + + This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + + This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. + + + + -------------------------- Example 7 -------------------------- + PS C:\> Find-PSResource -Name * + + This will search all PSResources from registered PSResourceRepositories. @@ -357,20 +404,20 @@ Get PSResource - {{ Fill in the Synopsis }} + Returns resources (modules and scripts) installed on the machine via PowerShellGet. - {{ Fill in the Description }} + The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. Get-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card characters or a null value. + System.String[] System.String[] @@ -380,9 +427,9 @@ Path - - {{ Fill Path Description }} - + + Specifies the path to search in. + System.String System.String @@ -392,9 +439,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -402,36 +450,30 @@ None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + Scope + + Specifies the scope of the resource. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to find. Accepts wild card characters or a null value. + System.String[] System.String[] @@ -441,9 +483,9 @@ Path - - {{ Fill Path Description }} - + + Specifies the path to search in. + System.String System.String @@ -453,9 +495,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -463,51 +506,21 @@ None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter + + Scope + + Specifies the scope of the resource. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - - - - System.String[] - - - - - - - - - - System.Object - - - - - - + + @@ -516,18 +529,62 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResource Az + + This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResource Az -version "1.0.0" + + This will return version 1.0.0 of the Az module. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" + + This will return all versions of the Az module within the specified range. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Get-PSResource Az -version "4.0.1-preview" + + Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. + + + + -------------------------- Example 5 -------------------------- + PS C:\> Get-PSResource Az -version "4.0.1" + + Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] + + Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Get-PSResource Az -Path . + + This will return all versions of the Az module that have been installed in the current directory. + + + + -------------------------- Example 7 -------------------------- + PS C:\> Get-PSResource - {{ Add example description here }} + This will return all versions and scripts installed on the machine. - - - <add> - - - + @@ -535,88 +592,42 @@ Get PSResourceRepository - {{ Fill in the Synopsis }} + Finds and returns registered repository information. - {{ Fill in the Description }} + The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. Get-PSResourceRepository - + Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + + String[] - System.String[] + String[] None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - + Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + + String[] - System.String[] + String[] None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - @@ -631,7 +642,7 @@ - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo @@ -640,24 +651,56 @@ - + If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*Gallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 - {{ Add example description here }} + This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. - - - <add> - - - + @@ -665,20 +708,20 @@ Install PSResource - {{ Fill in the Synopsis }} + Installs resources (modules and scripts) from a registered repository onto the machine. - {{ Fill in the Description }} + The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. Install-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to install. Does not accept wildcard characters or a null value. + System.String[] System.String[] @@ -687,21 +730,46 @@ None - AcceptLicense - - {{ Fill AcceptLicense Description }} - + Version + + Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String - System.Management.Automation.SwitchParameter + System.String + + + None + + + Prerelease + + When specified, includes prerelease versions in search results returned. + + + System.Management.Automation.SwitchParameter False - + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -710,10 +778,26 @@ None - NoClobber - - {{ Fill NoClobber Description }} - + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -721,10 +805,10 @@ False - Prerelease - - {{ Fill Prerelease Description }} - + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + System.Management.Automation.SwitchParameter @@ -733,9 +817,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses installation progress bar. + System.Management.Automation.SwitchParameter @@ -743,10 +827,10 @@ False - Reinstall - - {{ Fill Reinstall Description }} - + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + System.Management.Automation.SwitchParameter @@ -754,38 +838,32 @@ False - Repository - - {{ Fill Repository Description }} - - System.String[] + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - Scope - - {{ Fill Scope Description }} - - - CurrentUser - AllUsers - - System.String + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + - System.String + System.Management.Automation.SwitchParameter - None + False - TrustRepository - - {{ Fill TrustRepository Description }} - + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + System.Management.Automation.SwitchParameter @@ -793,34 +871,33 @@ False - Type - - {{ Fill Type Description }} - - System.String[] + PassThru + + Passes the resource installed to the console. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - - Version - - {{ Fill Version Description }} - - System.String + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -829,9 +906,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -841,22 +918,54 @@ Install-PSResource - - AcceptLicense - - {{ Fill AcceptLicense Description }} - - - System.Management.Automation.SwitchParameter + + RequiredResource + + A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + The hashtable will take a format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + A json string will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + RequiredResource + + RequiredResource - False + None - + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -865,10 +974,26 @@ None - NoClobber - - {{ Fill NoClobber Description }} - + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -876,10 +1001,10 @@ False - Prerelease - - {{ Fill Prerelease Description }} - + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + System.Management.Automation.SwitchParameter @@ -888,9 +1013,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses installation progress bar. + System.Management.Automation.SwitchParameter @@ -898,10 +1023,10 @@ False - Reinstall - - {{ Fill Reinstall Description }} - + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + System.Management.Automation.SwitchParameter @@ -909,10 +1034,122 @@ False - Repository - - {{ Fill Repository Description }} - + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Install-PSResource + + RequiredResourceFile + + Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + The psd1 will take a hashtable format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + json files will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + System.String[] System.String[] @@ -921,38 +1158,38 @@ None - RequiredResourceFile - - {{ Fill RequiredResourceFile Description }} - - System.String + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None Scope - - {{ Fill Scope Description }} - + + Specifies the scope under which a user has access. + CurrentUser AllUsers - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None TrustRepository - - {{ Fill TrustRepository Description }} - + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -960,96 +1197,99 @@ False - Type - - {{ Fill Type Description }} - - System.String[] + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + Quiet + + Supresses installation progress bar. + System.Management.Automation.SwitchParameter False - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + System.Management.Automation.SwitchParameter False - - - Install-PSResource - - InputObject - - {{ Fill InputObject Description }} - - System.Object[] + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + - System.Object[] + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + System.Management.Automation.SwitchParameter False - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + System.Management.Automation.SwitchParameter False - - - Install-PSResource - RequiredResource - - {{ Fill RequiredResource Description }} - - System.Object + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -1058,9 +1298,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -1070,47 +1310,11 @@ - - AcceptLicense - - {{ Fill AcceptLicense Description }} - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - InputObject - - {{ Fill InputObject Description }} - - System.Object[] - - System.Object[] - - - None - - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to install. Does not accept wildcard characters or a null value. + System.String[] System.String[] @@ -1119,22 +1323,23 @@ None - NoClobber - - {{ Fill NoClobber Description }} - - System.Management.Automation.SwitchParameter + Version + + Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String - System.Management.Automation.SwitchParameter + System.String - False + None Prerelease - - {{ Fill Prerelease Description }} - + + When specified, includes prerelease versions in search results returned. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1143,34 +1348,96 @@ False - Quiet - - {{ Fill Quiet Description }} - - System.Management.Automation.SwitchParameter + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None - - Reinstall - - {{ Fill Reinstall Description }} - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter + + RequiredResource + + A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + The hashtable will take a format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + A json string will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + RequiredResource + + RequiredResource - False + None - - Repository - - {{ Fill Repository Description }} - + + RequiredResourceFile + + Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + The psd1 will take a hashtable format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + json files will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + System.String[] System.String[] @@ -1179,46 +1446,46 @@ None - RequiredResource - - {{ Fill RequiredResource Description }} - - System.Object + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential - System.Object + System.Management.Automation.PSCredential None - RequiredResourceFile - - {{ Fill RequiredResourceFile Description }} - - System.String + Scope + + Specifies the scope under which a user has access. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - Scope - - {{ Fill Scope Description }} - - System.String + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter - None + False - TrustRepository - - {{ Fill TrustRepository Description }} - + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1227,34 +1494,34 @@ False - Type - - {{ Fill Type Description }} - - System.String[] + Quiet + + Supresses installation progress bar. + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False - Version - - {{ Fill Version Description }} - - System.String + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1262,11 +1529,11 @@ False - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -1274,43 +1541,69 @@ False - - - + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter + + False + + + PassThru - + Passes the resource installed to the console. - - + System.Management.Automation.SwitchParameter - System.Object[] + System.Management.Automation.SwitchParameter + + False + + + InputObject - + Used for pipeline input. - - + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.Management.Automation.PSCredential + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + None + + + Confirm - + Prompts you for confirmation before running the cmdlet. - - - - + System.Management.Automation.SwitchParameter - System.Object + System.Management.Automation.SwitchParameter + + False + + + WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - - + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + @@ -1319,555 +1612,67 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Install-PSResource Az - {{ Add example description here }} + Installs the Az module. - - - - <add> - - - - - - - Publish-PSResource - Publish - PSResource - - {{ Fill in the Synopsis }} - - - - {{ Fill in the Description }} - - - - Publish-PSResource - - Path - - {{ Fill Path Description }} - - System.String - - System.String - - - None - - - APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - Nuspec - - {{ Fill Nuspec Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - - System.String - - System.String - - - None - - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - - System.String - - System.String - - - None - - - Repository - - {{ Fill Repository Description }} - - System.String - - System.String - - - None - - - SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - - - System.Management.Automation.SwitchParameter - - - False - - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - Publish-PSResource - - APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - LiteralPath - - {{ Fill LiteralPath Description }} - - System.String - - System.String - - - None - - - Nuspec - - {{ Fill Nuspec Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - - System.String - - System.String - - - None - - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - - System.String - - System.String - - - None - - - Repository - - {{ Fill Repository Description }} - - System.String - - System.String - - - None - - - SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - - - System.Management.Automation.SwitchParameter - - - False - - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - Publish-PSResource - - APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - - System.String - - System.String - - - None - - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - - System.String - - System.String - - - None - - - Repository - - {{ Fill Repository Description }} - - System.String - - System.String - - - None - - - SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - - - System.Management.Automation.SwitchParameter - - - False - - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - + + -------------------------- Example 2 -------------------------- + PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" + + Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Install-PSResource Az -Repository PSGallery + + Installs the latest stable Az module from the PowerShellGallery. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Install-PSResource Az -Reinstall + + Installs the Az module and will write over any previously installed version if it is already installed. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 + + Installs the PSResources specified in the psd1 file. + + + + + + Online Version: + + + + + + + Publish-PSResource + Publish + PSResource + + Publishes a specified module from the local computer to PSResource repository. + + + + The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. + + Publish-PSResource - - APIKey - - {{ Fill APIKey Description }} - + + Path + + When specified, includes prerelease versions in search. + System.String System.String @@ -1876,22 +1681,10 @@ None - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - + APIKey + + Specifies the API key that you want to use to publish a resource to the online gallery. + System.String System.String @@ -1900,22 +1693,22 @@ None - Exclude - - {{ Fill Exclude Description }} - - System.String[] + Repository + + Specifies the repository to publish to. + + System.String - System.String[] + System.String None - - Nuspec - - {{ Fill Nuspec Description }} - + + DestinationPath + + Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + System.String System.String @@ -1924,22 +1717,22 @@ None - Repository - - {{ Fill Repository Description }} - - System.String + Credential + + Specifies a user account that has rights to a specific repository (used for finding dependencies). + + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - + + Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + System.Management.Automation.SwitchParameter @@ -1948,9 +1741,9 @@ Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -1959,9 +1752,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -1973,81 +1766,9 @@ APIKey - - {{ Fill APIKey Description }} - - System.String - - System.String - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - DestinationPath - - {{ Fill DestinationPath Description }} - - System.String - - System.String - - - None - - - Exclude - - {{ Fill Exclude Description }} - - System.String[] - - System.String[] - - - None - - - IconUrl - - {{ Fill IconUrl Description }} - - System.String - - System.String - - - None - - - LicenseUrl - - {{ Fill LicenseUrl Description }} - - System.String - - System.String - - - None - - - LiteralPath - - {{ Fill LiteralPath Description }} - + + Specifies the API key that you want to use to publish a resource to the online gallery. + System.String System.String @@ -2056,10 +1777,10 @@ None - Nuspec - - {{ Fill Nuspec Description }} - + Repository + + Specifies the repository to publish to. + System.String System.String @@ -2067,23 +1788,11 @@ None - + Path - - {{ Fill Path Description }} - - System.String - - System.String - - - None - - - ProjectUrl - - {{ Fill ProjectUrl Description }} - + + When specified, includes prerelease versions in search. + System.String System.String @@ -2091,11 +1800,11 @@ None - - ReleaseNotes - - {{ Fill ReleaseNotes Description }} - + + DestinationPath + + Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + System.String System.String @@ -2104,22 +1813,22 @@ None - Repository - - {{ Fill Repository Description }} - - System.String + Credential + + Specifies a user account that has rights to a specific repository (used for finding dependencies). + + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None SkipDependenciesCheck - - {{ Fill SkipDependenciesCheck Description }} - + + Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2127,23 +1836,11 @@ False - - Tags - - {{ Fill Tags Description }} - - System.String[] - - System.String[] - - - None - Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2153,9 +1850,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2164,26 +1861,8 @@ False - - - - System.String - - - - - - - - - - System.Object - - - - - - + + @@ -2192,15 +1871,22 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Publish-PSResource -Path c:\Test-Module + + This will publish the module 'Test-Module' to the highest priority repository + + + + -------------------------- Example 2 -------------------------- + PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' - {{ Add example description here }} + This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. - <add> + Online Version: @@ -2211,260 +1897,233 @@ Register PSResourceRepository - {{ Fill in the Synopsis }} + Registers a repository for PowerShell resources. - {{ Fill in the Description }} + The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. Register-PSResourceRepository Name - - {{ Fill Name Description }} - - System.String + + Name of the repository to be registered. Cannot be "PSGallery". + + String - System.String + String None - URL - - {{ Fill URL Description }} - - System.Uri - - System.Uri - - - None - - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential + Uri + + Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + + String - System.Management.Automation.PSCredential + String None Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 - System.Uri + Int32 - None + 50 - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + Trusted + + Specifies whether the repository should be trusted. + - System.Management.Automation.PSCredential + SwitchParameter - None + False - Trusted - - {{ Fill Trusted Description }} - + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Management.Automation.SwitchParameter + PSCredentialInfo - False + None Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + - System.Management.Automation.SwitchParameter + SwitchParameter False - - - Register-PSResourceRepository - Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + PassThru + + When specified, displays the succcessfully registered repository and its information. + - System.Uri + SwitchParameter - None + False - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + + Register-PSResourceRepository + + Priority + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 - System.Management.Automation.PSCredential + Int32 - None + 50 PSGallery - - {{ Fill PSGallery Description }} - + + When specified, registers PSGallery repository. + - System.Management.Automation.SwitchParameter + SwitchParameter False Trusted - - {{ Fill Trusted Description }} - + + Specifies whether the repository should be trusted. + - System.Management.Automation.SwitchParameter + SwitchParameter False Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + - System.Management.Automation.SwitchParameter + SwitchParameter False - - - Register-PSResourceRepository - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + + PassThru + + When specified, displays the succcessfully registered repository and its information. + - System.Uri + SwitchParameter - None + False - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + + Register-PSResourceRepository + + Repository + + Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + + Hashtable[] - System.Management.Automation.PSCredential + Hashtable[] None - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] + + Trusted + + Specifies whether the repository should be trusted. + - System.Collections.Generic.List`1[System.Collections.Hashtable] + SwitchParameter - None + False Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + + SwitchParameter + + + False + + + PassThru + + When specified, displays the succcessfully registered repository and its information. + - System.Management.Automation.SwitchParameter + SwitchParameter False @@ -2472,151 +2131,132 @@ - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - Name - - {{ Fill Name Description }} - - System.String + + Name of the repository to be registered. Cannot be "PSGallery". + + String - System.String + String None Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri - - System.Uri - - - None - - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 - System.Management.Automation.PSCredential + Int32 - None + 50 PSGallery - - {{ Fill PSGallery Description }} - - System.Management.Automation.SwitchParameter + + When specified, registers PSGallery repository. + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] + + Repository + + Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + + Hashtable[] - System.Collections.Generic.List`1[System.Collections.Hashtable] + Hashtable[] None Trusted - - {{ Fill Trusted Description }} - - System.Management.Automation.SwitchParameter + + Specifies whether the repository should be trusted. + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - URL - - {{ Fill URL Description }} - - System.Uri + Uri + + Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + + String + + String + + + None + + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Uri + PSCredentialInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - - - - - System.Management.Automation.PSCredential - + + PassThru - + When specified, displays the succcessfully registered repository and its information. - + SwitchParameter + + SwitchParameter + + + False + + + - System.Uri + System.String @@ -2626,7 +2266,7 @@ - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) @@ -2635,24 +2275,49 @@ - + Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. + Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). + Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + + This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Register-PSResourceRepository -PSGallery +PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. + + + + -------------------------- Example 3 -------------------------- + PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} +PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables +PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir False 50 - {{ Add example description here }} + This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. - - - <add> - - - + @@ -2660,20 +2325,20 @@ Save PSResource - {{ Fill in the Synopsis }} + Saves resources (modules and scripts) from a registered repository onto the machine. - {{ Fill in the Description }} + The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. Save-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources to save. Does not accept wildcard characters or a null value. + System.String[] System.String[] @@ -2682,21 +2347,46 @@ None - AsNupkg - - {{ Fill AsNupkg Description }} - + Version + + Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + Specifies to include prerelease versions. + System.Management.Automation.SwitchParameter False - + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -2704,11 +2394,22 @@ None + + AsNupkg + + Saves the resource as a zipped .nupkg file. + + + System.Management.Automation.SwitchParameter + + + False + IncludeXML - - {{ Fill IncludeXML Description }} - + + Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + System.Management.Automation.SwitchParameter @@ -2717,9 +2418,9 @@ Path - - {{ Fill Path Description }} - + + Specifies the path to save the resource to. + System.String System.String @@ -2728,10 +2429,10 @@ None - Prerelease - - {{ Fill Prerelease Description }} - + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter @@ -2739,34 +2440,66 @@ False - Repository - - {{ Fill Repository Description }} - - System.String[] + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + - System.String[] + System.Management.Automation.SwitchParameter - None + False - Version - - {{ Fill Version Description }} - - System.String + PassThru + + Passes the resource saved to the console. + - System.String + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses progress information. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -2775,9 +2508,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -2787,11 +2520,36 @@ + + Name + + Name of a resource or resources to save. Does not accept wildcard characters or a null value. + + System.String[] + + System.String[] + + + None + - AsNupkg - - {{ Fill AsNupkg Description }} - + Version + + Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + Specifies to include prerelease versions. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2799,11 +2557,23 @@ False - + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + Credential - - {{ Fill Credential Description }} - + + Optional credentials to be used when accessing a repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -2812,10 +2582,10 @@ None - IncludeXML - - {{ Fill IncludeXML Description }} - + AsNupkg + + Saves the resource as a zipped .nupkg file. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2823,23 +2593,23 @@ False - - Name - - {{ Fill Name Description }} - - System.String[] + + IncludeXML + + Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False Path - - {{ Fill Path Description }} - + + Specifies the path to save the resource to. + System.String System.String @@ -2848,10 +2618,10 @@ None - Prerelease - - {{ Fill Prerelease Description }} - + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2860,34 +2630,70 @@ False - Repository - - {{ Fill Repository Description }} - - System.String[] + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False + + + PassThru + + Passes the resource saved to the console. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses progress information. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False - - Version - - {{ Fill Version Description }} - - System.String + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2897,9 +2703,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -2908,42 +2714,8 @@ False - - - - System.String[] - - - - - - - - System.Management.Automation.PSCredential - - - - - - - - System.String - - - - - - - - - - System.Object - - - - - - + + @@ -2952,15 +2724,36 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Save-PSResource -Name Az - {{ Add example description here }} + Saves the Az module + + + + -------------------------- Example 2 -------------------------- + PS C:\> Save-PSResource -Name Az -Repository PSGallery + + Saves the Az module found in the PowerShellGallery + + + + -------------------------- Example 3 -------------------------- + PS C:\> Save-PSResource Az -AsNupkg + + Saves the Az module as a .nupkg file + + + + -------------------------- Example 4 -------------------------- + PS C:\> Save-PSResource Az -IncludeXML + + Saves the Az module and includes the PowerShellGet XML metadata - <add> + Online Version: @@ -2971,20 +2764,20 @@ Set PSResourceRepository - {{ Fill in the Synopsis }} + Sets information for a registered repository. - {{ Fill in the Description }} + The Set-PSResourceRepository cmdlet sets information for a registered repository. Set-PSResourceRepository - + Name - - {{ Fill Name Description }} - + + Specifies the name of the repository to be set. + System.String System.String @@ -2992,23 +2785,11 @@ None - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - + Priority - - {{ Fill Priority Description }} - + + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + System.Int32 System.Int32 @@ -3016,131 +2797,58 @@ None - - Proxy - - {{ Fill Proxy Description }} - - System.Uri - - System.Uri - - - None - - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - Trusted - - {{ Fill Trusted Description }} - + + Specifies whether the repository should be trusted. + System.Management.Automation.SwitchParameter False - - URL - - {{ Fill URL Description }} - - System.Uri + + Uri + + Specifies the location of the repository to be set. + + String - System.Uri + String None - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Management.Automation.SwitchParameter + PSCredentialInfo - False + None - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - + + PassThru + + When specified, displays the succcessfully registered repository and its information + System.Management.Automation.SwitchParameter False - - - Set-PSResourceRepository - - Priority - - {{ Fill Priority Description }} - - System.Int32 - - System.Int32 - - - None - - - Proxy - - {{ Fill Proxy Description }} - - System.Uri - - System.Uri - - - None - - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] - - System.Collections.Generic.List`1[System.Collections.Hashtable] - - - None - Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -3149,9 +2857,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -3161,23 +2869,11 @@ - - Credential - - {{ Fill Credential Description }} - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - + Name - - {{ Fill Name Description }} - + + Specifies the name of the repository to be set. + System.String System.String @@ -3185,11 +2881,11 @@ None - + Priority - - {{ Fill Priority Description }} - + + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + System.Int32 System.Int32 @@ -3197,47 +2893,48 @@ None - - Proxy - - {{ Fill Proxy Description }} - - System.Uri + + Trusted + + Specifies whether the repository should be trusted. + + System.Management.Automation.SwitchParameter - System.Uri + System.Management.Automation.SwitchParameter - None + False - - ProxyCredential - - {{ Fill ProxyCredential Description }} - - System.Management.Automation.PSCredential + + Uri + + Specifies the location of the repository to be set. + + String - System.Management.Automation.PSCredential + String None - - Repositories - - {{ Fill Repositories Description }} - - System.Collections.Generic.List`1[System.Collections.Hashtable] + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo - System.Collections.Generic.List`1[System.Collections.Hashtable] + PSCredentialInfo None - - Trusted - - {{ Fill Trusted Description }} - + + PassThru + + When specified, displays the succcessfully registered repository and its information + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3245,23 +2942,11 @@ False - - URL - - {{ Fill URL Description }} - - System.Uri - - System.Uri - - - None - Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3271,9 +2956,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3293,31 +2978,7 @@ - System.Uri - - - - - - - - System.Management.Automation.PSCredential - - - - - - - - System.Collections.Generic.List`1[[System.Collections.Hashtable, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] - - - - - - - - System.Int32 + System.Collections.Hashtable[] @@ -3327,7 +2988,7 @@ - System.Object + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) @@ -3342,18 +3003,53 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery file:///c:/code/testdir False 50 + + This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 25 + + This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + +PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} + +PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 50 + PoshTestGallery file:///c:/code/testdir False 50 - {{ Add example description here }} + This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. - - - <add> - - - + @@ -3361,20 +3057,20 @@ Uninstall PSResource - {{ Fill in the Synopsis }} + Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. - {{ Fill in the Description }} + The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. Uninstall-PSResource - + Name - - {{ Fill Name Description }} - + + Name of a resource or resources that has been installed. Accepts wild card characters. + System.String[] System.String[] @@ -3382,56 +3078,62 @@ None - - Force - - {{ Fill Force Description }} - + + Version + + Specifies the version of the resource to be uninstalled. + + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - PrereleaseOnly - - {{ Fill PrereleaseOnly Description }} - + Scope + + Specifies the scope of the resource to uninstall. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - Version - - {{ Fill Version Description }} - - System.String + SkipDependencyCheck + + Skips check to see if other resources are dependent on the resource being uninstalled. + - System.String + System.Management.Automation.SwitchParameter - None + False - - Confirm - - Prompts you for confirmation before running the cmdlet. - + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - False + None WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -3441,35 +3143,47 @@ - - Force - - {{ Fill Force Description }} - - System.Management.Automation.SwitchParameter + + Name + + Name of a resource or resources that has been installed. Accepts wild card characters. + + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None + + + Version + + Specifies the version of the resource to be uninstalled. + + System.String + + System.String + + + None - - Name - - {{ Fill Name Description }} - - System.String[] + + Scope + + Specifies the scope of the resource to uninstall. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - PrereleaseOnly - - {{ Fill PrereleaseOnly Description }} - + SkipDependencyCheck + + Skips check to see if other resources are dependent on the resource being uninstalled. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3477,35 +3191,23 @@ False - - Version - - {{ Fill Version Description }} - - System.String + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3514,26 +3216,8 @@ False - - - - System.String[] - - - - - - - - - - System.Object - - - - - - + + @@ -3542,18 +3226,41 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Uninstall-PSResource Az + + Uninstalls the latest version of the Az module. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "1.0.0" + + Uninstalls version 1.0.0 of the Az module. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" + + Uninstalls all versions within the specified version range. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" + + Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease - {{ Add example description here }} + Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. - - - <add> - - - + @@ -3561,45 +3268,56 @@ Unregister PSResourceRepository - {{ Fill in the Synopsis }} + Un-registers a repository from the repository store. - {{ Fill in the Description }} + The Unregister-PSResourceRepository cmdlet unregisters a repository. Unregister-PSResourceRepository Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + + String[] - System.String[] + String[] None + + PassThru + + Passes the resource installed to the console. + + + SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - + - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + - System.Management.Automation.SwitchParameter + SwitchParameter False @@ -3609,36 +3327,48 @@ Name - - {{ Fill Name Description }} - - System.String[] + + This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + + String[] - System.String[] + String[] None + + PassThru + + Passes the resource installed to the console. + + SwitchParameter + + SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter + + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False @@ -3654,16 +3384,7 @@ - - - - System.Object - - - - - - + @@ -3672,18 +3393,34 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> + + In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 + +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" +PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 - {{ Add example description here }} + In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. - - - <add> - - - + @@ -3691,43 +3428,43 @@ Update PSResource - {{ Fill in the Synopsis }} + Updates a package already installed on the user's machine. - {{ Fill in the Description }} + The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. It updates an already installed package based on the `-Name` parameter argument. It does not return an object. Other parameters allow the package to be updated to be further filtered. Update-PSResource - + Name - - {{ Fill Name Description }} - + + Specifies name of a resource or resources to update. + System.String[] System.String[] - None + "*" AcceptLicense - - {{ Fill AcceptLicense Description }} - + + For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + System.Management.Automation.SwitchParameter False - + Credential - - {{ Fill Credential Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -3735,22 +3472,11 @@ None - - NoClobber - - {{ Fill NoClobber Description }} - - - System.Management.Automation.SwitchParameter - - - False - Prerelease - - {{ Fill Prerelease Description }} - + + When specified, allows updating to a prerelease version. + System.Management.Automation.SwitchParameter @@ -3759,9 +3485,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses progress information. + System.Management.Automation.SwitchParameter @@ -3770,9 +3496,9 @@ Repository - - {{ Fill Repository Description }} - + + Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + System.String[] System.String[] @@ -3782,25 +3508,25 @@ Scope - - {{ Fill Scope Description }} - + + Specifies the scope of the resource to update. + CurrentUser AllUsers - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None TrustRepository - - {{ Fill TrustRepository Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.SwitchParameter @@ -3809,9 +3535,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -3819,11 +3546,55 @@ None + + Force + + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource updated to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipdependencyCheck + + Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter @@ -3832,9 +3603,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter @@ -3846,9 +3617,9 @@ AcceptLicense - - {{ Fill AcceptLicense Description }} - + + For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3856,11 +3627,11 @@ False - + Credential - - {{ Fill Credential Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.PSCredential System.Management.Automation.PSCredential @@ -3868,35 +3639,23 @@ None - + Name - - {{ Fill Name Description }} - + + Specifies name of a resource or resources to update. + System.String[] System.String[] - None - - - NoClobber - - {{ Fill NoClobber Description }} - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False + "*" Prerelease - - {{ Fill Prerelease Description }} - + + When specified, allows updating to a prerelease version. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3906,9 +3665,9 @@ Quiet - - {{ Fill Quiet Description }} - + + Supresses progress information. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3918,9 +3677,9 @@ Repository - - {{ Fill Repository Description }} - + + Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + System.String[] System.String[] @@ -3930,21 +3689,21 @@ Scope - - {{ Fill Scope Description }} - - System.String + + Specifies the scope of the resource to update. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None TrustRepository - - {{ Fill TrustRepository Description }} - + + Specifies optional credentials to be used when accessing a private repository. + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3954,9 +3713,10 @@ Version - - {{ Fill Version Description }} - + + Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + System.String System.String @@ -3964,11 +3724,59 @@ None + + Force + + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource updated to the console. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + SkipdependencyCheck + + Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + Confirm - + Prompts you for confirmation before running the cmdlet. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3978,9 +3786,9 @@ WhatIf - + Shows what would happen if the cmdlet runs. The cmdlet is not run. - + System.Management.Automation.SwitchParameter System.Management.Automation.SwitchParameter @@ -3998,25 +3806,8 @@ - - - System.Management.Automation.PSCredential - - - - - - - - - System.Object - - - - - - + @@ -4025,9 +3816,20 @@ -------------------------- Example 1 -------------------------- - PS C:\> {{ Add example code here }} + PS C:\> Update-PSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.2.0 test + +PS C:\> Update-PSResource -Name "TestModule" + +PS C:\> Update-PSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.3.0 test + TestModule 1.2.0 test - {{ Add example description here }} + In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. From c81c555ce67cc55b96d710916ab68fe9f1499b24 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 25 May 2022 13:31:06 -0400 Subject: [PATCH 158/276] add SupportsWildcard attribute for info to appear in help (#658) --- src/code/FindPSResource.cs | 1 + src/code/GetPSResource.cs | 1 + src/code/GetPSResourceRepository.cs | 1 + src/code/UninstallPSResource.cs | 9 +++++---- src/code/UpdatePSResource.cs | 1 + 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index f6a3c9ccf..b99b520c5 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -40,6 +40,7 @@ public sealed class FindPSResource : PSCmdlet /// /// Specifies name of a resource or resources to find. Accepts wild card characters. /// + [SupportsWildcards] [Parameter(Position = 0, ValueFromPipeline = true, ParameterSetName = ResourceNameParameterSet)] diff --git a/src/code/GetPSResource.cs b/src/code/GetPSResource.cs index 367262f7a..0db720a5f 100644 --- a/src/code/GetPSResource.cs +++ b/src/code/GetPSResource.cs @@ -28,6 +28,7 @@ public sealed class GetPSResource : PSCmdlet /// /// Specifies the desired name for the resource to look for. /// + [SupportsWildcards] [Parameter(Position = 0, ValueFromPipeline = true)] public string[] Name { get; set; } diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs index 66b6f7c6d..54eaa8ecb 100644 --- a/src/code/GetPSResourceRepository.cs +++ b/src/code/GetPSResourceRepository.cs @@ -24,6 +24,7 @@ public sealed class GetPSResourceRepository : PSCmdlet /// Specifies the name(s) of a registered repository to find. /// Supports wild card characters. /// + [SupportsWildcards] [Parameter(Position = 0, ValueFromPipeline = true)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 019484191..96a15d362 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -24,6 +24,7 @@ public sealed class UninstallPSResource : PSCmdlet /// Specifies the exact names of resources to uninstall. /// A comma-separated list of module names is accepted. The resource name must match the resource name in the repository. /// + [SupportsWildcards] [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] public string[] Name { get; set; } @@ -54,10 +55,10 @@ public sealed class UninstallPSResource : PSCmdlet [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } - /// - /// Specifies the scope of installation. - /// - [Parameter] + /// + /// Specifies the scope of installation. + /// + [Parameter] public ScopeType Scope { get; set; } #endregion diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 9913b4468..79e5e7f02 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -35,6 +35,7 @@ public sealed class UpdatePSResource : PSCmdlet /// Specifies name of a resource or resources to update. /// Accepts wildcard characters. /// + [SupportsWildcards] [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] public string[] Name { get; set ; } = new string[] {"*"}; From 4e7b7eec9862bbe17a242ea6ac385ced99d5b0aa Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 25 May 2022 13:10:32 -0700 Subject: [PATCH 159/276] Update changelog and pkg version for 3.0.13-beta release (#659) --- .ci/ci_release.yml | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ src/PowerShellGet.psd1 | 22 ++++++++++++++++++++-- src/code/PowerShellGet.csproj | 6 +++--- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index e3865843d..6aee46f35 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -244,7 +244,7 @@ stages: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' PackageName: 'PowerShellGet' - PackageVersion: '3.0.12' + PackageVersion: '3.0.13' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' diff --git a/CHANGELOG.md b/CHANGELOG.md index ee2512d2a..971f48232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # CHANGELOG +## 3.0.13-beta + +### New Features +- Implementation of -RequiredResourceFile and -RequiredResource parameters for Install-PSResource (#610, #592) +- Scope parameters for Get-PSResource and Uninstall-PSResource (#639) +- Support for credential persistence (#480 Thanks @cansuerdogan!) + +### Bug Fixes +- Bug fix for publishing scripts (#642) +- Bug fix for publishing modules with 'RequiredModules' specified in the module manifest (#640) + +### Changes +- 'SupportsWildcard' attribute added to Find-PSResource, Get-PSResource, Get-PSResourceRepository, Uninstall-PSResource, and Update-PSResource (#658) +- Updated help documentation (#651) +- -Repositories parameter changed to singular -Repository in Register-PSResource and Set-PSResource (#645) +- Better prerelease support for Uninstall-PSResource (#593) +- Rename PSResourceInfo's PrereleaseLabel property to match Prerelease column displayed (#591) +- Renaming of parameters -Url to -Uri (#551 Thanks @fsackur!) + ## 3.0.12-beta ### Changes diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index dcc368d03..5e016df9f 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.12' + ModuleVersion = '3.0.13' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -40,7 +40,25 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' -### 3.0.12 beta release +## 3.0.13-beta + +### New Features +- Implementation of -RequiredResourceFile and -RequiredResource parameters for Install-PSResource (#610, #592) +- Scope parameters for Get-PSResource and Uninstall-PSResource (#639) +- Support for credential persistence (#480 Thanks @cansuerdogan!) + +### Bug Fixes +- Bug fix for publishing scripts (#642) +- Bug fix for publishing modules with 'RequiredModules' specified in the module manifest (#640) + +### Changes +- 'SupportsWildcard' attribute added to Find-PSResource, Get-PSResource, Get-PSResourceRepository, Uninstall-PSResource, and Update-PSResource (#658) +- Updated help documentation (#651) +- -Repositories parameter changed to singular -Repository in Register-PSResource and Set-PSResource (#645) +- Better prerelease support for Uninstall-PSResource (#593) +- Rename PSResourceInfo's PrereleaseLabel property to match Prerelease column displayed (#591) +- Renaming of parameters -Url to -Uri (#551 Thanks @fsackur!) + See change log (CHANGELOG.md) at https://github.com/PowerShell/PowerShellGet '@ } diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index ccba80588..83ff3a8f3 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.12.0 - 3.0.12 - 3.0.12 + 3.0.13.0 + 3.0.13 + 3.0.13 netstandard2.0 8.0 From 42bddf6381e90aceda971007033913360b4711a2 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 26 May 2022 17:36:20 -0400 Subject: [PATCH 160/276] Psresourcerepository file bug (#661) fix Uri/Url not being null checked --- src/code/RepositorySettings.cs | 181 +++++++++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 22 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index b622bbe8e..dec5d2d15 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -98,7 +98,7 @@ public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriorit XElement newElement = new XElement( "Repository", new XAttribute("Name", repoName), - new XAttribute("Uri", repoUri), + new XAttribute("Url", repoUri), new XAttribute("Priority", repoPriority), new XAttribute("Trusted", repoTrusted) ); @@ -139,17 +139,60 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio throw new ArgumentException("Cannot find the repository because it does not exist. Try registering the repository using 'Register-PSResourceRepository'"); } + // Check that repository node we are attempting to update has all required attributes: Name, Url (or Uri), Priority, Trusted. + // Name attribute is already checked for in FindRepositoryElement() + + if (node.Attribute("Priority") == null) + { + throw new ArgumentException("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + } + + if (node.Attribute("Trusted") == null) + { + throw new ArgumentException("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + } + + bool urlAttributeExists = node.Attribute("Url") != null; + bool uriAttributeExists = node.Attribute("Uri") != null; + if (!urlAttributeExists && !uriAttributeExists) + { + throw new ArgumentException("Repository element does not contain neccessary 'Url' attribute (or alternatively 'Uri' attribute), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + } + // Else, keep going // Get root of XDocument (XElement) var root = doc.Root; - // A null Uri value passed in signifies the Uri was not attempted to be set. + // A null Uri (or Url) value passed in signifies the Uri was not attempted to be set. // So only set Uri attribute if non-null value passed in for repoUri + + // determine if existing repository node (which we wish to update) had Url to Uri attribute + Uri thisUrl = null; if (repoUri != null) { - node.Attribute("Uri").Value = repoUri.AbsoluteUri; + if (urlAttributeExists) + { + node.Attribute("Url").Value = repoUri.AbsoluteUri; + // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. + if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); + } + } + else + { + // Uri attribute exists + node.Attribute("Uri").Value = repoUri.AbsoluteUri; + if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); + } + } } + + + // A negative Priority value passed in signifies the Priority value was not attempted to be set. // So only set Priority attribute if non-null value passed in for repoPriority if (repoPriority >= 0) @@ -187,12 +230,6 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio } } - // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. - if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) - { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); - } - // Create CredentialInfo based on new values or whether it was empty to begin with PSCredentialInfo thisCredentialInfo = null; if (node.Attribute(PSCredentialInfo.VaultNameAttribute)?.Value != null && @@ -204,7 +241,7 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio } updatedRepo = new PSRepositoryInfo(repoName, - thisUri, + thisUrl, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); @@ -257,9 +294,32 @@ public static List Remove(string[] repoNames, out string[] err { repoCredentialInfo = new PSCredentialInfo(node.Attribute("VaultName").Value, node.Attribute("SecretName").Value); } + + if (node.Attribute("Priority") == null) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + if (node.Attribute("Trusted") == null) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + // determine if repo had Url or Uri (less likely) attribute + bool urlAttributeExists = node.Attribute("Url") != null; + bool uriAttributeExists = node.Attribute("Uri") != null; + if (!urlAttributeExists && !uriAttributeExists) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Url' or equivalent 'Uri' attribute (it must contain one per Repository), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + string attributeUrlUriName = urlAttributeExists ? "Url" : "Uri"; removedRepos.Add( new PSRepositoryInfo(repo, - new Uri(node.Attribute("Uri").Value), + new Uri(node.Attribute(attributeUrlUriName).Value), Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), repoCredentialInfo)); @@ -290,17 +350,58 @@ public static List Read(string[] repoNames, out string[] error throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); } - if (repoNames == null || !repoNames.Any() || string.Equals(repoNames[0], "*") || repoNames[0] == null) + if (repoNames == null || repoNames.Length == 0 || string.Equals(repoNames[0], "*") || repoNames[0] == null) { // Name array or single value is null so we will list all repositories registered // iterate through the doc foreach (XElement repo in doc.Descendants("Repository")) { - if (!Uri.TryCreate(repo.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) + if (repo.Attribute("Name") == null) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Name' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + if (repo.Attribute("Priority") == null) { - tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repo.Attribute("Name").Value)); + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } + + if (repo.Attribute("Trusted") == null) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + bool urlAttributeExists = repo.Attribute("Url") != null; + bool uriAttributeExists = repo.Attribute("Uri") != null; + // case: neither Url nor Uri attributes exist + if (!urlAttributeExists && !uriAttributeExists) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Url' or equivalent 'Uri' attribute (it must contain one), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + Uri thisUrl = null; + // case: either attribute Uri or Url exists + // TODO: do we only allow both to exist, across repositories? (i.e if a file has Uri attribute for one repo and Url attribute for another --> is that invalid?) + if (urlAttributeExists) + { + if (!Uri.TryCreate(repo.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) + { + tempErrorList.Add(String.Format("Unable to read incorrectly formatted Url for repo {0}", repo.Attribute("Name").Value)); + continue; + } + } + else if (uriAttributeExists) + { + if (!Uri.TryCreate(repo.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) + { + tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repo.Attribute("Name").Value)); + continue; + } + } PSCredentialInfo thisCredentialInfo; string credentialInfoErrorMessage = $"Repository {repo.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; @@ -335,7 +436,7 @@ public static List Read(string[] repoNames, out string[] error } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(repo.Attribute("Name").Value, - thisUri, + thisUrl, Int32.Parse(repo.Attribute("Priority").Value), Boolean.Parse(repo.Attribute("Trusted").Value), thisCredentialInfo); @@ -350,15 +451,50 @@ public static List Read(string[] repoNames, out string[] error bool repoMatch = false; WildcardPattern nameWildCardPattern = new WildcardPattern(repo, WildcardOptions.IgnoreCase); - foreach (var node in doc.Descendants("Repository").Where(e => nameWildCardPattern.IsMatch(e.Attribute("Name").Value))) + foreach (var node in doc.Descendants("Repository").Where(e => e.Attribute("Name") != null && nameWildCardPattern.IsMatch(e.Attribute("Name").Value))) { - repoMatch = true; - if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) + if (node.Attribute("Priority") == null) { - //debug statement - tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", node.Attribute("Name").Value)); + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } + + if (node.Attribute("Trusted") == null) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + repoMatch = true; + bool urlAttributeExists = node.Attribute("Url") != null; + bool uriAttributeExists = node.Attribute("Uri") != null; + + // case: neither Url nor Uri attributes exist + if (!urlAttributeExists && !uriAttributeExists) + { + tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Url' or equivalent 'Uri' attribute (it must contain one), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); + continue; + } + + Uri thisUrl = null; + // case: either attribute Uri or Url exists + // TODO: do we only allow both to exist, across repositories? (i.e if a file has Uri attribute for one repo and Url attribute for another --> is that invalid?) + if (urlAttributeExists) + { + if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) + { + tempErrorList.Add(String.Format("Unable to read incorrectly formatted Url for repo {0}", node.Attribute("Name").Value)); + continue; + } + } + else if (uriAttributeExists) + { + if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) + { + tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", node.Attribute("Name").Value)); + continue; + } + } PSCredentialInfo thisCredentialInfo; string credentialInfoErrorMessage = $"Repository {node.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; @@ -393,7 +529,7 @@ public static List Read(string[] repoNames, out string[] error } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(node.Attribute("Name").Value, - thisUri, + thisUrl, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); @@ -421,7 +557,8 @@ public static List Read(string[] repoNames, out string[] error private static XElement FindRepositoryElement(XDocument doc, string name) { return doc.Descendants("Repository").Where( - e => string.Equals( + e => e.Attribute("Name") != null && + string.Equals( e.Attribute("Name").Value, name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); From 108018bd8c5262d29a6b22c7946ec5fed32967e8 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 26 May 2022 15:13:21 -0700 Subject: [PATCH 161/276] Update changelog, release notes for version 3.0.14-beta14 (#663) --- .ci/ci_release.yml | 2 +- CHANGELOG.md | 5 +++++ src/PowerShellGet.psd1 | 7 ++++++- src/code/PowerShellGet.csproj | 6 +++--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 6aee46f35..8f1a739df 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -244,7 +244,7 @@ stages: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' PackageName: 'PowerShellGet' - PackageVersion: '3.0.13' + PackageVersion: '3.0.14' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' diff --git a/CHANGELOG.md b/CHANGELOG.md index 971f48232..99ff88819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 3.0.14-beta14 + +### Bug Fixes +- Bug fix for repository store (#661) + ## 3.0.13-beta ### New Features diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 5e016df9f..b1ada654d 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.13' + ModuleVersion = '3.0.14' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -40,6 +40,11 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 3.0.14-beta14 + +### Bug Fixes +- Bug fix for repository store (#661) + ## 3.0.13-beta ### New Features diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 83ff3a8f3..6d580abac 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.13.0 - 3.0.13 - 3.0.13 + 3.0.14.0 + 3.0.14 + 3.0.14 netstandard2.0 8.0 From 98c08e63d142779f4aa392def7ae958b0c480dc0 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 26 May 2022 16:24:42 -0700 Subject: [PATCH 162/276] Update prerelease tag to 'beta14' --- src/PowerShellGet.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index b1ada654d..4029ab2bf 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -30,7 +30,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta' + Prerelease = 'beta14' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', From 8d0db7fbc27100026ec0fcc79737272b9a3f882c Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:51:09 -0700 Subject: [PATCH 163/276] Add authenticode validation to Install-PSResource (#632) --- src/code/InstallHelper.cs | 1801 +++++++++++++++--------------- src/code/InstallPSResource.cs | 9 +- src/code/SavePSResource.cs | 8 + src/code/UpdatePSResource.cs | 8 + src/code/Utils.cs | 116 +- test/InstallPSResource.Tests.ps1 | 53 +- test/SavePSResource.Tests.ps1 | 56 + test/UpdatePSResource.Tests.ps1 | 52 +- 8 files changed, 1202 insertions(+), 901 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 2d758216a..17e9e7583 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -1,898 +1,907 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.PowerShell.PowerShellGet.UtilClasses; -using MoreLinq.Extensions; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging; -using NuGet.Packaging.Core; -using NuGet.Packaging.PackageExtraction; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Net; -using System.Text.RegularExpressions; -using System.Threading; - -namespace Microsoft.PowerShell.PowerShellGet.Cmdlets -{ - /// - /// Install helper class - /// - internal class InstallHelper : PSCmdlet +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.Commands; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using MoreLinq.Extensions; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.Packaging.PackageExtraction; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Install helper class + /// + internal class InstallHelper : PSCmdlet { - #region Members - + #region Members + public const string PSDataFileExt = ".psd1"; - public const string PSScriptFileExt = ".ps1"; - private const string MsgRepositoryNotTrusted = "Untrusted repository"; - private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; - - private CancellationToken _cancellationToken; - private readonly PSCmdlet _cmdletPassedIn; - private List _pathsToInstallPkg; - private VersionRange _versionRange; - private bool _prerelease; - private bool _acceptLicense; - private bool _quiet; - private bool _reinstall; - private bool _force; - private bool _trustRepository; - private PSCredential _credential; - private bool _asNupkg; - private bool _includeXML; - private bool _noClobber; - private bool _savePkg; - List _pathsToSearch; - List _pkgNamesToInstall; - - #endregion - - #region Public methods - - public InstallHelper(PSCmdlet cmdletPassedIn) - { - CancellationTokenSource source = new CancellationTokenSource(); - _cancellationToken = source.Token; - _cmdletPassedIn = cmdletPassedIn; - } - - public List InstallPackages( - string[] names, - VersionRange versionRange, - bool prerelease, - string[] repository, - bool acceptLicense, - bool quiet, - bool reinstall, - bool force, - bool trustRepository, - bool noClobber, - PSCredential credential, - bool asNupkg, - bool includeXML, - bool skipDependencyCheck, - bool savePkg, - List pathsToInstallPkg) - { - _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXML '{10}'; SavePackage '{11}'", - string.Join(",", names), - versionRange != null ? (versionRange.OriginalString != null ? versionRange.OriginalString : string.Empty) : string.Empty, - prerelease.ToString(), - repository != null ? string.Join(",", repository) : string.Empty, - acceptLicense.ToString(), - quiet.ToString(), - reinstall.ToString(), - trustRepository.ToString(), - noClobber.ToString(), - asNupkg.ToString(), - includeXML.ToString(), - savePkg.ToString())); - - _versionRange = versionRange; - _prerelease = prerelease; - _acceptLicense = acceptLicense || force; - _quiet = quiet; - _reinstall = reinstall; - _force = force; - _trustRepository = trustRepository || force; - _noClobber = noClobber; - _credential = credential; - _asNupkg = asNupkg; - _includeXML = includeXML; - _savePkg = savePkg; - _pathsToInstallPkg = pathsToInstallPkg; - - // Create list of installation paths to search. - _pathsToSearch = new List(); - _pkgNamesToInstall = names.ToList(); - - // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) - // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations - // e.g.: - // ./InstallPackagePath1/PackageA - // ./InstallPackagePath1/PackageB - // ./InstallPackagePath2/PackageC - // ./InstallPackagePath3/PackageD - foreach (var path in _pathsToInstallPkg) - { - _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); - } - - // Go through the repositories and see which is the first repository to have the pkg version available - return ProcessRepositories( - repository: repository, - trustRepository: _trustRepository, - credential: _credential, - skipDependencyCheck: skipDependencyCheck); - } - - #endregion - - #region Private methods - - // This method calls iterates through repositories (by priority order) to search for the pkgs to install - private List ProcessRepositories( - string[] repository, - bool trustRepository, - PSCredential credential, - bool skipDependencyCheck) - { - var listOfRepositories = RepositorySettings.Read(repository, out string[] _); - var yesToAll = false; - var noToAll = false; - - var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); - List allPkgsInstalled = new List(); - - foreach (var repo in listOfRepositories) - { - // If no more packages to install, then return - if (!_pkgNamesToInstall.Any()) return allPkgsInstalled; - - string repoName = repo.Name; - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); - - // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true - // OR the user issues trust interactively via console. - var sourceTrusted = true; - if (repo.Trusted == false && !trustRepository && !_force) - { - _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); - - if (!(yesToAll || noToAll)) - { - // Prompt for installation of package from untrusted repository - var message = string.Format(CultureInfo.InvariantCulture, MsgInstallUntrustedPackage, repoName); - sourceTrusted = _cmdletPassedIn.ShouldContinue(message, MsgRepositoryNotTrusted, true, ref yesToAll, ref noToAll); - } - } - - if (!sourceTrusted && !yesToAll) - { - continue; - } - - _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); - - // If it can't find the pkg in one repository, it'll look for it in the next repo in the list - var isLocalRepo = repo.Uri.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); - - // Finds parent packages and dependencies - IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( - name: _pkgNamesToInstall.ToArray(), - type: ResourceType.None, - version: _versionRange != null ? _versionRange.OriginalString : null, - prerelease: _prerelease, - tag: null, - repository: new string[] { repoName }, - credential: credential, - includeDependencies: !skipDependencyCheck); - - if (!pkgsFromRepoToInstall.Any()) - { - _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); - // Check in the next repository - continue; - } - - // Select the first package from each name group, which is guaranteed to be the latest version. - // We should only have one version returned for each package name - // e.g.: - // PackageA (version 1.0) - // PackageB (version 2.0) - // PackageC (version 1.0) - pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( - m => new { m.Name }).Select( - group => group.First()).ToList(); - - // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) - if (!_reinstall) - { - pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); - } - - if (!pkgsFromRepoToInstall.Any()) - { - continue; - } - - List pkgsInstalled = InstallPackage( - pkgsFromRepoToInstall, - repoName, - repo.Uri.AbsoluteUri, - repo.CredentialInfo, - credential, - isLocalRepo); - - foreach (PSResourceInfo pkg in pkgsInstalled) - { - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); - } - - allPkgsInstalled.AddRange(pkgsInstalled); - } - - // At this only package names left were those which could not be found in registered repositories - foreach (string pkgName in _pkgNamesToInstall) - { - var message = String.Format("Package '{0}' with requested version range {1} could not be installed as it was not found in any registered repositories", - pkgName, - _versionRange.ToString()); - var ex = new ArgumentException(message); - var ResourceNotFoundError = new ErrorRecord(ex, "ResourceNotFoundError", ErrorCategory.ObjectNotFound, null); - _cmdletPassedIn.WriteError(ResourceNotFoundError); - } - - return allPkgsInstalled; - } - - // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install - private IEnumerable FilterByInstalledPkgs(IEnumerable packages) - { - // Create list of installation paths to search. - List _pathsToSearch = new List(); - // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) - // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations - // e.g.: - // ./InstallPackagePath1/PackageA - // ./InstallPackagePath1/PackageB - // ./InstallPackagePath2/PackageC - // ./InstallPackagePath3/PackageD - foreach (var path in _pathsToInstallPkg) - { - _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); - } - - var filteredPackages = new Dictionary(); - foreach (var pkg in packages) - { - filteredPackages.Add(pkg.Name, pkg); - } - - GetHelper getHelper = new GetHelper(_cmdletPassedIn); - // Get currently installed packages. - // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, never select prerelease only. - IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( - name: filteredPackages.Keys.ToArray(), - versionRange: _versionRange, - pathsToSearch: _pathsToSearch, - selectPrereleaseOnly: false); - if (!pkgsAlreadyInstalled.Any()) - { - return packages; - } - - // Remove from list package versions that are already installed. - foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) - { - _cmdletPassedIn.WriteWarning( - string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", - pkg.Name, - pkg.Version)); - - filteredPackages.Remove(pkg.Name); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); - } - - return filteredPackages.Values.ToArray(); - } - - private List InstallPackage( - IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) - string repoName, - string repoUri, - PSCredentialInfo repoCredentialInfo, - PSCredential credential, - bool isLocalRepo) - { - List pkgsSuccessfullyInstalled = new List(); - int totalPkgs = pkgsToInstall.Count(); - - // Counters for tracking current package out of total - int totalInstalledPkgCount = 0; - foreach (PSResourceInfo pkg in pkgsToInstall) - { - totalInstalledPkgCount++; - var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - try - { - // Create a temp directory to install to - var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly - // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator - // with a mask (bitwise complement of desired attributes combination). - // TODO: check the attributes and if it's read only then set it - // attribute may be inherited from the parent - // TODO: are there Linux accommodations we need to consider here? - dir.Attributes &= ~FileAttributes.ReadOnly; - - _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkg.Name)); - - if (!_quiet) - { - int activityId = 0; - int percentComplete = ((totalInstalledPkgCount * 100) / totalPkgs); - string activity = string.Format("Installing {0}...", pkg.Name); - string statusDescription = string.Format("{0}% Complete", percentComplete); - _cmdletPassedIn.WriteProgress( - new ProgressRecord(activityId, activity, statusDescription)); - } - - // Create PackageIdentity in order to download - string createFullVersion = pkg.Version.ToString(); - if (pkg.IsPrerelease) - { - createFullVersion = pkg.Version.ToString() + "-" + pkg.Prerelease; - } - - if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) - { - var message = String.Format("{0} package could not be installed with error: could not parse package '{0}' version '{1} into a NuGetVersion", - pkg.Name, - pkg.Version.ToString()); - var ex = new ArgumentException(message); - var packageIdentityVersionParseError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); - _cmdletPassedIn.WriteError(packageIdentityVersionParseError); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); - continue; - } - - var pkgIdentity = new PackageIdentity(pkg.Name, pkgVersion); - var cacheContext = new SourceCacheContext(); - - if (isLocalRepo) - { - /* Download from a local repository -- this is slightly different process than from a server */ - var localResource = new FindLocalPackagesResourceV2(repoUri); - var resource = new LocalDownloadResource(repoUri, localResource); - - // Actually downloading the .nupkg from a local repo - var result = resource.GetDownloadResourceResultAsync( - identity: pkgIdentity, - downloadContext: new PackageDownloadContext(cacheContext), - globalPackagesFolder: tempInstallPath, - logger: NullLogger.Instance, - token: _cancellationToken).GetAwaiter().GetResult(); - - // Create the package extraction context - PackageExtractionContext packageExtractionContext = new PackageExtractionContext( - packageSaveMode: PackageSaveMode.Nupkg, - xmlDocFileSaveMode: PackageExtractionBehavior.XmlDocFileSaveMode, - clientPolicyContext: null, - logger: NullLogger.Instance); - - // Extracting from .nupkg and placing files into tempInstallPath - result.PackageReader.CopyFiles( - destination: tempInstallPath, - packageFiles: result.PackageReader.GetFiles(), - extractFile: new PackageFileExtractor( - result.PackageReader.GetFiles(), - packageExtractionContext.XmlDocFileSaveMode).ExtractPackageFile, - logger: NullLogger.Instance, - token: _cancellationToken); - result.Dispose(); - } - else - { - /* Download from a non-local repository */ - // Set up NuGet API resource for download - PackageSource source = new PackageSource(repoUri); - - // Explicitly passed in Credential takes precedence over repository CredentialInfo - if (credential != null) - { - string password = new NetworkCredential(string.Empty, credential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repoUri, credential.UserName, password, true, null); - } - else if (repoCredentialInfo != null) - { - PSCredential repoCredential = Utils.GetRepositoryCredentialFromSecretManagement( - repoName, - repoCredentialInfo, - _cmdletPassedIn); - - string password = new NetworkCredential(string.Empty, repoCredential.Password).Password; - source.Credentials = PackageSourceCredential.FromUserInput(repoUri, repoCredential.UserName, password, true, null); - } - var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); - SourceRepository repository = new SourceRepository(source, provider); - - /* Download from a non-local repository -- ie server */ - var downloadResource = repository.GetResourceAsync().GetAwaiter().GetResult(); - DownloadResourceResult result = null; - try - { - result = downloadResource.GetDownloadResourceResultAsync( - identity: pkgIdentity, - downloadContext: new PackageDownloadContext(cacheContext), - globalPackagesFolder: tempInstallPath, - logger: NullLogger.Instance, - token: _cancellationToken).GetAwaiter().GetResult(); - } - catch (Exception e) - { - _cmdletPassedIn.WriteVerbose(string.Format("Error attempting download: '{0}'", e.Message)); - } - finally - { - // Need to close the .nupkg - if (result != null) result.Dispose(); - } - } - - _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); - - // pkgIdentity.Version.Version gets the version without metadata or release labels. - string newVersion = pkgIdentity.Version.ToNormalizedString(); - string normalizedVersionNoPrerelease = newVersion; - if (pkgIdentity.Version.IsPrerelease) - { - // eg: 2.0.2 - normalizedVersionNoPrerelease = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); - } - - string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); - var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); - string moduleManifestVersion = string.Empty; - var scriptPath = Path.Combine(tempDirNameVersion, pkg.Name + PSScriptFileExt); - var modulePath = Path.Combine(tempDirNameVersion, pkg.Name + PSDataFileExt); - // Check if the package is a module or a script - var isModule = File.Exists(modulePath); - - string installPath; - if (_savePkg) - { - // For save the installation path is what is passed in via -Path - installPath = _pathsToInstallPkg.FirstOrDefault(); - - // If saving as nupkg simply copy the nupkg and move onto next iteration of loop - // asNupkg functionality only applies to Save-PSResource - if (_asNupkg) - { - var nupkgFile = pkgIdentity.ToString().ToLower() + ".nupkg"; - File.Copy(Path.Combine(tempDirNameVersion, nupkgFile), Path.Combine(installPath, nupkgFile)); - - _cmdletPassedIn.WriteVerbose(string.Format("'{0}' moved into file path '{1}'", nupkgFile, installPath)); - pkgsSuccessfullyInstalled.Add(pkg); - - continue; - } - } - else - { - // PSModules: - /// ./Modules - /// ./Scripts - /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list - installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) - : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); - } - - if (isModule) - { - var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + PSDataFileExt); - if (!File.Exists(moduleManifest)) - { - var message = String.Format("{0} package could not be installed with error: Module manifest file: {1} does not exist. This is not a valid PowerShell module.", pkgIdentity.Id, moduleManifest); - - var ex = new ArgumentException(message); - var psdataFileDoesNotExistError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); - _cmdletPassedIn.WriteError(psdataFileDoesNotExistError); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); - continue; - } - - if (!Utils.TryParsePSDataFile(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) - { - // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. - continue; - } - - moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; - - // Accept License verification - if (!_savePkg && !CallAcceptLicense(pkg, moduleManifest, tempInstallPath, newVersion)) - { - continue; - } - - // If NoClobber is specified, ensure command clobbering does not happen - if (_noClobber && !DetectClobber(pkg.Name, parsedMetadataHashtable)) - { - continue; - } - } - - // Delete the extra nupkg related files that are not needed and not part of the module/script - DeleteExtraneousFiles(pkgIdentity, tempDirNameVersion); - - if (_includeXML) - { - CreateMetadataXMLFile(tempDirNameVersion, installPath, pkg, isModule); - } - - MoveFilesIntoInstallPath( - pkg, - isModule, - isLocalRepo, - tempDirNameVersion, - tempInstallPath, - installPath, - newVersion, - moduleManifestVersion, - scriptPath); - - _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkg.Name, installPath)); - pkgsSuccessfullyInstalled.Add(pkg); - } - catch (Exception e) - { - _cmdletPassedIn.WriteError( - new ErrorRecord( - new PSInvalidOperationException( - message: $"Unable to successfully install package '{pkg.Name}': '{e.Message}'", - innerException: e), - "InstallPackageFailed", - ErrorCategory.InvalidOperation, - _cmdletPassedIn)); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); - } - finally - { - // Delete the temp directory and all its contents - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); - - if (Directory.Exists(tempInstallPath)) - { - if (!TryDeleteDirectory(tempInstallPath, out ErrorRecord errorMsg)) - { - _cmdletPassedIn.WriteError(errorMsg); - } - else - { - _cmdletPassedIn.WriteVerbose(String.Format("Successfully deleted '{0}'", tempInstallPath)); - } - } - } - } - - return pkgsSuccessfullyInstalled; - } - - private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string tempInstallPath, string newVersion) - { - var requireLicenseAcceptance = false; - var success = true; - - if (File.Exists(moduleManifest)) - { - using (StreamReader sr = new StreamReader(moduleManifest)) - { - var text = sr.ReadToEnd(); - - var pattern = "RequireLicenseAcceptance\\s*=\\s*\\$true"; - var patternToSkip1 = "#\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; - var patternToSkip2 = "\\*\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; - - Regex rgx = new Regex(pattern); - Regex rgxComment1 = new Regex(patternToSkip1); - Regex rgxComment2 = new Regex(patternToSkip2); - if (rgx.IsMatch(text) && !rgxComment1.IsMatch(text) && !rgxComment2.IsMatch(text)) - { - requireLicenseAcceptance = true; - } - } - - // Licesnse agreement processing - if (requireLicenseAcceptance) - { - // If module requires license acceptance and -AcceptLicense is not passed in, display prompt - if (!_acceptLicense) - { - var PkgTempInstallPath = Path.Combine(tempInstallPath, p.Name, newVersion); - var LicenseFilePath = Path.Combine(PkgTempInstallPath, "License.txt"); - - if (!File.Exists(LicenseFilePath)) - { - var exMessage = String.Format("{0} package could not be installed with error: License.txt not found. License.txt must be provided when user license acceptance is required.", p.Name); - var ex = new ArgumentException(exMessage); - var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); - - _cmdletPassedIn.WriteError(acceptLicenseError); - _pkgNamesToInstall.RemoveAll(x => x.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)); - success = false; - } - - // Otherwise read LicenseFile - string licenseText = System.IO.File.ReadAllText(LicenseFilePath); - var acceptanceLicenseQuery = $"Do you accept the license terms for module '{p.Name}'."; - var message = licenseText + "`r`n" + acceptanceLicenseQuery; - - var title = "License Acceptance"; - var yesToAll = false; - var noToAll = false; - var shouldContinueResult = _cmdletPassedIn.ShouldContinue(message, title, true, ref yesToAll, ref noToAll); - - if (shouldContinueResult || yesToAll) - { - _acceptLicense = true; - } - } - - // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install - if (!_acceptLicense) - { - var message = String.Format("{0} package could not be installed with error: License Acceptance is required for module '{0}'. Please specify '-AcceptLicense' to perform this operation.", p.Name); - var ex = new ArgumentException(message); - var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); - - _cmdletPassedIn.WriteError(acceptLicenseError); - _pkgNamesToInstall.RemoveAll(x => x.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)); - success = false; - } - } - } - - return success; - } - - private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) - { - // Get installed modules, then get all possible paths - bool foundClobber = false; - GetHelper getHelper = new GetHelper(_cmdletPassedIn); - // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, never select prerelease only. - IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( - name: new string[] { "*" }, - versionRange: VersionRange.All, - pathsToSearch: _pathsToSearch, - selectPrereleaseOnly: false); - // user parsed metadata hash - List listOfCmdlets = new List(); - foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) - { - listOfCmdlets.Add(cmdletName as string); - - } - - foreach (var pkg in pkgsAlreadyInstalled) - { - List duplicateCmdlets = new List(); - List duplicateCmds = new List(); - // See if any of the cmdlets or commands in the pkg we're trying to install exist within a package that's already installed - if (pkg.Includes.Cmdlet != null && pkg.Includes.Cmdlet.Any()) - { - duplicateCmdlets = listOfCmdlets.Where(cmdlet => pkg.Includes.Cmdlet.Contains(cmdlet)).ToList(); - - } - - if (pkg.Includes.Command != null && pkg.Includes.Command.Any()) - { - duplicateCmds = listOfCmdlets.Where(commands => pkg.Includes.Command.Contains(commands, StringComparer.InvariantCultureIgnoreCase)).ToList(); - } - - if (duplicateCmdlets.Any() || duplicateCmds.Any()) - { - - duplicateCmdlets.AddRange(duplicateCmds); - - var errMessage = string.Format( - "{1} package could not be installed with error: The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", - String.Join(", ", duplicateCmdlets), pkgName); - - var ex = new ArgumentException(errMessage); - var noClobberError = new ErrorRecord(ex, "CommandAlreadyExists", ErrorCategory.ResourceExists, null); - - _cmdletPassedIn.WriteError(noClobberError); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)); - foundClobber = true; - - return foundClobber; - } - } - - return foundClobber; - } - - private void CreateMetadataXMLFile(string dirNameVersion, string installPath, PSResourceInfo pkg, bool isModule) - { - // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" - // Modules will have the metadata file: "PSGetModuleInfo.xml" - var metadataXMLPath = isModule ? Path.Combine(dirNameVersion, "PSGetModuleInfo.xml") - : Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")); - - pkg.InstalledDate = DateTime.Now; - pkg.InstalledLocation = installPath; - - // Write all metadata into metadataXMLPath - if (!pkg.TryWrite(metadataXMLPath, out string error)) - { - var message = string.Format("{0} package could not be installed with error: Error parsing metadata into XML: '{1}'", pkg.Name, error); - var ex = new ArgumentException(message); - var ErrorParsingMetadata = new ErrorRecord(ex, "ErrorParsingMetadata", ErrorCategory.ParserError, null); - - _cmdletPassedIn.WriteError(ErrorParsingMetadata); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); - } - } - - private void DeleteExtraneousFiles(PackageIdentity pkgIdentity, string dirNameVersion) - { - // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module - var pkgIdString = pkgIdentity.ToString(); - var nupkgSHAToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.sha512"); - var nuspecToDelete = Path.Combine(dirNameVersion, pkgIdentity.Id + ".nuspec"); - var nupkgToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg"); - var nupkgMetadataToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.metadata"); - var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); - var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); - var packageDirToDelete = Path.Combine(dirNameVersion, "package"); - - // Unforunately have to check if each file exists because it may or may not be there - if (File.Exists(nupkgSHAToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgSHAToDelete)); - File.Delete(nupkgSHAToDelete); - } - if (File.Exists(nuspecToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nuspecToDelete)); - File.Delete(nuspecToDelete); - } - if (File.Exists(nupkgToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgToDelete)); - File.Delete(nupkgToDelete); - } - if (File.Exists(nupkgMetadataToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgMetadataToDelete)); - File.Delete(nupkgMetadataToDelete); - } - if (File.Exists(contentTypesToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", contentTypesToDelete)); - File.Delete(contentTypesToDelete); - } - if (Directory.Exists(relsDirToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", relsDirToDelete)); - Utils.DeleteDirectory(relsDirToDelete); - } - if (Directory.Exists(packageDirToDelete)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", packageDirToDelete)); - Utils.DeleteDirectory(packageDirToDelete); - } - } - - private bool TryDeleteDirectory( - string tempInstallPath, - out ErrorRecord errorMsg) - { - errorMsg = null; - - try - { - Utils.DeleteDirectory(tempInstallPath); - } - catch (Exception e) - { - var TempDirCouldNotBeDeletedError = new ErrorRecord(e, "errorDeletingTempInstallPath", ErrorCategory.InvalidResult, null); - errorMsg = TempDirCouldNotBeDeletedError; - return false; - } - - return true; - } - - private void MoveFilesIntoInstallPath( - PSResourceInfo pkgInfo, - bool isModule, - bool isLocalRepo, - string dirNameVersion, - string tempInstallPath, - string installPath, - string newVersion, - string moduleManifestVersion, - string scriptPath) - { - // Creating the proper installation path depending on whether pkg is a module or script - var newPathParent = isModule ? Path.Combine(installPath, pkgInfo.Name) : installPath; - var finalModuleVersionDir = isModule ? Path.Combine(installPath, pkgInfo.Name, moduleManifestVersion) : installPath; - - // If script, just move the files over, if module, move the version directory over - var tempModuleVersionDir = (!isModule || isLocalRepo) ? dirNameVersion - : Path.Combine(tempInstallPath, pkgInfo.Name.ToLower(), newVersion); - - _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); - _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); - - if (isModule) - { - // If new path does not exist - if (!Directory.Exists(newPathParent)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Directory.CreateDirectory(newPathParent); - Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); - } - else - { - _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); - - if (Directory.Exists(finalModuleVersionDir)) - { - // Delete the directory path before replacing it with the new module. - // If deletion fails (usually due to binary file in use), then attempt restore so that the currently - // installed module is not corrupted. - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete with restore on failure.'{0}'", finalModuleVersionDir)); - Utils.DeleteDirectoryWithRestore(finalModuleVersionDir); - } - - _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); - Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); - } - } - else - { - if (!_savePkg) - { - // Need to delete old xml files because there can only be 1 per script - var scriptXML = pkgInfo.Name + "_InstalledScriptInfo.xml"; - _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); - if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting script metadata XML")); - File.Delete(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); - } - - _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); - Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); - - // Need to delete old script file, if that exists - _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)))); - if (File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt))) - { - _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); - File.Delete(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)); - } - } - - _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt))); - Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)); - } - } - - #endregion - } -} + public const string PSScriptFileExt = ".ps1"; + private const string MsgRepositoryNotTrusted = "Untrusted repository"; + private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; + private CancellationToken _cancellationToken; + private readonly PSCmdlet _cmdletPassedIn; + private List _pathsToInstallPkg; + private VersionRange _versionRange; + private bool _prerelease; + private bool _acceptLicense; + private bool _quiet; + private bool _reinstall; + private bool _force; + private bool _trustRepository; + private PSCredential _credential; + private bool _asNupkg; + private bool _includeXML; + private bool _noClobber; + private bool _authenticodeCheck; + private bool _savePkg; + List _pathsToSearch; + List _pkgNamesToInstall; + + #endregion + + #region Public methods + + public InstallHelper(PSCmdlet cmdletPassedIn) + { + CancellationTokenSource source = new CancellationTokenSource(); + _cancellationToken = source.Token; + _cmdletPassedIn = cmdletPassedIn; + } + + public List InstallPackages( + string[] names, + VersionRange versionRange, + bool prerelease, + string[] repository, + bool acceptLicense, + bool quiet, + bool reinstall, + bool force, + bool trustRepository, + bool noClobber, + PSCredential credential, + bool asNupkg, + bool includeXML, + bool skipDependencyCheck, + bool authenticodeCheck, + bool savePkg, + List pathsToInstallPkg) + { + _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXML '{10}'; SavePackage '{11}'", + string.Join(",", names), + versionRange != null ? (versionRange.OriginalString != null ? versionRange.OriginalString : string.Empty) : string.Empty, + prerelease.ToString(), + repository != null ? string.Join(",", repository) : string.Empty, + acceptLicense.ToString(), + quiet.ToString(), + reinstall.ToString(), + trustRepository.ToString(), + noClobber.ToString(), + asNupkg.ToString(), + includeXML.ToString(), + savePkg.ToString())); + + _versionRange = versionRange; + _prerelease = prerelease; + _acceptLicense = acceptLicense || force; + _authenticodeCheck = authenticodeCheck; + _quiet = quiet; + _reinstall = reinstall; + _force = force; + _trustRepository = trustRepository || force; + _noClobber = noClobber; + _credential = credential; + _asNupkg = asNupkg; + _includeXML = includeXML; + _savePkg = savePkg; + _pathsToInstallPkg = pathsToInstallPkg; + + // Create list of installation paths to search. + _pathsToSearch = new List(); + _pkgNamesToInstall = names.ToList(); + + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // e.g.: + // ./InstallPackagePath1/PackageA + // ./InstallPackagePath1/PackageB + // ./InstallPackagePath2/PackageC + // ./InstallPackagePath3/PackageD + foreach (var path in _pathsToInstallPkg) + { + _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); + } + + // Go through the repositories and see which is the first repository to have the pkg version available + return ProcessRepositories( + repository: repository, + trustRepository: _trustRepository, + credential: _credential, + skipDependencyCheck: skipDependencyCheck); + } + + #endregion + + #region Private methods + + // This method calls iterates through repositories (by priority order) to search for the pkgs to install + private List ProcessRepositories( + string[] repository, + bool trustRepository, + PSCredential credential, + bool skipDependencyCheck) + { + var listOfRepositories = RepositorySettings.Read(repository, out string[] _); + var yesToAll = false; + var noToAll = false; + + var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); + List allPkgsInstalled = new List(); + + foreach (var repo in listOfRepositories) + { + // If no more packages to install, then return + if (!_pkgNamesToInstall.Any()) return allPkgsInstalled; + + string repoName = repo.Name; + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to search for packages in '{0}'", repoName)); + + // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true + // OR the user issues trust interactively via console. + var sourceTrusted = true; + if (repo.Trusted == false && !trustRepository && !_force) + { + _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); + + if (!(yesToAll || noToAll)) + { + // Prompt for installation of package from untrusted repository + var message = string.Format(CultureInfo.InvariantCulture, MsgInstallUntrustedPackage, repoName); + sourceTrusted = _cmdletPassedIn.ShouldContinue(message, MsgRepositoryNotTrusted, true, ref yesToAll, ref noToAll); + } + } + + if (!sourceTrusted && !yesToAll) + { + continue; + } + + _cmdletPassedIn.WriteVerbose("Untrusted repository accepted as trusted source."); + + // If it can't find the pkg in one repository, it'll look for it in the next repo in the list + var isLocalRepo = repo.Uri.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); + + // Finds parent packages and dependencies + IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( + name: _pkgNamesToInstall.ToArray(), + type: ResourceType.None, + version: _versionRange != null ? _versionRange.OriginalString : null, + prerelease: _prerelease, + tag: null, + repository: new string[] { repoName }, + credential: credential, + includeDependencies: !skipDependencyCheck); + + if (!pkgsFromRepoToInstall.Any()) + { + _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); + // Check in the next repository + continue; + } + + // Select the first package from each name group, which is guaranteed to be the latest version. + // We should only have one version returned for each package name + // e.g.: + // PackageA (version 1.0) + // PackageB (version 2.0) + // PackageC (version 1.0) + pkgsFromRepoToInstall = pkgsFromRepoToInstall.GroupBy( + m => new { m.Name }).Select( + group => group.First()).ToList(); + + // Check to see if the pkgs (including dependencies) are already installed (ie the pkg is installed and the version satisfies the version range provided via param) + if (!_reinstall) + { + pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); + } + + if (!pkgsFromRepoToInstall.Any()) + { + continue; + } + + List pkgsInstalled = InstallPackage( + pkgsFromRepoToInstall, + repoName, + repo.Uri.AbsoluteUri, + repo.CredentialInfo, + credential, + isLocalRepo); + + foreach (PSResourceInfo pkg in pkgsInstalled) + { + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + } + + allPkgsInstalled.AddRange(pkgsInstalled); + } + + // At this only package names left were those which could not be found in registered repositories + foreach (string pkgName in _pkgNamesToInstall) + { + var message = String.Format("Package '{0}' with requested version range {1} could not be installed as it was not found in any registered repositories", + pkgName, + _versionRange.ToString()); + var ex = new ArgumentException(message); + var ResourceNotFoundError = new ErrorRecord(ex, "ResourceNotFoundError", ErrorCategory.ObjectNotFound, null); + _cmdletPassedIn.WriteError(ResourceNotFoundError); + } + + return allPkgsInstalled; + } + + // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install + private IEnumerable FilterByInstalledPkgs(IEnumerable packages) + { + // Create list of installation paths to search. + List _pathsToSearch = new List(); + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // e.g.: + // ./InstallPackagePath1/PackageA + // ./InstallPackagePath1/PackageB + // ./InstallPackagePath2/PackageC + // ./InstallPackagePath3/PackageD + foreach (var path in _pathsToInstallPkg) + { + _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); + } + + var filteredPackages = new Dictionary(); + foreach (var pkg in packages) + { + filteredPackages.Add(pkg.Name, pkg); + } + + GetHelper getHelper = new GetHelper(_cmdletPassedIn); + // Get currently installed packages. + // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, never select prerelease only. + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( + name: filteredPackages.Keys.ToArray(), + versionRange: _versionRange, + pathsToSearch: _pathsToSearch, + selectPrereleaseOnly: false); + if (!pkgsAlreadyInstalled.Any()) + { + return packages; + } + + // Remove from list package versions that are already installed. + foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) + { + _cmdletPassedIn.WriteWarning( + string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", + pkg.Name, + pkg.Version)); + + filteredPackages.Remove(pkg.Name); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + } + + return filteredPackages.Values.ToArray(); + } + + private List InstallPackage( + IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) + string repoName, + string repoUri, + PSCredentialInfo repoCredentialInfo, + PSCredential credential, + bool isLocalRepo) + { + List pkgsSuccessfullyInstalled = new List(); + int totalPkgs = pkgsToInstall.Count(); + + // Counters for tracking current package out of total + int totalInstalledPkgCount = 0; + foreach (PSResourceInfo pkg in pkgsToInstall) + { + totalInstalledPkgCount++; + var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + try + { + // Create a temp directory to install to + var dir = Directory.CreateDirectory(tempInstallPath); // should check it gets created properly + // To delete file attributes from the existing ones get the current file attributes first and use AND (&) operator + // with a mask (bitwise complement of desired attributes combination). + // TODO: check the attributes and if it's read only then set it + // attribute may be inherited from the parent + // TODO: are there Linux accommodations we need to consider here? + dir.Attributes &= ~FileAttributes.ReadOnly; + + _cmdletPassedIn.WriteVerbose(string.Format("Begin installing package: '{0}'", pkg.Name)); + + if (!_quiet) + { + int activityId = 0; + int percentComplete = ((totalInstalledPkgCount * 100) / totalPkgs); + string activity = string.Format("Installing {0}...", pkg.Name); + string statusDescription = string.Format("{0}% Complete", percentComplete); + _cmdletPassedIn.WriteProgress( + new ProgressRecord(activityId, activity, statusDescription)); + } + + // Create PackageIdentity in order to download + string createFullVersion = pkg.Version.ToString(); + if (pkg.IsPrerelease) + { + createFullVersion = pkg.Version.ToString() + "-" + pkg.Prerelease; + } + + if (!NuGetVersion.TryParse(createFullVersion, out NuGetVersion pkgVersion)) + { + var message = String.Format("{0} package could not be installed with error: could not parse package '{0}' version '{1} into a NuGetVersion", + pkg.Name, + pkg.Version.ToString()); + var ex = new ArgumentException(message); + var packageIdentityVersionParseError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); + _cmdletPassedIn.WriteError(packageIdentityVersionParseError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + continue; + } + + var pkgIdentity = new PackageIdentity(pkg.Name, pkgVersion); + var cacheContext = new SourceCacheContext(); + + if (isLocalRepo) + { + /* Download from a local repository -- this is slightly different process than from a server */ + var localResource = new FindLocalPackagesResourceV2(repoUri); + var resource = new LocalDownloadResource(repoUri, localResource); + + // Actually downloading the .nupkg from a local repo + var result = resource.GetDownloadResourceResultAsync( + identity: pkgIdentity, + downloadContext: new PackageDownloadContext(cacheContext), + globalPackagesFolder: tempInstallPath, + logger: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + + // Create the package extraction context + PackageExtractionContext packageExtractionContext = new PackageExtractionContext( + packageSaveMode: PackageSaveMode.Nupkg, + xmlDocFileSaveMode: PackageExtractionBehavior.XmlDocFileSaveMode, + clientPolicyContext: null, + logger: NullLogger.Instance); + + // Extracting from .nupkg and placing files into tempInstallPath + result.PackageReader.CopyFiles( + destination: tempInstallPath, + packageFiles: result.PackageReader.GetFiles(), + extractFile: new PackageFileExtractor( + result.PackageReader.GetFiles(), + packageExtractionContext.XmlDocFileSaveMode).ExtractPackageFile, + logger: NullLogger.Instance, + token: _cancellationToken); + result.Dispose(); + } + else + { + /* Download from a non-local repository */ + // Set up NuGet API resource for download + PackageSource source = new PackageSource(repoUri); + + // Explicitly passed in Credential takes precedence over repository CredentialInfo + if (credential != null) + { + string password = new NetworkCredential(string.Empty, credential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repoUri, credential.UserName, password, true, null); + } + else if (repoCredentialInfo != null) + { + PSCredential repoCredential = Utils.GetRepositoryCredentialFromSecretManagement( + repoName, + repoCredentialInfo, + _cmdletPassedIn); + + string password = new NetworkCredential(string.Empty, repoCredential.Password).Password; + source.Credentials = PackageSourceCredential.FromUserInput(repoUri, repoCredential.UserName, password, true, null); + } + var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); + SourceRepository repository = new SourceRepository(source, provider); + + /* Download from a non-local repository -- ie server */ + var downloadResource = repository.GetResourceAsync().GetAwaiter().GetResult(); + DownloadResourceResult result = null; + try + { + result = downloadResource.GetDownloadResourceResultAsync( + identity: pkgIdentity, + downloadContext: new PackageDownloadContext(cacheContext), + globalPackagesFolder: tempInstallPath, + logger: NullLogger.Instance, + token: _cancellationToken).GetAwaiter().GetResult(); + } + catch (Exception e) + { + _cmdletPassedIn.WriteVerbose(string.Format("Error attempting download: '{0}'", e.Message)); + } + finally + { + // Need to close the .nupkg + if (result != null) result.Dispose(); + } + } + + _cmdletPassedIn.WriteVerbose(string.Format("Successfully able to download package from source to: '{0}'", tempInstallPath)); + + // pkgIdentity.Version.Version gets the version without metadata or release labels. + string newVersion = pkgIdentity.Version.ToNormalizedString(); + string normalizedVersionNoPrerelease = newVersion; + if (pkgIdentity.Version.IsPrerelease) + { + // eg: 2.0.2 + normalizedVersionNoPrerelease = pkgIdentity.Version.ToNormalizedString().Substring(0, pkgIdentity.Version.ToNormalizedString().IndexOf('-')); + } + + string tempDirNameVersion = isLocalRepo ? tempInstallPath : Path.Combine(tempInstallPath, pkgIdentity.Id.ToLower(), newVersion); + var version4digitNoPrerelease = pkgIdentity.Version.Version.ToString(); + string moduleManifestVersion = string.Empty; + var scriptPath = Path.Combine(tempDirNameVersion, pkg.Name + PSScriptFileExt); + var modulePath = Path.Combine(tempDirNameVersion, pkg.Name + PSDataFileExt); + // Check if the package is a module or a script + var isModule = File.Exists(modulePath); + + string installPath; + if (_savePkg) + { + // For save the installation path is what is passed in via -Path + installPath = _pathsToInstallPkg.FirstOrDefault(); + + // If saving as nupkg simply copy the nupkg and move onto next iteration of loop + // asNupkg functionality only applies to Save-PSResource + if (_asNupkg) + { + var nupkgFile = pkgIdentity.ToString().ToLower() + ".nupkg"; + File.Copy(Path.Combine(tempDirNameVersion, nupkgFile), Path.Combine(installPath, nupkgFile)); + + _cmdletPassedIn.WriteVerbose(string.Format("'{0}' moved into file path '{1}'", nupkgFile, installPath)); + pkgsSuccessfullyInstalled.Add(pkg); + + continue; + } + } + else + { + // PSModules: + /// ./Modules + /// ./Scripts + /// _pathsToInstallPkg is sorted by desirability, Find will pick the pick the first Script or Modules path found in the list + installPath = isModule ? _pathsToInstallPkg.Find(path => path.EndsWith("Modules", StringComparison.InvariantCultureIgnoreCase)) + : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); + } + + if (_authenticodeCheck && !AuthenticodeSignature.CheckAuthenticodeSignature(pkg.Name, tempDirNameVersion, _versionRange, _pathsToSearch, installPath, _cmdletPassedIn, out ErrorRecord errorRecord)) + { + ThrowTerminatingError(errorRecord); + } + + if (isModule) + { + var moduleManifest = Path.Combine(tempDirNameVersion, pkgIdentity.Id + PSDataFileExt); + if (!File.Exists(moduleManifest)) + { + var message = String.Format("{0} package could not be installed with error: Module manifest file: {1} does not exist. This is not a valid PowerShell module.", pkgIdentity.Id, moduleManifest); + + var ex = new ArgumentException(message); + var psdataFileDoesNotExistError = new ErrorRecord(ex, "psdataFileNotExistError", ErrorCategory.ReadError, null); + _cmdletPassedIn.WriteError(psdataFileDoesNotExistError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + continue; + } + + if (!Utils.TryParsePSDataFile(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) + { + // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. + continue; + } + + moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; + + // Accept License verification + if (!_savePkg && !CallAcceptLicense(pkg, moduleManifest, tempInstallPath, newVersion)) + { + continue; + } + + // If NoClobber is specified, ensure command clobbering does not happen + if (_noClobber && !DetectClobber(pkg.Name, parsedMetadataHashtable)) + { + continue; + } + } + + // Delete the extra nupkg related files that are not needed and not part of the module/script + DeleteExtraneousFiles(pkgIdentity, tempDirNameVersion); + + if (_includeXML) + { + CreateMetadataXMLFile(tempDirNameVersion, installPath, pkg, isModule); + } + + MoveFilesIntoInstallPath( + pkg, + isModule, + isLocalRepo, + tempDirNameVersion, + tempInstallPath, + installPath, + newVersion, + moduleManifestVersion, + scriptPath); + + _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkg.Name, installPath)); + pkgsSuccessfullyInstalled.Add(pkg); + } + catch (Exception e) + { + _cmdletPassedIn.WriteError( + new ErrorRecord( + new PSInvalidOperationException( + message: $"Unable to successfully install package '{pkg.Name}': '{e.Message}'", + innerException: e), + "InstallPackageFailed", + ErrorCategory.InvalidOperation, + _cmdletPassedIn)); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + } + finally + { + // Delete the temp directory and all its contents + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete '{0}'", tempInstallPath)); + + if (Directory.Exists(tempInstallPath)) + { + if (!TryDeleteDirectory(tempInstallPath, out ErrorRecord errorMsg)) + { + _cmdletPassedIn.WriteError(errorMsg); + } + else + { + _cmdletPassedIn.WriteVerbose(String.Format("Successfully deleted '{0}'", tempInstallPath)); + } + } + } + } + + return pkgsSuccessfullyInstalled; + } + + private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string tempInstallPath, string newVersion) + { + var requireLicenseAcceptance = false; + var success = true; + + if (File.Exists(moduleManifest)) + { + using (StreamReader sr = new StreamReader(moduleManifest)) + { + var text = sr.ReadToEnd(); + + var pattern = "RequireLicenseAcceptance\\s*=\\s*\\$true"; + var patternToSkip1 = "#\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; + var patternToSkip2 = "\\*\\s*RequireLicenseAcceptance\\s*=\\s*\\$true"; + + Regex rgx = new Regex(pattern); + Regex rgxComment1 = new Regex(patternToSkip1); + Regex rgxComment2 = new Regex(patternToSkip2); + if (rgx.IsMatch(text) && !rgxComment1.IsMatch(text) && !rgxComment2.IsMatch(text)) + { + requireLicenseAcceptance = true; + } + } + + // Licesnse agreement processing + if (requireLicenseAcceptance) + { + // If module requires license acceptance and -AcceptLicense is not passed in, display prompt + if (!_acceptLicense) + { + var PkgTempInstallPath = Path.Combine(tempInstallPath, p.Name, newVersion); + var LicenseFilePath = Path.Combine(PkgTempInstallPath, "License.txt"); + + if (!File.Exists(LicenseFilePath)) + { + var exMessage = String.Format("{0} package could not be installed with error: License.txt not found. License.txt must be provided when user license acceptance is required.", p.Name); + var ex = new ArgumentException(exMessage); + var acceptLicenseError = new ErrorRecord(ex, "LicenseTxtNotFound", ErrorCategory.ObjectNotFound, null); + + _cmdletPassedIn.WriteError(acceptLicenseError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)); + success = false; + } + + // Otherwise read LicenseFile + string licenseText = System.IO.File.ReadAllText(LicenseFilePath); + var acceptanceLicenseQuery = $"Do you accept the license terms for module '{p.Name}'."; + var message = licenseText + "`r`n" + acceptanceLicenseQuery; + + var title = "License Acceptance"; + var yesToAll = false; + var noToAll = false; + var shouldContinueResult = _cmdletPassedIn.ShouldContinue(message, title, true, ref yesToAll, ref noToAll); + + if (shouldContinueResult || yesToAll) + { + _acceptLicense = true; + } + } + + // Check if user agreed to license terms, if they didn't then throw error, otherwise continue to install + if (!_acceptLicense) + { + var message = String.Format("{0} package could not be installed with error: License Acceptance is required for module '{0}'. Please specify '-AcceptLicense' to perform this operation.", p.Name); + var ex = new ArgumentException(message); + var acceptLicenseError = new ErrorRecord(ex, "ForceAcceptLicense", ErrorCategory.InvalidArgument, null); + + _cmdletPassedIn.WriteError(acceptLicenseError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)); + success = false; + } + } + } + + return success; + } + + private bool DetectClobber(string pkgName, Hashtable parsedMetadataHashtable) + { + // Get installed modules, then get all possible paths + bool foundClobber = false; + GetHelper getHelper = new GetHelper(_cmdletPassedIn); + // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, never select prerelease only. + IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( + name: new string[] { "*" }, + versionRange: VersionRange.All, + pathsToSearch: _pathsToSearch, + selectPrereleaseOnly: false); + // user parsed metadata hash + List listOfCmdlets = new List(); + foreach (var cmdletName in parsedMetadataHashtable["CmdletsToExport"] as object[]) + { + listOfCmdlets.Add(cmdletName as string); + + } + + foreach (var pkg in pkgsAlreadyInstalled) + { + List duplicateCmdlets = new List(); + List duplicateCmds = new List(); + // See if any of the cmdlets or commands in the pkg we're trying to install exist within a package that's already installed + if (pkg.Includes.Cmdlet != null && pkg.Includes.Cmdlet.Any()) + { + duplicateCmdlets = listOfCmdlets.Where(cmdlet => pkg.Includes.Cmdlet.Contains(cmdlet)).ToList(); + + } + + if (pkg.Includes.Command != null && pkg.Includes.Command.Any()) + { + duplicateCmds = listOfCmdlets.Where(commands => pkg.Includes.Command.Contains(commands, StringComparer.InvariantCultureIgnoreCase)).ToList(); + } + + if (duplicateCmdlets.Any() || duplicateCmds.Any()) + { + + duplicateCmdlets.AddRange(duplicateCmds); + + var errMessage = string.Format( + "{1} package could not be installed with error: The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter.", + String.Join(", ", duplicateCmdlets), pkgName); + + var ex = new ArgumentException(errMessage); + var noClobberError = new ErrorRecord(ex, "CommandAlreadyExists", ErrorCategory.ResourceExists, null); + + _cmdletPassedIn.WriteError(noClobberError); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkgName, StringComparison.InvariantCultureIgnoreCase)); + foundClobber = true; + + return foundClobber; + } + } + + return foundClobber; + } + + private void CreateMetadataXMLFile(string dirNameVersion, string installPath, PSResourceInfo pkg, bool isModule) + { + // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml" + // Modules will have the metadata file: "PSGetModuleInfo.xml" + var metadataXMLPath = isModule ? Path.Combine(dirNameVersion, "PSGetModuleInfo.xml") + : Path.Combine(dirNameVersion, (pkg.Name + "_InstalledScriptInfo.xml")); + + pkg.InstalledDate = DateTime.Now; + pkg.InstalledLocation = installPath; + + // Write all metadata into metadataXMLPath + if (!pkg.TryWrite(metadataXMLPath, out string error)) + { + var message = string.Format("{0} package could not be installed with error: Error parsing metadata into XML: '{1}'", pkg.Name, error); + var ex = new ArgumentException(message); + var ErrorParsingMetadata = new ErrorRecord(ex, "ErrorParsingMetadata", ErrorCategory.ParserError, null); + + _cmdletPassedIn.WriteError(ErrorParsingMetadata); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + } + } + + private void DeleteExtraneousFiles(PackageIdentity pkgIdentity, string dirNameVersion) + { + // Deleting .nupkg SHA file, .nuspec, and .nupkg after unpacking the module + var pkgIdString = pkgIdentity.ToString(); + var nupkgSHAToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.sha512"); + var nuspecToDelete = Path.Combine(dirNameVersion, pkgIdentity.Id + ".nuspec"); + var nupkgToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg"); + var nupkgMetadataToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.metadata"); + var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); + var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); + var packageDirToDelete = Path.Combine(dirNameVersion, "package"); + + // Unforunately have to check if each file exists because it may or may not be there + if (File.Exists(nupkgSHAToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgSHAToDelete)); + File.Delete(nupkgSHAToDelete); + } + if (File.Exists(nuspecToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nuspecToDelete)); + File.Delete(nuspecToDelete); + } + if (File.Exists(nupkgToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgToDelete)); + File.Delete(nupkgToDelete); + } + if (File.Exists(nupkgMetadataToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", nupkgMetadataToDelete)); + File.Delete(nupkgMetadataToDelete); + } + if (File.Exists(contentTypesToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", contentTypesToDelete)); + File.Delete(contentTypesToDelete); + } + if (Directory.Exists(relsDirToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", relsDirToDelete)); + Utils.DeleteDirectory(relsDirToDelete); + } + if (Directory.Exists(packageDirToDelete)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting '{0}'", packageDirToDelete)); + Utils.DeleteDirectory(packageDirToDelete); + } + } + + private bool TryDeleteDirectory( + string tempInstallPath, + out ErrorRecord errorMsg) + { + errorMsg = null; + + try + { + Utils.DeleteDirectory(tempInstallPath); + } + catch (Exception e) + { + var TempDirCouldNotBeDeletedError = new ErrorRecord(e, "errorDeletingTempInstallPath", ErrorCategory.InvalidResult, null); + errorMsg = TempDirCouldNotBeDeletedError; + return false; + } + + return true; + } + + private void MoveFilesIntoInstallPath( + PSResourceInfo pkgInfo, + bool isModule, + bool isLocalRepo, + string dirNameVersion, + string tempInstallPath, + string installPath, + string newVersion, + string moduleManifestVersion, + string scriptPath) + { + // Creating the proper installation path depending on whether pkg is a module or script + var newPathParent = isModule ? Path.Combine(installPath, pkgInfo.Name) : installPath; + var finalModuleVersionDir = isModule ? Path.Combine(installPath, pkgInfo.Name, moduleManifestVersion) : installPath; + + // If script, just move the files over, if module, move the version directory over + var tempModuleVersionDir = (!isModule || isLocalRepo) ? dirNameVersion + : Path.Combine(tempInstallPath, pkgInfo.Name.ToLower(), newVersion); + + _cmdletPassedIn.WriteVerbose(string.Format("Installation source path is: '{0}'", tempModuleVersionDir)); + _cmdletPassedIn.WriteVerbose(string.Format("Installation destination path is: '{0}'", finalModuleVersionDir)); + + if (isModule) + { + // If new path does not exist + if (!Directory.Exists(newPathParent)) + { + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Directory.CreateDirectory(newPathParent); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); + } + else + { + _cmdletPassedIn.WriteVerbose(string.Format("Temporary module version directory is: '{0}'", tempModuleVersionDir)); + + if (Directory.Exists(finalModuleVersionDir)) + { + // Delete the directory path before replacing it with the new module. + // If deletion fails (usually due to binary file in use), then attempt restore so that the currently + // installed module is not corrupted. + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to delete with restore on failure.'{0}'", finalModuleVersionDir)); + Utils.DeleteDirectoryWithRestore(finalModuleVersionDir); + } + + _cmdletPassedIn.WriteVerbose(string.Format("Attempting to move '{0}' to '{1}'", tempModuleVersionDir, finalModuleVersionDir)); + Utils.MoveDirectory(tempModuleVersionDir, finalModuleVersionDir); + } + } + else + { + if (!_savePkg) + { + // Need to delete old xml files because there can only be 1 per script + var scriptXML = pkgInfo.Name + "_InstalledScriptInfo.xml"; + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)))); + if (File.Exists(Path.Combine(installPath, "InstalledScriptInfos", scriptXML))) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting script metadata XML")); + File.Delete(Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + } + + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML))); + Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, "InstalledScriptInfos", scriptXML)); + + // Need to delete old script file, if that exists + _cmdletPassedIn.WriteVerbose(string.Format("Checking if path '{0}' exists: ", File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)))); + if (File.Exists(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt))) + { + _cmdletPassedIn.WriteVerbose(string.Format("Deleting script file")); + File.Delete(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)); + } + } + + _cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt))); + Utils.MoveFiles(scriptPath, Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt)); + } + } + + #endregion + } +} diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index c08987d26..98c64a346 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -103,6 +103,12 @@ class InstallPSResource : PSCmdlet /// [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } + + /// + /// Check validation for signed and catalog files + /// + [Parameter] + public SwitchParameter AuthenticodeCheck { get; set; } /// /// Passes the resource installed to the console. @@ -310,7 +316,7 @@ protected override void ProcessRecord() { requiredResourceFileStream = sr.ReadToEnd(); } - + Hashtable pkgsInFile = null; try { @@ -513,6 +519,7 @@ private void ProcessInstallHelper(string[] pkgNames, VersionRange pkgVersion, bo asNupkg: false, includeXML: true, skipDependencyCheck: SkipDependencyCheck, + authenticodeCheck: AuthenticodeCheck, savePkg: false, pathsToInstallPkg: _pathsToInstallPkg); diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index a7e17e3ab..73b6d1c19 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -131,6 +131,13 @@ public string Path [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } + /// + /// Check validation for signed and catalog files + + /// + [Parameter] + public SwitchParameter AuthenticodeCheck { get; set; } + /// /// Suppresses progress information. /// @@ -259,6 +266,7 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p asNupkg: AsNupkg, includeXML: IncludeXML, skipDependencyCheck: SkipDependencyCheck, + authenticodeCheck: AuthenticodeCheck, savePkg: true, pathsToInstallPkg: new List { _path }); diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 79e5e7f02..5ca79d529 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -111,6 +111,13 @@ public sealed class UpdatePSResource : PSCmdlet [Parameter] public SwitchParameter SkipDependencyCheck { get; set; } + /// + /// Check validation for signed and catalog files + + /// + [Parameter] + public SwitchParameter AuthenticodeCheck { get; set; } + #endregion #region Override Methods @@ -178,6 +185,7 @@ protected override void ProcessRecord() asNupkg: false, includeXML: true, skipDependencyCheck: SkipDependencyCheck, + authenticodeCheck: AuthenticodeCheck, savePkg: false, pathsToInstallPkg: _pathsToInstallPkg); diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 07c74fc12..9ab09b3ce 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.Win32.SafeHandles; using NuGet.Versioning; using System; using System.Collections; @@ -14,6 +15,7 @@ using System.Management.Automation.Runspaces; using System.Runtime.InteropServices; using System.Security; +using System.Security.Cryptography.X509Certificates; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -1126,7 +1128,117 @@ public static Collection InvokeScriptWithHost( } #endregion Methods - } - + } + + #endregion + + #region AuthenticodeSignature + + internal static class AuthenticodeSignature + { + #region Methods + + internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNameVersion, VersionRange versionRange, List pathsToSearch, string installPath, PSCmdlet cmdletPassedIn, out ErrorRecord errorRecord) + { + errorRecord = null; + + // Because authenticode and catalog verifications are only applicable on Windows, we allow all packages by default to be installed on unix systems. + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return true; + } + + // Check that the catalog file is signed properly + string catalogFilePath = Path.Combine(tempDirNameVersion, pkgName + ".cat"); + if (File.Exists(catalogFilePath)) + { + // Run catalog validation + Collection TestFileCatalogResult = new Collection(); + string moduleBasePath = tempDirNameVersion; + try + { + // By default "Test-FileCatalog will look through all files in the provided directory, -FilesToSkip allows us to ignore specific files + TestFileCatalogResult = cmdletPassedIn.InvokeCommand.InvokeScript( + script: @"param ( + [string] $moduleBasePath, + [string] $catalogFilePath + ) + $catalogValidation = Test-FileCatalog -Path $moduleBasePath -CatalogFilePath $CatalogFilePath ` + -FilesToSkip '*.nupkg','*.nuspec', '*.nupkg.metadata', '*.nupkg.sha512' ` + -Detailed -ErrorAction SilentlyContinue + + if ($catalogValidation.Status.ToString() -eq 'valid' -and $catalogValidation.Signature.Status -eq 'valid') { + return $true + } + else { + return $false + } + ", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { moduleBasePath, catalogFilePath }); + } + catch (Exception e) + { + errorRecord = new ErrorRecord(new ArgumentException(e.Message), "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); + return false; + } + + bool catalogValidation = (TestFileCatalogResult[0] != null) ? (bool)TestFileCatalogResult[0].BaseObject : false; + if (!catalogValidation) + { + var exMessage = String.Format("The catalog file '{0}' is invalid.", pkgName + ".cat"); + var ex = new ArgumentException(exMessage); + + errorRecord = new ErrorRecord(ex, "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); + return false; + } + } + + Collection authenticodeSignature = new Collection(); + try + { + string[] listOfExtensions = { "*.ps1", "*.psd1", "*.psm1", "*.mof", "*.cat", "*.ps1xml" }; + authenticodeSignature = cmdletPassedIn.InvokeCommand.InvokeScript( + script: @"param ( + [string] $tempDirNameVersion, + [string[]] $listOfExtensions + ) + Get-ChildItem $tempDirNameVersion -Recurse -Include $listOfExtensions | Get-AuthenticodeSignature -ErrorAction SilentlyContinue", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { tempDirNameVersion, listOfExtensions }); + } + catch (Exception e) + { + errorRecord = new ErrorRecord(new ArgumentException(e.Message), "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); + return false; + } + + // If the authenticode signature is not valid, return false + if (authenticodeSignature.Any() && authenticodeSignature[0] != null) + { + foreach (var sign in authenticodeSignature) + { + Signature signature = (Signature)sign.BaseObject; + if (!signature.Status.Equals(SignatureStatus.Valid)) + { + var exMessage = String.Format("The signature for '{0}' is '{1}.", pkgName, signature.Status.ToString()); + var ex = new ArgumentException(exMessage); + errorRecord = new ErrorRecord(ex, "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); + + return false; + } + } + } + + return true; + } + + #endregion + } + #endregion } diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index e887265ed..2f82c537e 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -12,6 +12,7 @@ Describe 'Test Install-PSResource for Module' { $testModuleName = "test_module" $testModuleName2 = "TestModule99" $testScriptName = "test_script" + $PackageManagement = "PackageManagement" $RequiredResourceJSONFileName = "TestRequiredResourceFile.json" $RequiredResourcePSD1FileName = "TestRequiredResourceFile.psd1" Get-NewPSResourceRepositoryFile @@ -19,7 +20,7 @@ Describe 'Test Install-PSResource for Module' { } AfterEach { - Uninstall-PSResource "test_module", "test_module2", "test_script", "TestModule99", "testModuleWithlicense", "TestFindModule","ClobberTestModule1", "ClobberTestModule2" -SkipDependencyCheck -ErrorAction SilentlyContinue + Uninstall-PSResource "test_module", "test_module2", "test_script", "TestModule99", "testModuleWithlicense", "TestFindModule","ClobberTestModule1", "ClobberTestModule2", "PackageManagement" -SkipDependencyCheck -ErrorAction SilentlyContinue } AfterAll { @@ -415,6 +416,56 @@ Describe 'Test Install-PSResource for Module' { $res3.Name | Should -Be $testModuleName2 $res3.Version | Should -Be "0.0.93.0" } + + # Install module 1.4.3 (is authenticode signed and has catalog file) + # Should install successfully + It "Install modules with catalog file using publisher validation" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $PackageManagement -Version "1.4.3" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository + + $res1 = Get-PSResource $PackageManagement -Version "1.4.3" + $res1.Name | Should -Be $PackageManagement + $res1.Version | Should -Be "1.4.3.0" + } + + # Install module 1.4.7 (is authenticode signed and has no catalog file) + # Should not install successfully + It "Install module with no catalog file" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $PackageManagement -Version "1.4.7" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository + + $res1 = Get-PSResource $PackageManagement -Version "1.4.7" + $res1.Name | Should -Be $PackageManagement + $res1.Version | Should -Be "1.4.7.0" + } + + # Install module that is not authenticode signed + # Should FAIL to install the module + It "Install module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + } + # Install 1.4.4.1 (with incorrect catalog file) + # Should FAIL to install the module + It "Install module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + } + + # Install script that is signed + # Should install successfully + It "Install script that is authenticode signed" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name "Install-VSCode" -Version "1.4.2" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository + + $res1 = Get-PSResource "Install-VSCode" -Version "1.4.2" + $res1.Name | Should -Be "Install-VSCode" + $res1.Version | Should -Be "1.4.2.0" + } + + # Install script that is not signed + # Should throw + It "Install script that is not signed" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + } } <# Temporarily commented until -Tag is implemented for this Describe block diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 8160144bc..1c3b612e1 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -12,6 +12,7 @@ Describe 'Test Save-PSResource for PSResources' { $testModuleName = "test_module" $testScriptName = "test_script" $testModuleName2 = "testmodule99" + $PackageManagement = "PackageManagement" Get-NewPSResourceRepositoryFile Register-LocalRepos @@ -217,6 +218,61 @@ Describe 'Test Save-PSResource for PSResources' { $res.Name | Should -Be $testModuleName $res.Version | Should -Be "1.0.0.0" } + + # Save module 1.4.3 (is authenticode signed and has catalog file) + # Should save successfully + It "Save modules with catalog file using publisher validation" -Skip:(!(Get-IsWindows)) { + Save-PSResource -Name $PackageManagement -Version "1.4.3" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir + + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $PackageManagement + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.4.3" + } + + # Save module 1.4.7 (is authenticode signed and has NO catalog file) + # Should save successfully + It "Save module with no catalog file" -Skip:(!(Get-IsWindows)) { + Save-PSResource -Name $PackageManagement -Version "1.4.7" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir + + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $PackageManagement + $pkgDir | Should -Not -BeNullOrEmpty + $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName + $pkgDirVersion.Name | Should -Be "1.4.7" + } + + # Save module that is not authenticode signed + # Should FAIL to save the module + It "Save module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { + Save-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + + # Save 1.4.4.1 (with incorrect catalog file) + # Should FAIL to save the module + It "Save module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { + Save-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + + # Save script that is signed + # Should save successfully + It "Save script that is authenticode signed" -Skip:(!(Get-IsWindows)) { + Save-PSResource -Name "Install-VSCode" -Version "1.4.2" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir + + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq "Install-VSCode.ps1" + $pkgDir | Should -Not -BeNullOrEmpty + $pkgName = Get-ChildItem -Path $pkgDir.FullName + $pkgName.Name | Should -Be "Install-VSCode.ps1" + } + + # Save script that is not signed + # Should throw + It "Save script that is not signed" -Skip:(!(Get-IsWindows)) { + Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + <# # Tests should not write to module directory It "Save specific module resource by name if no -Path param is specifed" { diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 4c3bf082b..0bbbdc2da 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -13,12 +13,13 @@ Describe 'Test Update-PSResource' { $testModuleName = "test_module" $testModuleName2 = "test_module2" $testModuleName3 = "TestModule99" + $PackageManagement = "PackageManagement" Get-NewPSResourceRepositoryFile Get-PSResourceRepository } AfterEach { - Uninstall-PSResource "test_module", "TestModule99", "TestModuleWithLicense", "test_module2", "test_script" + Uninstall-PSResource "test_module", "TestModule99", "TestModuleWithLicense", "test_module2", "test_script", "PackaeManagement" -Version "*" } AfterAll { @@ -324,4 +325,53 @@ Describe 'Test Update-PSResource' { $res.Name | Should -Contain $testModuleName $res.Version | Should -Contain "3.0.0.0" } + + # Update to module 1.4.3 (is authenticode signed and has catalog file) + # Should update successfully + It "Update module with catalog file using publisher validation" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $PackageManagement -Version "1.4.3" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository + + $res1 = Get-PSResource $PackageManagement -Version "1.4.3" + $res1.Name | Should -Be $PackageManagement + $res1.Version | Should -Be "1.4.3.0" + } + + # Update to module 1.4.7 (is authenticode signed and has NO catalog file) + # Should update successfully + It "Install module with no catalog file" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $PackageManagement -Version "1.4.7" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository + + $res1 = Get-PSResource $PackageManagement -Version "1.4.7" + $res1.Name | Should -Be $PackageManagement + $res1.Version | Should -Be "1.4.7.0" + } + + # Update to module 1.4.4.1 (with incorrect catalog file) + # Should FAIL to update the module + It "Update module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" + } + + # Update script that is signed + # Should update successfully + It "Update script that is authenticode signed" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name "Install-VSCode" -Version "1.4.1" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name "Install-VSCode" -Version "1.4.2" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository + + $res1 = Get-PSResource "Install-VSCode" -Version "1.4.2" + $res1.Name | Should -Be "Install-VSCode" + $res1.Version | Should -Be "1.4.2.0" + } + + # Update script that is not signed + # Should throw + It "Update script that is not signed" -Skip:(!(Get-IsWindows)) { + Install-PSResource -Name "TestTestScript" -Version "1.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" + } } From 6f2ec28aaa0dac5d11d5a054720952c2c7a4d9f1 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 21 Jun 2022 12:11:51 -0700 Subject: [PATCH 164/276] Update nuget client dependency packages (#678) --- src/code/PowerShellGet.csproj | 12 ++++++------ src/code/PublishPSResource.cs | 2 +- test/InstallPSResource.Tests.ps1 | 26 ++++++++++++++++++++------ test/SavePSResource.Tests.ps1 | 29 +++++++++++++++++++++-------- test/UninstallPSResource.Tests.ps1 | 6 +++++- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 6d580abac..dbd51ee95 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -15,12 +15,12 @@ - - - - - - + + + + + + diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index f80f0ca5c..c3c465e63 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -1008,7 +1008,7 @@ private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, o PushRunner.Run( settings: Settings.LoadDefaultSettings(root: null, configFileName: null, machineWideSettings: null), sourceProvider: new PackageSourceProvider(settings), - packagePath: fullNupkgFile, + packagePaths: new List { fullNupkgFile }, source: publishLocation, apiKey: ApiKey, symbolSource: null, diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 2f82c537e..e2666efb0 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -96,13 +96,27 @@ Describe 'Test Install-PSResource for Module' { $pkg.Version | Should -Be "3.0.0.0" } - It "Should not install resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.0.0.0)'; Description="exclusive version (1.0.0.0)"}, - @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter [1-0-0-0]"} - ) { - param($Version, $Description) + # TODO: Update this test and others like it that use try/catch blocks instead of Should -Throw + It "Should not install resource with incorrectly formatted version such as exclusive version (1.0.0.0)" { + $Version = "(1.0.0.0)" + try { + Install-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "IncorrectVersionFormat,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + + $res = Get-PSResource $testModuleName + $res | Should -BeNullOrEmpty + } - Install-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + It "Should not install resource with incorrectly formatted version such as version formatted with invalid delimiter [1-0-0-0]" { + $Version="[1-0-0-0]" + try { + Install-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} $Error[0].FullyQualifiedErrorId | Should -be "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" $res = Get-PSResource $testModuleName diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 1c3b612e1..b9ddac47d 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -99,17 +99,30 @@ Describe 'Test Save-PSResource for PSResources' { $pkgDirVersion.Name | Should -Be "3.0.0.0" } - It "Should not save resource with incorrectly formatted version such as " -TestCases @( - @{Version='(1.0.0.0)'; Description="exclusive version (1.0.0.0)"}, - @{Version='[1-0-0-0]'; Description="version formatted with invalid delimiter [1-0-0-0]"} - ) { - param($Version, $Description) + It "Should not save resource with incorrectly formatted version such as exclusive version (1.0.0.0)" { + $Version="(1.0.0.0)" + try { + Save-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -Path $SaveDir -ErrorAction SilentlyContinue -TrustRepository + } + catch + {} + $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName + $pkgDir | Should -BeNullOrEmpty + $Error.Count | Should -Not -Be 0 + $Error[0].FullyQualifiedErrorId | Should -Be "IncorrectVersionFormat,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } - Save-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -Path $SaveDir -ErrorVariable err -ErrorAction SilentlyContinue -TrustRepository + It "Should not save resource with incorrectly formatted version such as version formatted with invalid delimiter [1-0-0-0]"{ + $Version = "[1-0-0-0]" + try { + Save-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -Path $SaveDir -ErrorAction SilentlyContinue -TrustRepository + } + catch + {} $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -BeNullOrEmpty - $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + $Error.Count | Should -Not -Be 0 + $Error[0].FullyQualifiedErrorId | Should -BeExactly "ResourceNotFoundError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } It "Save resource when given Name, Version '*', should install the latest version" { diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 0c0850e60..a0bc31e30 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -152,7 +152,11 @@ Describe 'Test Uninstall-PSResource for Modules' { Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - Uninstall-PSResource -Name $testModuleName -Version $Version + try { + Uninstall-PSResource -Name $testModuleName -Version $Version -ErrorAction SilentlyContinue + } + catch + {} $pkg = Get-PSResource $testModuleName -Version "1.0.0.0" $pkg.Version | Should -Be "1.0.0.0" } From 2b4dab36195453edbd85789c9fdb8353b7c6130e Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 23 Jun 2022 14:34:20 -0700 Subject: [PATCH 165/276] Update PSData file reader. (#681) --- src/code/InstallHelper.cs | 13 +- src/code/InstallPSResource.cs | 29 +-- src/code/PublishPSResource.cs | 17 +- src/code/Utils.cs | 339 +++++++++++++++++++--------------- 4 files changed, 231 insertions(+), 167 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 17e9e7583..5f2a7b06f 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -520,9 +520,18 @@ private List InstallPackage( continue; } - if (!Utils.TryParsePSDataFile(moduleManifest, _cmdletPassedIn, out Hashtable parsedMetadataHashtable)) + if (!Utils.TryReadManifestFile( + manifestFilePath: moduleManifest, + manifestInfo: out Hashtable parsedMetadataHashtable, + error: out Exception manifestReadError)) { - // Ran into errors parsing the module manifest file which was found in Utils.ParseModuleManifest() and written. + WriteError( + new ErrorRecord( + exception: manifestReadError, + errorId: "ManifestFileReadParseError", + errorCategory: ErrorCategory.ReadError, + this)); + continue; } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 98c64a346..cb9bb3510 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -320,18 +320,25 @@ protected override void ProcessRecord() Hashtable pkgsInFile = null; try { - if (_resourceFileType.Equals(ResourceFileType.JsonFile)) + switch (_resourceFileType) { - pkgsInFile = Utils.ConvertJsonToHashtable(this, requiredResourceFileStream); - } - else - { - // must be a .psd1 file - if (!Utils.TryParsePSDataFile(_requiredResourceFile, this, out pkgsInFile)) - { - // Ran into errors parsing the .psd1 file which was found in Utils.TryParsePSDataFile() and written. - return; - } + case ResourceFileType.JsonFile: + pkgsInFile = Utils.ConvertJsonToHashtable(this, requiredResourceFileStream); + break; + + case ResourceFileType.PSDataFile: + if (!Utils.TryReadRequiredResourceFile( + resourceFilePath: _requiredResourceFile, + out pkgsInFile, + out Exception error)) + { + throw error; + } + break; + + case ResourceFileType.UnknownFile: + throw new PSInvalidOperationException( + message: "Unkown file type. Required resource file must be either a json or psd1 data file."); } } catch (Exception) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index c3c465e63..f10648451 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -477,12 +477,19 @@ private string CreateNuspec( // a module will still need the module manifest to be parsed. if (!isScript) { - // Parse the module manifest and *replace* the passed-in metadata with the module manifest metadata. - if (!Utils.TryParsePSDataFile( - moduleFileInfo: filePath, - cmdletPassedIn: this, - parsedMetadataHashtable: out parsedMetadataHash)) + // Use the parsed module manifest data as 'parsedMetadataHash' instead of the passed-in data. + if (!Utils.TryReadManifestFile( + manifestFilePath: filePath, + manifestInfo: out parsedMetadataHash, + error: out Exception manifestReadError)) { + WriteError( + new ErrorRecord( + exception: manifestReadError, + errorId: "ManifestFileReadParseForNuspecError", + errorCategory: ErrorCategory.ReadError, + this)); + return string.Empty; } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 9ab09b3ce..af3687a1f 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -25,7 +25,7 @@ internal static class Utils { #region String fields - public static readonly string[] EmptyStrArray = Array.Empty(); + public static readonly string[] EmptyStrArray = Array.Empty(); public const string PSDataFileExt = ".psd1"; private const string ConvertJsonToHashtableScript = @" param ( @@ -728,53 +728,94 @@ private static void GetStandardPlatformPaths( #endregion - #region Manifest methods + #region PSDataFile parsing - public static bool TryParsePSDataFile( - string moduleFileInfo, - PSCmdlet cmdletPassedIn, - out Hashtable parsedMetadataHashtable) + private static readonly string[] ManifestFileVariables = new string[] { "PSEdition", "PSScriptRoot" }; + + /// + /// Read psd1 manifest file contents and return as Hashtable object. + /// + /// File path to manfiest psd1 file. + /// Hashtable of manifest file contents. + /// Error exception on failure. + /// True on success. + public static bool TryReadManifestFile( + string manifestFilePath, + out Hashtable manifestInfo, + out Exception error) { - parsedMetadataHashtable = new Hashtable(); - bool successfullyParsed = false; + return TryReadPSDataFile( + filePath: manifestFilePath, + allowedVariables: ManifestFileVariables, + allowedCommands: Utils.EmptyStrArray, + allowEnvironmentVariables: false, + out manifestInfo, + out error); + } - // A script will already have the metadata parsed into the parsedMetadatahash, - // a module will still need the module manifest to be parsed. - if (moduleFileInfo.EndsWith(PSDataFileExt, StringComparison.OrdinalIgnoreCase)) - { - // Parse the module manifest - var ast = Parser.ParseFile( - moduleFileInfo, - out Token[] tokens, - out ParseError[] errors); + /// + /// Read psd1 required resource file contents and return as Hashtable object. + /// + /// File path to required resource psd1 file. + /// Hashtable of required resource file contents. + /// Error exception on failure. + /// True on success. + public static bool TryReadRequiredResourceFile( + string resourceFilePath, + out Hashtable resourceInfo, + out Exception error) + { + return TryReadPSDataFile( + filePath: resourceFilePath, + allowedVariables: Utils.EmptyStrArray, + allowedCommands: Utils.EmptyStrArray, + allowEnvironmentVariables: false, + out resourceInfo, + out error); + } - if (errors.Length > 0) + private static bool TryReadPSDataFile( + string filePath, + string[] allowedVariables, + string[] allowedCommands, + bool allowEnvironmentVariables, + out Hashtable dataFileInfo, + out Exception error) + { + try + { + if (filePath is null) { - var message = String.Format("Could not parse '{0}' as a PowerShell data file.", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - return successfullyParsed; + throw new PSArgumentNullException(nameof(filePath)); } - else + + string contents = System.IO.File.ReadAllText(filePath); + var scriptBlock = System.Management.Automation.ScriptBlock.Create(contents); + + // Ensure that the content script block is safe to convert into a PSDataFile Hashtable. + // This will throw for unsafe content. + scriptBlock.CheckRestrictedLanguage( + allowedCommands: allowedCommands, + allowedVariables: allowedVariables, + allowEnvironmentVariables: allowEnvironmentVariables); + + // Convert contents into PSDataFile Hashtable by executing content as script. + object result = scriptBlock.InvokeReturnAsIs(); + if (result is PSObject psObject) { - var data = ast.Find(a => a is HashtableAst, false); - if (data != null) - { - parsedMetadataHashtable = (Hashtable)data.SafeGetValue(); - successfullyParsed = true; - } - else - { - var message = String.Format("Could not parse as PowerShell data file-- no hashtable root for file '{0}'", moduleFileInfo); - var ex = new ArgumentException(message); - var psdataParseError = new ErrorRecord(ex, "psdataParseError", ErrorCategory.ParserError, null); - cmdletPassedIn.WriteError(psdataParseError); - } + result = psObject.BaseObject; } - } - return successfullyParsed; + dataFileInfo = (Hashtable) result; + error = null; + return true; + } + catch (Exception ex) + { + dataFileInfo = null; + error = ex; + return false; + } } #endregion @@ -1128,117 +1169,117 @@ public static Collection InvokeScriptWithHost( } #endregion Methods - } - + } + #endregion - + #region AuthenticodeSignature - - internal static class AuthenticodeSignature - { - #region Methods - - internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNameVersion, VersionRange versionRange, List pathsToSearch, string installPath, PSCmdlet cmdletPassedIn, out ErrorRecord errorRecord) - { - errorRecord = null; - - // Because authenticode and catalog verifications are only applicable on Windows, we allow all packages by default to be installed on unix systems. - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return true; - } - - // Check that the catalog file is signed properly - string catalogFilePath = Path.Combine(tempDirNameVersion, pkgName + ".cat"); - if (File.Exists(catalogFilePath)) - { - // Run catalog validation - Collection TestFileCatalogResult = new Collection(); - string moduleBasePath = tempDirNameVersion; - try - { - // By default "Test-FileCatalog will look through all files in the provided directory, -FilesToSkip allows us to ignore specific files - TestFileCatalogResult = cmdletPassedIn.InvokeCommand.InvokeScript( - script: @"param ( - [string] $moduleBasePath, - [string] $catalogFilePath - ) - $catalogValidation = Test-FileCatalog -Path $moduleBasePath -CatalogFilePath $CatalogFilePath ` - -FilesToSkip '*.nupkg','*.nuspec', '*.nupkg.metadata', '*.nupkg.sha512' ` - -Detailed -ErrorAction SilentlyContinue - - if ($catalogValidation.Status.ToString() -eq 'valid' -and $catalogValidation.Signature.Status -eq 'valid') { - return $true - } - else { - return $false - } - ", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { moduleBasePath, catalogFilePath }); - } - catch (Exception e) - { - errorRecord = new ErrorRecord(new ArgumentException(e.Message), "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); - return false; - } - - bool catalogValidation = (TestFileCatalogResult[0] != null) ? (bool)TestFileCatalogResult[0].BaseObject : false; - if (!catalogValidation) - { - var exMessage = String.Format("The catalog file '{0}' is invalid.", pkgName + ".cat"); - var ex = new ArgumentException(exMessage); - - errorRecord = new ErrorRecord(ex, "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); - return false; - } - } - - Collection authenticodeSignature = new Collection(); - try - { - string[] listOfExtensions = { "*.ps1", "*.psd1", "*.psm1", "*.mof", "*.cat", "*.ps1xml" }; - authenticodeSignature = cmdletPassedIn.InvokeCommand.InvokeScript( - script: @"param ( - [string] $tempDirNameVersion, - [string[]] $listOfExtensions - ) - Get-ChildItem $tempDirNameVersion -Recurse -Include $listOfExtensions | Get-AuthenticodeSignature -ErrorAction SilentlyContinue", - useNewScope: true, - writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, - input: null, - args: new object[] { tempDirNameVersion, listOfExtensions }); - } - catch (Exception e) - { - errorRecord = new ErrorRecord(new ArgumentException(e.Message), "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); - return false; - } - - // If the authenticode signature is not valid, return false - if (authenticodeSignature.Any() && authenticodeSignature[0] != null) - { - foreach (var sign in authenticodeSignature) - { - Signature signature = (Signature)sign.BaseObject; - if (!signature.Status.Equals(SignatureStatus.Valid)) - { - var exMessage = String.Format("The signature for '{0}' is '{1}.", pkgName, signature.Status.ToString()); - var ex = new ArgumentException(exMessage); - errorRecord = new ErrorRecord(ex, "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); - - return false; - } - } - } - - return true; - } - - #endregion - } - + + internal static class AuthenticodeSignature + { + #region Methods + + internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNameVersion, VersionRange versionRange, List pathsToSearch, string installPath, PSCmdlet cmdletPassedIn, out ErrorRecord errorRecord) + { + errorRecord = null; + + // Because authenticode and catalog verifications are only applicable on Windows, we allow all packages by default to be installed on unix systems. + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return true; + } + + // Check that the catalog file is signed properly + string catalogFilePath = Path.Combine(tempDirNameVersion, pkgName + ".cat"); + if (File.Exists(catalogFilePath)) + { + // Run catalog validation + Collection TestFileCatalogResult = new Collection(); + string moduleBasePath = tempDirNameVersion; + try + { + // By default "Test-FileCatalog will look through all files in the provided directory, -FilesToSkip allows us to ignore specific files + TestFileCatalogResult = cmdletPassedIn.InvokeCommand.InvokeScript( + script: @"param ( + [string] $moduleBasePath, + [string] $catalogFilePath + ) + $catalogValidation = Test-FileCatalog -Path $moduleBasePath -CatalogFilePath $CatalogFilePath ` + -FilesToSkip '*.nupkg','*.nuspec', '*.nupkg.metadata', '*.nupkg.sha512' ` + -Detailed -ErrorAction SilentlyContinue + + if ($catalogValidation.Status.ToString() -eq 'valid' -and $catalogValidation.Signature.Status -eq 'valid') { + return $true + } + else { + return $false + } + ", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { moduleBasePath, catalogFilePath }); + } + catch (Exception e) + { + errorRecord = new ErrorRecord(new ArgumentException(e.Message), "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); + return false; + } + + bool catalogValidation = (TestFileCatalogResult[0] != null) ? (bool)TestFileCatalogResult[0].BaseObject : false; + if (!catalogValidation) + { + var exMessage = String.Format("The catalog file '{0}' is invalid.", pkgName + ".cat"); + var ex = new ArgumentException(exMessage); + + errorRecord = new ErrorRecord(ex, "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); + return false; + } + } + + Collection authenticodeSignature = new Collection(); + try + { + string[] listOfExtensions = { "*.ps1", "*.psd1", "*.psm1", "*.mof", "*.cat", "*.ps1xml" }; + authenticodeSignature = cmdletPassedIn.InvokeCommand.InvokeScript( + script: @"param ( + [string] $tempDirNameVersion, + [string[]] $listOfExtensions + ) + Get-ChildItem $tempDirNameVersion -Recurse -Include $listOfExtensions | Get-AuthenticodeSignature -ErrorAction SilentlyContinue", + useNewScope: true, + writeToPipeline: System.Management.Automation.Runspaces.PipelineResultTypes.None, + input: null, + args: new object[] { tempDirNameVersion, listOfExtensions }); + } + catch (Exception e) + { + errorRecord = new ErrorRecord(new ArgumentException(e.Message), "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); + return false; + } + + // If the authenticode signature is not valid, return false + if (authenticodeSignature.Any() && authenticodeSignature[0] != null) + { + foreach (var sign in authenticodeSignature) + { + Signature signature = (Signature)sign.BaseObject; + if (!signature.Status.Equals(SignatureStatus.Valid)) + { + var exMessage = String.Format("The signature for '{0}' is '{1}.", pkgName, signature.Status.ToString()); + var ex = new ArgumentException(exMessage); + errorRecord = new ErrorRecord(ex, "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); + + return false; + } + } + } + + return true; + } + + #endregion + } + #endregion } From c535ca78cdc0b68bb47d4a4c7052f8b627030c04 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Sun, 26 Jun 2022 21:09:58 -0700 Subject: [PATCH 166/276] Add tests for New-PSScriptInfoFIle, Update-PSScriptInfoFile, and Test-PSScriptInfoFIle (#683) --- test/NewPSScriptFileInfo.Tests.ps1 | 299 +++++++++++++++++++++ test/TestPSScriptInfo.Tests.ps1 | 42 +++ test/UpdatePSScriptInfo.Tests.ps1 | 415 +++++++++++++++++++++++++++++ 3 files changed, 756 insertions(+) create mode 100644 test/NewPSScriptFileInfo.Tests.ps1 create mode 100644 test/TestPSScriptInfo.Tests.ps1 create mode 100644 test/UpdatePSScriptInfo.Tests.ps1 diff --git a/test/NewPSScriptFileInfo.Tests.ps1 b/test/NewPSScriptFileInfo.Tests.ps1 new file mode 100644 index 000000000..3ba34acf3 --- /dev/null +++ b/test/NewPSScriptFileInfo.Tests.ps1 @@ -0,0 +1,299 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test New-PSScriptFileInfo" { + BeforeAll { + $script:TempPath = Get-TempPath + } + BeforeEach { + # Create temp script path + $script:TempScriptPath = Join-Path $script:TempPath "PSGet_$(Get-Random)" + $null = New-Item -Path $script:TempScriptPath -ItemType Directory -Force + + $script:PSScriptInfoName = "PSGetTestScript" + $script:testPSScriptInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath "$script:PSScriptInfoName.psd1" + } + AfterEach { + RemoveItem "$script:TempScriptPath" + } + + ### TODO: Add tests for -Force and -WhatIf if those parameters are applicable +<# + It "Create .ps1 file with minimal required fields" { + $Description = "this is a test script" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Test-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath | Should -BeTrue + } + + It "Create .ps1 file with relative path" { + $RelativeCurrentPath = Get-Location + $ScriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" + $Description = "this is a test script" + New-PSScriptFileInfo -FilePath $ScriptFilePath -Description $Description + + Test-PSScriptFileInfo -FilePath $ScriptFilePath | Should -BeTrue + Remove-Item -Path $ScriptFilePath + } + + It "Create new .ps1 given Version parameter" { + $Version = "2.0.0.0" + $Description = "Test description" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Version) | Should -BeTrue + $results.Contains(".VERSION $Version") | Should -BeTrue + } + + It "Create new .ps1 given Guid parameter" { + $Guid = [guid]::NewGuid() + $Description = "Test description" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Guid $Guid -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Guid) | Should -BeTrue + $results.Contains(".GUID $Guid") | Should -BeTrue + } + + It "Create new .ps1 given Author parameter" { + $Author = "Test Author" + $Description = "Test description" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Author $Author -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Author) | Should -BeTrue + $results.Contains(".AUTHOR $Author") | Should -BeTrue + } + + It "Create new .ps1 given Description parameter" { + $Description = "PowerShellGet test description" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($Description) | Should -BeTrue + $results -like ".DESCRIPTION*$Description" | Should -BeTrue + } + + It "Create new .ps1 given CompanyName parameter" { + $CompanyName = "Microsoft" + $Description = "Test description" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -CompanyName $CompanyName -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($CompanyName) | Should -BeTrue + $results.Contains(".COMPANYNAME $Companyname") | Should -BeTrue + } + + It "Create new .ps1 given Copyright parameter" { + $Copyright = "(c) Test Corporation" + $Description = "Test description" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Copyright $Copyright -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Copyright) | Should -BeTrue + $results.Contains(".COPYRIGHT $Copyright") | Should -BeTrue + } + + It "Create new .ps1 given RequiredModules parameter" { + $requiredModuleName = 'PackageManagement' + $requiredModuleVersion = '1.0.0.0' + $RequiredModules = @(@{ModuleName = $requiredModuleName; ModuleVersion = $requiredModuleVersion }) + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredModules $RequiredModules -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($requiredModuleName) | Should -BeTrue + $results.Contains($requiredModuleVersion) | Should -BeTrue + $results -like ".REQUIREDMODULES*$requiredModuleName*$requiredModuleVersion" | Should -BeTrue + } + + It "Create new .ps1 given ReleaseNotes parameter" { + $Description = "Test Description" + $ReleaseNotes = "Release notes for script." + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ReleaseNotes $ReleaseNotes -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($ReleaseNotes) | Should -BeTrue + $results -like ".RELEASENOTES*$ReleaseNotes" | Should -BeTrue + } + + It "Create new .ps1 given Tags parameter" { + $Description = "Test Description" + $Tag1 = "tag1" + $Tag2 = "tag2" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Tags $Tag1, $Tag2 -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($Tag1) | Should -BeTrue + $results.Contains($Tag2) | Should -BeTrue + $results.Contains(".TAGS $Tag1 $Tag2") | Should -BeTrue + } + + It "Create new .ps1 given ProjectUri parameter" { + $Description = "Test Description" + $ProjectUri = "https://www.testprojecturi.com/" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ProjectUri $ProjectUri -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($ProjectUri) | Should -BeTrue + $results.Contains(".PROJECTURI $ProjectUri") | Should -BeTrue + } + + It "Create new .ps1 given LicenseUri parameter" { + $Description = "Test Description" + $LicenseUri = "https://www.testlicenseuri.com/" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -LicenseUri $LicenseUri -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($LicenseUri) | Should -BeTrue + $results.Contains(".LICENSEURI $LicenseUri") | Should -BeTrue + } + + It "Create new .ps1 given IconUri parameter" { + $Description = "Test Description" + $IconUri = "https://www.testiconuri.com/" + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -IconUri $IconUri -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($IconUri) | Should -BeTrue + $results.Contains(".ICONURI $IconUri") | Should -BeTrue + } + + It "Create new .ps1 given ExternalModuleDependencies parameter" { + $Description = "Test Description" + $ExternalModuleDep1 = "ExternalModuleDep1" + $ExternalModuleDep2 = "ExternalModuleDep2" + $ExternalModuleDep1FileName = "ExternalModuleDep1.psm1" + $ExternalModuleDep2FileName = "ExternalModuleDep2.psm1" + $ExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalModuleDep1FileName + $ExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalModuleDep2FileName + + $null = New-Item -Path $ExternalModuleDepPath1 -ItemType File -Force + $null = New-Item -Path $ExternalModuleDepPath2 -ItemType File -Force + + # NOTE: you may need to add the -NestedModules parameter here as well + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $ExternalModuleDep1, $ExternalModuleDep2 -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($ExternalModuleDep1) | Should -BeTrue + $results.Contains($ExternalModuleDep2) | Should -BeTrue + $results -like ".EXTERNALMODULEDEPENDENCIES*$ExternalModuleDep1*$ExternalModuleDep2" | Should -BeTrue + } + + It "Create new .ps1 given RequiredAssemblies parameter" { + $Description = "Test Description" + $RequiredAssembly1 = "RequiredAssembly1.dll" + $RequiredAssembly2 = "RequiredAssembly2.dll" + $RequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredAssembly1 + $RequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredAssembly2 + + $null = New-Item -Path $RequiredAssemblyPath1 -ItemType File -Force + $null = New-Item -Path $RequiredAssemblyPath2 -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredAssemblies $RequiredAssembly1, $RequiredAssembly2 -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($RequiredAssembly1) | Should -BeTrue + $results.Contains($RequiredAssembly2) | Should -BeTrue + $results -like ".REQUIREDASSEMBLIES*$RequiredAssembly1*$RequiredAssembly2" | Should -BeTrue + } + + It "Create new .ps1 given NestedModules parameter" { + $Description = "Test Description" + $NestedModule1 = "NestedModule1" + $NestedModule2 = "NestedModule2" + $NestModuleFileName1 = "NestedModule1.dll" + $NestModuleFileName2 = "NestedModule2.dll" + $NestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NestModuleFileName1 + $NestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NestModuleFileName2 + + $null = New-Item -Path $NestedModulePath1 -ItemType File -Force + $null = New-Item -Path $NestedModulePath2 -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -NestedModules $NestedModule1, $NestedModule2 -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NestedModule1) | Should -BeTrue + $results.Contains($NestedModule2) | Should -BeTrue + $results -like ".NESTEDMODULES*$NestedModule1*$NestedModule2" | Should -BeTrue + } + + It "Create new .ps1 given RequiredScripts parameter" { + $Description = "Test Description" + $RequiredScript1 = "NestedModule1.ps1" + $RequiredScript2 = "NestedModule2.ps1" + $RequiredScript1Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredScript1 + $RequiredScript2Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredScript2 + + $null = New-Item -Path $RequiredScript1Path -ItemType File -Force + $null = New-Item -Path $RequiredScript2Path -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredScripts $RequiredScript1, $RequiredScript2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($RequiredScript1) | Should -BeTrue + $results.Contains($RequiredScript2) | Should -BeTrue + $results -like ".REQUIREDSCRIPTS*$RequiredScript1*$RequiredScript2" | Should -BeTrue + } + + It "Create new .ps1 given ExternalScriptDependencies parameter" { + $Description = "Test Description" + $ExternalScriptDep1 = "ExternalScriptDep1.ps1" + $ExternalScriptDep2 = "ExternalScriptDep2.ps1" + $ExternalScriptDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalScriptDep1 + $ExternalScriptDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalScriptDep2 + + $null = New-Item -Path $ExternalScriptDepPath1 -ItemType File -Force + $null = New-Item -Path $ExternalScriptDepPath2 -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $ExternalModuleDep1, $ExternalModuleDep2 -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($ExternalModuleDep1) | Should -BeTrue + $results.Contains($ExternalModuleDep2) | Should -BeTrue + $results -like ".EXTERNALSCRIPTDEPENDENCIES*$ExternalScriptDep1*$ExternalScriptDep2" | Should -BeTrue + } + + It "Create new .ps1 given PrivateData parameter" { + $Description = "Test Description" + $PrivateData = @{"PrivateDataEntry1" = "PrivateDataValue1"} + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -PrivateData $PrivateData -Description $Description + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($PrivateData) | Should -BeTrue + $results -like ".PRIVATEDATA*$PrivateData" | Should -BeTrue + } +#> +} \ No newline at end of file diff --git a/test/TestPSScriptInfo.Tests.ps1 b/test/TestPSScriptInfo.Tests.ps1 new file mode 100644 index 000000000..fa79f8bf9 --- /dev/null +++ b/test/TestPSScriptInfo.Tests.ps1 @@ -0,0 +1,42 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Test-PSScriptFileInfo" { + + BeforeAll { + $script:TempPath = Get-TempPath + } + BeforeEach { + # Create temp script path + $script:TempScriptPath = Join-Path $script:TempPath "PSGet_$(Get-Random)" + $null = New-Item -Path $script:TempScriptPath -ItemType Directory -Force + + $script:PSScriptInfoName = "PSGetTestScript" + $script:testPSScriptInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath "$script:PSScriptInfoName.psd1" + } + AfterEach { + RemoveItem "$script:TempScriptPath" + } + + ### TODO: Add tests for -Force and -WhatIf if those parameters are applicable + <# + It "Test .ps1 file with minimal required fields" { + $Description = "This is a test script" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Test-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath | Should -BeTrue + } + + It "Test .ps1 file with relative path" { + $RelativeCurrentPath = Get-Location + $ScriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" + $Description = "this is a test script" + New-PSScriptFileInfo -FilePath $ScriptFilePath -Description $Description + + Test-PSScriptFileInfo -FilePath $ScriptFilePath | Should -BeTrue + Remove-Item -Path $ScriptFilePath + } + #> +} diff --git a/test/UpdatePSScriptInfo.Tests.ps1 b/test/UpdatePSScriptInfo.Tests.ps1 new file mode 100644 index 000000000..eb1450eaf --- /dev/null +++ b/test/UpdatePSScriptInfo.Tests.ps1 @@ -0,0 +1,415 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Update-PSScriptFileInfo" { + + BeforeAll { + $script:TempPath = Get-TempPath + } + BeforeEach { + # Create temp script path + $script:TempScriptPath = Join-Path $script:TempPath "PSGet_$(Get-Random)" + $null = New-Item -Path $script:TempScriptPath -ItemType Directory -Force + + $script:PSScriptInfoName = "PSGetTestScript" + $script:testPSScriptInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath "$script:PSScriptInfoName.psd1" + } + AfterEach { + RemoveItem "$script:TempScriptPath" + } + + ### TODO: Add tests for -Force and -WhatIf if those parameters are applicable +<# + It "Update .ps1 file with relative path" { + $RelativeCurrentPath = Get-Location + $ScriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" + $OldDescription = "Old description for test script" + $NewDescription = "Old description for test script" + New-PSScriptFileInfo -FilePath $ScriptFilePath -Description $OldDescription + + Update-PSScriptFileInfo -FilePath $ScriptFilePath -Description $NewDescription + + Test-PSScriptFileInfo -FilePath $ScriptFilePath | Should -BeTrue + Remove-Item -Path $ScriptFilePath + } + + It "Update .ps1 given Version parameter" { + $Version = "2.0.0.0" + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Version) | Should -BeTrue + $results.Contains(".VERSION $Version") | Should -BeTrue + } + + It "Update .ps1 given prerelease version" { + $Version = "2.0.0.0-alpha" + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Version) | Should -BeTrue + $results.Contains(".VERSION $Version") | Should -BeTrue + } + + It "Should not update .ps1 with invalid version" { + $Version = "4.0.0.0.0" + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version -ErrorVariable err -ErrorAction SilentlyContinue + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeFalse + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "VersionParseIntoNuGetVersion,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" + } + + It "Update .ps1 given Guid parameter" { + $Guid = [guid]::NewGuid() + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Guid $Guid + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Guid) | Should -BeTrue + $results.Contains(".GUID $Guid") | Should -BeTrue + } + + It "Update .ps1 given Author parameter" { + $Author = "New Author" + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Author $Author + + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($Author) | Should -BeTrue + $results.Contains(".AUTHOR $Author") | Should -BeTrue + } + + It "Update .ps1 given Description parameter" { + $OldDescription = "Old description for test script." + $NewDescription = "New description for test script." + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $OldDescription + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $NewDescription + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewDescription) | Should -BeTrue + $results -like ".DESCRIPTION*$NewDescription" | Should -BeTrue + } + + It "Update .ps1 given CompanyName parameter" { + $OldCompanyName = "Old company name" + $NewCompanyName = "New company name" + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -CompanyName $OldCompanyName -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -CompanyName $NewCompanyName + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($NewCompanyName) | Should -BeTrue + $results.Contains(".COMPANYNAME $NewCompanyName") | Should -BeTrue + } + + It "Update .ps1 given Copyright parameter" { + $OldCopyright = "(c) Old Test Corporation" + $NewCopyright = "(c) New Test Corporation" + $Description = "Test description" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Copyright $OldCopyright -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Copyright $NewCopyright + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testPSScriptInfoPath -Raw + $results.Contains($NewCopyright) | Should -BeTrue + $results.Contains(".COPYRIGHT $NewCopyright") | Should -BeTrue + } + + It "Update .ps1 given RequiredModules parameter" { + $RequiredModuleName = 'PackageManagement' + $OldrequiredModuleVersion = '1.0.0.0' + $OldRequiredModules = @(@{ModuleName = $RequiredModuleName; ModuleVersion = $OldrequiredModuleVersion }) + $NewrequiredModuleVersion = '2.0.0.0' + $NewRequiredModules = @(@{ModuleName = $RequiredModuleName; ModuleVersion = $NewrequiredModuleVersion }) + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredModules $OldRequiredModules -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredModules $NewRequiredModules + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($RequiredModuleName) | Should -BeTrue + $results.Contains($NewrequiredModuleVersion) | Should -BeTrue + $results -like ".REQUIREDMODULES*$RequiredModuleName*$NewrequiredModuleVersion" | Should -BeTrue + } + + It "Update .ps1 given ReleaseNotes parameter" { + $Description = "Test Description" + $OldReleaseNotes = "Old release notes for script." + $NewReleaseNotes = "New release notes for script." + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ReleaseNotes $OldReleaseNotes -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ReleaseNotes $NewReleaseNotes + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewReleaseNotes) | Should -BeTrue + $results -like ".RELEASENOTES*$NewReleaseNotes" | Should -BeTrue + } + + It "Update .ps1 given Tags parameter" { + $Description = "Test Description" + $OldTag1 = "Tag1" + $OldTag2 = "Tag2" + $NewTag1 = "NewTag1" + $NewTag2 = "NewTag2" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Tags $OldTag1, $OldTag2 -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Tags $NewTag1, $NewTag2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewTag1) | Should -BeTrue + $results.Contains($NewTag2) | Should -BeTrue + $results.Contains(".TAGS $NewTag1 $NewTag2") | Should -BeTrue + } + + It "Update .ps1 given ProjectUri parameter" { + $Description = "Test Description" + $OldProjectUri = "https://www.oldtestprojecturi.com/" + $NewProjectUri = "https://www.newtestprojecturi.com/" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ProjectUri $OldProjectUri -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ProjectUri $NewProjectUri + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewProjectUri) | Should -BeTrue + $results.Contains(".PROJECTURI $NewProjectUri") | Should -BeTrue + } + + It "Update .ps1 given LicenseUri parameter" { + $Description = "Test Description" + $OldLicenseUri = "https://www.oldtestlicenseuri.com/" + $NewLicenseUri = "https://www.newtestlicenseuri.com/" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -LicenseUri $OldLicenseUri -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -LicenseUri $NewLicenseUri + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewLicenseUri) | Should -BeTrue + $results.Contains(".LICENSEURI $NewLicenseUri") | Should -BeTrue + } + + It "Update .ps1 given IconUri parameter" { + $Description = "Test Description" + $OldIconUri = "https://www.oldtesticonuri.com/" + $NewIconUri = "https://www.newtesticonuri.com/" + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -IconUri $OldIconUri -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -IconUri $NewIconUri + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewIconUri) | Should -BeTrue + $results.Contains(".ICONURI $NewIconUri") | Should -BeTrue + } + + It "Update .ps1 given ExternalModuleDependencies parameter" { + $Description = "Test Description" + $OldExternalModuleDep1 = "OldExternalModuleDep1" + $OldExternalModuleDep2 = "OldExternalModuleDep2" + $OldExternalModuleDep1FileName = "OldExternalModuleDep1.psm1" + $OldExternalModuleDep2FileName = "OldExternalModuleDep2.psm1" + $OldExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalModuleDep1FileName + $OldExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalModuleDep2FileName + $null = New-Item -Path $OldExternalModuleDepPath1 -ItemType File -Force + $null = New-Item -Path $OldExternalModuleDepPath2 -ItemType File -Force + + $NewExternalModuleDep1 = "NewExternalModuleDep1" + $NewExternalModuleDep2 = "NewExternalModuleDep2" + $NewExternalModuleDep1FileName = "NewExternalModuleDep1.psm1" + $NewExternalModuleDep2FileName = "NewExternalModuleDep2.psm1" + $NewExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalModuleDep1FileName + $NewExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalModuleDep2FileName + $null = New-Item -Path $NewExternalModuleDepPath1 -ItemType File -Force + $null = New-Item -Path $NewExternalModuleDepPath2 -ItemType File -Force + + # NOTE: you may need to add the -NestedModules parameter here as well + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $OldExternalModuleDep1, $OldExternalModuleDep2 -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $NewExternalModuleDep1, $NewExternalModuleDep2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewExternalModuleDep1) | Should -BeTrue + $results.Contains($NewExternalModuleDep2) | Should -BeTrue + $results -like ".EXTERNALMODULEDEPENDENCIES*$NewExternalModuleDep1*$NewExternalModuleDep2" | Should -BeTrue + } + + It "Update .ps1 given RequiredAssemblies parameter" { + $Description = "Test Description" + $OldRequiredAssembly1 = "OldRequiredAssembly1.dll" + $OldRequiredAssembly2 = "OldRequiredAssembly2.dll" + $OldRequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredAssembly1 + $OldRequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredAssembly2 + $null = New-Item -Path $OldRequiredAssemblyPath1 -ItemType File -Force + $null = New-Item -Path $OldRequiredAssemblyPath2 -ItemType File -Force + + $NewRequiredAssembly1 = "NewRequiredAssembly1.dll" + $NewRequiredAssembly2 = "NewRequiredAssembly2.dll" + $NewRequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredAssembly1 + $NewRequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredAssembly2 + $null = New-Item -Path $NewRequiredAssemblyPath1 -ItemType File -Force + $null = New-Item -Path $NewRequiredAssemblyPath2 -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredAssemblies $OldRequiredAssembly1, $OldRequiredAssembly2 -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredAssemblies $NewRequiredAssembly1, $NewRequiredAssembly2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewRequiredAssembly1) | Should -BeTrue + $results.Contains($NewRequiredAssembly2) | Should -BeTrue + $results -like ".REQUIREDASSEMBLIES*$NewRequiredAssembly1*$NewRequiredAssembly2" | Should -BeTrue + } + + It "Update .ps1 given NestedModules parameter" { + $Description = "Test Description" + $OldNestedModule1 = "OldNestedModule1" + $OldNestedModule2 = "OldNestedModule2" + $OldNestModuleFileName1 = "OldNestedModule1.dll" + $OldNestModuleFileName2 = "OldNestedModule2.dll" + $OldNestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldNestModuleFileName1 + $OldNestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldNestModuleFileName2 + $null = New-Item -Path $OldNestedModulePath1 -ItemType File -Force + $null = New-Item -Path $OldNestedModulePath2 -ItemType File -Force + + $NewNestedModule1 = "NewNestedModule1" + $NewNestedModule2 = "NewNestedModule2" + $NewNestModuleFileName1 = "NewNestedModule1.dll" + $NewNestModuleFileName2 = "NewNestedModule2.dll" + $NewNestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewNestModuleFileName1 + $NewNestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewNestModuleFileName2 + $null = New-Item -Path $NewNestedModulePath1 -ItemType File -Force + $null = New-Item -Path $NewNestedModulePath2 -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -NestedModules $OldNestedModule1, $OldNestedModule2 -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -NestedModules $NewNestedModule1, $NewNestedModule2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewNestedModule1) | Should -BeTrue + $results.Contains($NewNestedModule2) | Should -BeTrue + $results -like ".NESTEDMODULES*$NewNestedModule1*$NewNestedModule2" | Should -BeTrue + } + + It "Update .ps1 given RequiredScripts parameter" { + $Description = "Test Description" + $OldRequiredScript1 = "OldNestedModule1.ps1" + $OldRequiredScript2 = "OldNestedModule2.ps1" + $OldRequiredScript1Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredScript1 + $OldRequiredScript2Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredScript2 + $null = New-Item -Path $OldRequiredScript1Path -ItemType File -Force + $null = New-Item -Path $OldRequiredScript2Path -ItemType File -Force + + $NewRequiredScript1 = "NewNestedModule1.ps1" + $NewRequiredScript2 = "NewNestedModule2.ps1" + $NewRequiredScript1Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredScript1 + $NewRequiredScript2Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredScript2 + $null = New-Item -Path $NewRequiredScript1Path -ItemType File -Force + $null = New-Item -Path $NewRequiredScript2Path -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredScripts $OldRequiredScript1, $OldRequiredScript2 -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredScripts $NewRequiredScript1, $NewRequiredScript2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewRequiredScript1) | Should -BeTrue + $results.Contains($NewRequiredScript2) | Should -BeTrue + $results -like ".REQUIREDSCRIPTS*$NewRequiredScript1*$NewRequiredScript2" | Should -BeTrue + } + + It "Update .ps1 given ExternalScriptDependencies parameter" { + $Description = "Test Description" + $OldExternalScriptDep1 = "OldExternalScriptDep1.ps1" + $OldExternalScriptDep2 = "OldExternalScriptDep2.ps1" + $OldExternalScriptDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalScriptDep1 + $OldExternalScriptDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalScriptDep2 + $null = New-Item -Path $OldExternalScriptDepPath1 -ItemType File -Force + $null = New-Item -Path $OldExternalScriptDepPath2 -ItemType File -Force + + $NewExternalScriptDep1 = "NewExternalScriptDep1.ps1" + $NewExternalScriptDep2 = "NewExternalScriptDep2.ps1" + $NewExternalScriptDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalScriptDep1 + $NewExternalScriptDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalScriptDep2 + $null = New-Item -Path $NewExternalScriptDepPath1 -ItemType File -Force + $null = New-Item -Path $NewExternalScriptDepPath2 -ItemType File -Force + + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $OldExternalModuleDep1, $OldExternalModuleDep2 -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $NewExternalModuleDep1, $NewExternalModuleDep2 + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewExternalModuleDep1) | Should -BeTrue + $results.Contains($NewExternalModuleDep2) | Should -BeTrue + $results -like ".EXTERNALSCRIPTDEPENDENCIES*$NewExternalModuleDep1*$NewExternalModuleDep2" | Should -BeTrue + } + + It "Update .ps1 given PrivateData parameter" { + $Description = "Test Description" + $OldPrivateData = @{"OldPrivateDataEntry1" = "OldPrivateDataValue1"} + $NewPrivateData = @{"NewPrivateDataEntry1" = "NewPrivateDataValue1"} + New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -PrivateData $OldPrivateData -Description $Description + + Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -PrivateData $NewPrivateData + + Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($NewPrivateData) | Should -BeTrue + $results -like ".PRIVATEDATA*$NewPrivateData" | Should -BeTrue + } + + It "Update signed script when using RemoveSignature parameter" { + $scriptName = "ScriptWithSignature.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + # use a copy of the signed script file so we can re-use for other tests + $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive + $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName + + Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" -RemoveSignature + Test-PSScriptFileInfo -FilePath $tmpScriptFilePath | Should -Be $true + } + + It "Throw error when attempting to update a signed script without -RemoveSignature parameter" { + $scriptName = "ScriptWithSignature.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + # use a copy of the signed script file so we can re-use for other tests + $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive + $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName + + { Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" } | Should -Throw -ErrorId "ScriptToBeUpdatedContainsSignature,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" + } +#> +} \ No newline at end of file From b8599db8cd402b09e9a0bd11bdd48fcb94771a7b Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 7 Jul 2022 12:32:39 -0700 Subject: [PATCH 167/276] Add benchmark tests for v3 (and v2) performance (#690) --- src/code/PowerShellGet.csproj | 4 ++ test/perf/benchmarks/BenchmarksV2LocalRepo.cs | 70 ++++++++++++++++++ .../perf/benchmarks/BenchmarksV2RemoteRepo.cs | 60 ++++++++++++++++ test/perf/benchmarks/BenchmarksV3LocalRepo.cs | 72 +++++++++++++++++++ .../perf/benchmarks/BenchmarksV3RemoteRepo.cs | 68 ++++++++++++++++++ test/perf/benchmarks/Program.cs | 18 +++++ test/perf/benchmarks/README.md | 32 +++++++++ test/perf/benchmarks/benchmarks.csproj | 25 +++++++ 8 files changed, 349 insertions(+) create mode 100644 test/perf/benchmarks/BenchmarksV2LocalRepo.cs create mode 100644 test/perf/benchmarks/BenchmarksV2RemoteRepo.cs create mode 100644 test/perf/benchmarks/BenchmarksV3LocalRepo.cs create mode 100644 test/perf/benchmarks/BenchmarksV3RemoteRepo.cs create mode 100644 test/perf/benchmarks/Program.cs create mode 100644 test/perf/benchmarks/README.md create mode 100644 test/perf/benchmarks/benchmarks.csproj diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index dbd51ee95..e9d2e9a88 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -27,6 +27,10 @@ + + + + diff --git a/test/perf/benchmarks/BenchmarksV2LocalRepo.cs b/test/perf/benchmarks/BenchmarksV2LocalRepo.cs new file mode 100644 index 000000000..966db9c5b --- /dev/null +++ b/test/perf/benchmarks/BenchmarksV2LocalRepo.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using BenchmarkDotNet; +using BenchmarkDotNet.Attributes; +using Microsoft.PowerShell; +using System; +using System.Collections.ObjectModel; +using System.Management.Automation; + +namespace Benchmarks +{ + public class BenchmarksV2LocalRepo + { + System.Management.Automation.PowerShell pwsh; + + [GlobalSetup] + public void GlobalSetup() + { + // Setting up the PowerShell runspace + var defaultSS = System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2(); + defaultSS.ExecutionPolicy = ExecutionPolicy.Unrestricted; + pwsh = System.Management.Automation.PowerShell.Create(defaultSS); + + // Using PSGet v3 in order to save the Az modules and its dependencies + pwsh.AddScript("Import-Module PowerShellGet -RequiredVersion 3.0.14 -Force"); + pwsh.AddScript("New-Item TestRepo -ItemType Directory"); + pwsh.AddScript("Save-PSResource -Name Az -Repository PSGallery -AsNupkg -TrustRepository -Path .\\TestRepo"); + + // Now import the PSGet module version we want to test and register a local repo + pwsh.AddScript("Import-Module PowerShellGet -RequiredVersion 2.2.5 -Force"); + pwsh.AddScript("Register-PSRepository -Name LocalRepo -SourceLocation .\\TestRepo"); + + pwsh.Invoke(); + } + + [GlobalCleanup] + public void GlobalCleanup() + { + pwsh.Dispose(); + } + + [Benchmark] + public void FindAzModuleV2() + + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-Module -Name Az -Repository LocalRepo"); + pwsh.Invoke(); + } + + [Benchmark] + public void FindAzModuleAndDependenciesV2() + + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-Module -Name Az -IncludeDependencies -Repository LocalRepo"); + pwsh.Invoke(); + } + + [Benchmark] + public void InstallAzModuleAndDependenciesV2() + + { + pwsh.Commands.Clear(); + pwsh.AddScript("Install-Module -Name Az -Repository LocalRepo -Force"); + pwsh.Invoke(); + } + } +} diff --git a/test/perf/benchmarks/BenchmarksV2RemoteRepo.cs b/test/perf/benchmarks/BenchmarksV2RemoteRepo.cs new file mode 100644 index 000000000..cfa0cf88c --- /dev/null +++ b/test/perf/benchmarks/BenchmarksV2RemoteRepo.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using BenchmarkDotNet; +using BenchmarkDotNet.Attributes; +using Microsoft.PowerShell; +using System; +using System.Collections.ObjectModel; +using System.Management.Automation; + +namespace Benchmarks +{ + public class BenchmarksV2RemoteRepo + { + System.Management.Automation.PowerShell pwsh; + + [GlobalSetup] + public void GlobalSetup() + { + // Setting up the PowerShell runspace + var defaultSS = System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2(); + defaultSS.ExecutionPolicy = ExecutionPolicy.Unrestricted; + pwsh = System.Management.Automation.PowerShell.Create(defaultSS); + + // Import the PSGet version we want to test + pwsh.AddScript("Import-Module PowerShellGet -RequiredVersion 2.2.5 -Force"); + pwsh.Invoke(); + } + + [GloblaCleanup] + public void IterationCleanup() + { + pwsh.Dispose(); + } + + [Benchmark] + public void FindAzModuleV2() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-Module -Name Az -Repository PSGallery"); + pwsh.Invoke(); + } + + [Benchmark] + public void FindAzModuleAndDependenciesV2() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-Module -Name Az -IncludeDependencies -Repository PSGallery"); + pwsh.Invoke(); + } + + [Benchmark] + public void InstallAzModuleAndDependenciesV2() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Install-Module -Name Az -Repository PSGallery -Force"); + pwsh.Invoke(); + } + } +} diff --git a/test/perf/benchmarks/BenchmarksV3LocalRepo.cs b/test/perf/benchmarks/BenchmarksV3LocalRepo.cs new file mode 100644 index 000000000..f3cfe6044 --- /dev/null +++ b/test/perf/benchmarks/BenchmarksV3LocalRepo.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using BenchmarkDotNet; +using BenchmarkDotNet.Attributes; +using Microsoft.PowerShell; +using System; +using System.Collections.ObjectModel; +using System.Management.Automation; + +namespace Benchmarks +{ + public class BenchmarksV3LocalRepo + { + System.Management.Automation.PowerShell pwsh; + + [GlobalSetup] + public void GlobalSetup() + { + // Setting up the PowerShell runspace + var defaultSS = System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2(); + defaultSS.ExecutionPolicy = ExecutionPolicy.Unrestricted; + pwsh = System.Management.Automation.PowerShell.Create(defaultSS); + + // Import the PSGet module version we want to test, register a local repo, and save the Az modules and its dependencies + pwsh.AddScript("Import-Module PowerShellGet -RequiredVersion 3.0.14 -Force"); + pwsh.AddScript("New-Item TestRepo -ItemType Directory"); + pwsh.AddScript("Register-PSResourceRepository -Name LocalRepo -Uri .\\TestRepo"); + pwsh.AddScript("Save-PSResource -Name Az -Repository PSGallery -AsNupkg -TrustRepository -Path .\\TestRepo"); + + pwsh.Invoke(); + } + + [GlobalCleanup] + public void GlobalCleanup() + { + pwsh.Dispose(); + } + + [Benchmark] + public void FindAzModuleV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-PSResource -Name Az -Repository LocalRepo"); + pwsh.Invoke(); + } + + [Benchmark] + public void FindAzModuleAndDependenciesV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-PSResource -Name Az -IncludeDependencies -Repository LocalRepo"); + pwsh.Invoke(); + } + + [Benchmark] + public void InstallAzModuleV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Install-PSResource -Name Az -Repository LocalRepo -TrustRepository -SkipDependencyCheck -Reinstall"); + pwsh.Invoke(); + } + + [Benchmark] + public void InstallAzModuleAndDependenciesV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Install-PSResource -Name Az -Repository LocalRepo -TrustRepository -Reinstall"); + pwsh.Invoke(); + } + } +} diff --git a/test/perf/benchmarks/BenchmarksV3RemoteRepo.cs b/test/perf/benchmarks/BenchmarksV3RemoteRepo.cs new file mode 100644 index 000000000..278dd7535 --- /dev/null +++ b/test/perf/benchmarks/BenchmarksV3RemoteRepo.cs @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using BenchmarkDotNet; +using BenchmarkDotNet.Attributes; +using Microsoft.PowerShell; +using System; +using System.Collections.ObjectModel; +using System.Management.Automation; + +namespace Benchmarks +{ + public class BenchmarksV3RemoteRepo + { + System.Management.Automation.PowerShell pwsh; + + [GlobalSetup] + public void GlobalSetup() + { + // Setting up the PowerShell runspace + var defaultSS = System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2(); + defaultSS.ExecutionPolicy = ExecutionPolicy.Unrestricted; + pwsh = System.Management.Automation.PowerShell.Create(defaultSS); + + // Import the PSGet version we want to test + pwsh.AddScript("Import-Module PowerShellGet -RequiredVersion 3.0.14 -Force"); + pwsh.Invoke(); + } + + [GlobalCleanup] + public void GlobalCleanup() + { + pwsh.Dispose(); + } + + [Benchmark] + public void FindAzModuleV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-PSResource -Name Az -Repository PSGallery"); + pwsh.Invoke(); + } + + [Benchmark] + public void FindAzModuleAndDependenciesV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Find-PSResource -Name Az -IncludeDependencies -Repository PSGallery"); + pwsh.Invoke(); + } + + [Benchmark] + public void InstallAzModuleV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Install-PSResource -Name Az -Repository PSGallery -TrustRepository -SkipDependencyCheck -Reinstall"); + pwsh.Invoke(); + } + + [Benchmark] + public void InstallAzModuleAndDependenciesV3() + { + pwsh.Commands.Clear(); + pwsh.AddScript("Install-PSResource -Name Az -Repository PSGallery -TrustRepository -Reinstall"); + pwsh.Invoke(); + } + } +} diff --git a/test/perf/benchmarks/Program.cs b/test/perf/benchmarks/Program.cs new file mode 100644 index 000000000..a6e6ac316 --- /dev/null +++ b/test/perf/benchmarks/Program.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using BenchmarkDotNet.Running; + +namespace Benchmarks +{ + public sealed class Program + { + public static void Main(string[] args) + { + var summaryV2Remote = BenchmarkRunner.Run(); + var summaryV3Remote = BenchmarkRunner.Run(); + var summaryV2Local = BenchmarkRunner.Run(); + var summaryV3Local = BenchmarkRunner.Run(); + } + } +} diff --git a/test/perf/benchmarks/README.md b/test/perf/benchmarks/README.md new file mode 100644 index 000000000..127b164a7 --- /dev/null +++ b/test/perf/benchmarks/README.md @@ -0,0 +1,32 @@ +## Micro Benchmarks + +This folder contains micro benchmarks that test the performance of PowerShellGet. + +### Quick Start + +You can run the benchmarks directly using `dotnet run` in this directory: +1. To run the benchmarks in Interactive Mode, where you will be asked which benchmark(s) to run: + ``` + dotnet run -c Release -f net6.0 + ``` + +2. To list all available benchmarks ([read more](https://github.com/dotnet/performance/blob/main/docs/benchmarkdotnet.md#Listing-the-Benchmarks)): + ``` + dotnet run -c Release -f net6.0 --list [flat/tree] + ``` + +3. To filter the benchmarks using a glob pattern applied to `namespace.typeName.methodName` ([read more](https://github.com/dotnet/performance/blob/main/docs/benchmarkdotnet.md#Filtering-the-Benchmarks)]): + ``` + dotnet run -c Release -f net6.0 --filter *script* --list flat + ``` + +4. To profile the benchmarked code and produce an ETW Trace file ([read more](https://github.com/dotnet/performance/blob/main/docs/benchmarkdotnet.md#Profiling)) + ``` + dotnet run -c Release -f net6.0 --filter *script* --profiler ETW + ``` + +## References + +- [Getting started with BenchmarkDotNet](https://benchmarkdotnet.org/articles/guides/getting-started.html) +- [Micro-benchmark Design Guidelines](https://github.com/dotnet/performance/blob/main/docs/microbenchmark-design-guidelines.md) +- [Adam SITNIK: Powerful benchmarking in .NET](https://www.youtube.com/watch?v=pdcrSG4tOLI&t=351s) \ No newline at end of file diff --git a/test/perf/benchmarks/benchmarks.csproj b/test/perf/benchmarks/benchmarks.csproj new file mode 100644 index 000000000..3ea7e4fe8 --- /dev/null +++ b/test/perf/benchmarks/benchmarks.csproj @@ -0,0 +1,25 @@ + + + net6.0 + Exe + + + AnyCPU + pdbonly + true + true + true + Release + false + + + + + + + + + + + + From 5f032f14eeaa5f7090ee35ff18c826a749279600 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 12 Jul 2022 17:42:28 -0700 Subject: [PATCH 168/276] 'Update-ModuleManifest' cmdlet implementation (#677) --- help/Update-ModuleManifest.md | 698 ++++++++++++++++++++++++++++ src/PowerShellGet.psd1 | 1 + src/code/PublishPSResource.cs | 75 +-- src/code/UpdateModuleManifest.cs | 638 +++++++++++++++++++++++++ src/code/Utils.cs | 57 +++ test/UpdateModuleManifest.Tests.ps1 | 406 ++++++++++++++++ 6 files changed, 1814 insertions(+), 61 deletions(-) create mode 100644 help/Update-ModuleManifest.md create mode 100644 src/code/UpdateModuleManifest.cs create mode 100644 test/UpdateModuleManifest.Tests.ps1 diff --git a/help/Update-ModuleManifest.md b/help/Update-ModuleManifest.md new file mode 100644 index 000000000..100e7550f --- /dev/null +++ b/help/Update-ModuleManifest.md @@ -0,0 +1,698 @@ +--- +external help file: PowerShellGet.dll-Help.xml +Module Name: PowerShellGet +online version: +schema: 2.0.0 +--- + +# Update-ModuleManifest + +## SYNOPSIS +Updates a module manifest file. + +## SYNTAX + +### NameParameterSet (Default) +``` +Update-ModuleManifest [-Path] [-NestedModules ] [-Guid ] [-Author ] + [-CompanyName ] [-Copyright ] [-RootModule ] [-ModuleVersion ] + [-Description ] [-ProcessorArchitecture ] [-CompatiblePSEditions ] + [-PowerShellVersion ] [-ClrVersion ] [-DotNetFrameworkVersion ] + [-PowerShellHostName ] [-PowerShellHostVersion ] [-RequiredModules ] + [-TypesToProcess ] [-FormatsToProcess ] [-ScriptsToProcess ] + [-RequiredAssemblies ] [-FileList ] [-ModuleList ] [-FunctionsToExport ] + [-AliasesToExport ] [-VariablesToExport ] [-CmdletsToExport ] + [-DscResourcesToExport ] [-PrivateData ] [-Tags ] [-ProjectUri ] + [-LicenseUri ] [-IconUri ] [-ReleaseNotes ] [-Prerelease ] [-HelpInfoUri ] + [-DefaultCommandPrefix ] [-ExternalModuleDependencies ] [-RequireLicenseAcceptance] + [] +``` + +## DESCRIPTION +The Update-ModuleManifest cmdlet replaces the Update-ModuleManifest cmdlet from V2. +It updates a module manifest based on the `-Path` parameter argument. +It does not return an object. Other parameters allow specific properties of the manifest to be updated. + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" +``` +In this example the author property in the module manifest will be updated to "New Author". + +```powershell +PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" +``` +In this example the prerelease property will be updated to "beta2" + +```powershell +PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." +``` +In this example the tags and description will be updated to the passed in values. + +## PARAMETERS + +### -Path +Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -NestedModules +Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. + +Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + +```yaml +Type: Object[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Guid +Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + +```yaml +Type: System.Guid +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Author +Specifies the module author. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -CompanyName +Specifies the company or vendor who created the module. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Copyright +Specifies a copyright statement for the module. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -RootModule +Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. + +If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). + +To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ModuleVersion +Specifies the version of the module. + +```yaml +Type: System.Version +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Description +Specifies a description of the module. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ProcessorArchitecture +Specifies the processor architecture that the module requires. + +The acceptable values for this parameter are: + +* Amd64 +* Arm +* IA64 +* MSIL +* None (unknown or unspecified) +* X86 + +```yaml +Type: System.Reflection.ProcessorArchitecture +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -CompatiblePSEditions +Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: +Accepted Values: Desktop, Core + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PowerShellVersion +Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + +```yaml +Type: System.Version +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ClrVersion +Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + +```yaml +Type: System.Version +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -DotNetFrameworkVersion +Specifies the minimum version of the Microsoft .NET Framework that the module requires. + +```yaml +Type: System.Version +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PowerShellHostName +Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + +To find the name of a host program, in the program, type $Host.Name. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PowerShellHostVersion +Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + +```yaml +Type: System.Version +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -RequiredModules +Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + +```yaml +Type: System.Object[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -TypesToProcess +Specifies the type files (.ps1xml) that run when the module is imported. + +When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -FormatsToProcess +Specifies the formatting files (.ps1xml) that run when the module is imported. + +When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ScriptsToProcess +Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + +To specify scripts that run in the module's session state, use the NestedModules key. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -RequiredAssemblies +Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. + +Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -FileList +Specifies all items that are included in the module. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ModuleList +Specifies an array of modules that are included in the module. + +Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + +This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -FunctionsToExport +Specifies the functions that the module exports. Wildcards are permitted. + +Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + +### -AliasesToExport +Specifies the aliases that the module exports. Wildcards are permitted. + +Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + +### -VariablesToExport +Specifies the variables that the module exports. Wildcards are permitted. + +Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + +### -CmdletsToExport +Specifies the cmdlets that the module exports. Wildcards are permitted. + +Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + +### -DscResourcesToExport +Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + +### -PrivateData +Specifies data that is passed to the module when it's imported. + +```yaml +Type: Hashtable +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Tags +Specifies an array of tags. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ProjectUri +Specifies the URL of a web page about this project. + +```yaml +Type: Uri +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -LicenseUri +Specifies the URL of licensing terms for the module. + +```yaml +Type: Uri +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -IconUri +Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + +```yaml +Type: Uri +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ReleaseNotes +Specifies a string array that contains release notes or comments that you want available for this version of the script. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Prerelease +Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -HelpInfoUri +Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. + +The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. + +For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + +```yaml +Type: Uri +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -DefaultCommandPrefix +Specifies the default command prefix. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ExternalModuleDependencies +Specifies an array of external module dependencies. + +```yaml +Type: System.String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -RequireLicenseAcceptance +Specifies that a license acceptance is required for the module. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### System.String[] + +## OUTPUTS +None + +## NOTES + +## RELATED LINKS + +[]() diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 4029ab2bf..2c9b767b2 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -24,6 +24,7 @@ 'Publish-PSResource', 'Uninstall-PSResource', 'Unregister-PSResourceRepository', + 'Update-ModuleManifest', 'Update-PSResource') VariablesToExport = 'PSGetPath' diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index f10648451..752255eae 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -232,9 +232,21 @@ protected override void EndProcessing() } // validate that the module manifest has correct data - if (!IsValidModuleManifest(resourceFilePath)) + string[] errorMsgs = null; + try { - return; + Utils.ValidateModuleManifest(resourceFilePath, out errorMsgs); + + } + finally { + if (errorMsgs.Length > 0) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsgs.First()), + "InvalidModuleManifest", + ErrorCategory.InvalidOperation, + this)); + } } } @@ -404,65 +416,6 @@ protected override void EndProcessing() #region Private methods - private bool IsValidModuleManifest(string moduleManifestPath) - { - var isValid = true; - using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) - { - // use PowerShell cmdlet Test-ModuleManifest - // TODO: Test-ModuleManifest will throw an error if RequiredModules specifies a module that does not exist - // locally on the machine. Consider adding a -Syntax param to Test-ModuleManifest so that it only checks that - // the syntax is correct. In build/release pipelines for example, the modules listed under RequiredModules may - // not be locally available, but we still want to allow the user to publish. - Collection results = null; - try - { - results = pwsh.AddCommand("Test-ModuleManifest").AddParameter("Path", moduleManifestPath).Invoke(); - } - catch (Exception e) - { - ThrowTerminatingError(new ErrorRecord( - new ArgumentException("Error occured while running 'Test-ModuleManifest': " + e.Message), - "ErrorExecutingTestModuleManifest", - ErrorCategory.InvalidArgument, - this)); - } - - if (pwsh.HadErrors) - { - var message = string.Empty; - - if (results.Any()) - { - if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Author)) - { - message = "No author was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; - } - else if (string.IsNullOrWhiteSpace((results[0].BaseObject as PSModuleInfo).Description)) - { - message = "No description was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; - } - else if ((results[0].BaseObject as PSModuleInfo).Version == null) - { - message = "No version or an incorrectly formatted version was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; - } - } - - if (string.IsNullOrEmpty(message) && pwsh.Streams.Error.Count > 0) - { - // This will handle version errors - message = pwsh.Streams.Error[0].ToString() + "Run 'Test-ModuleManifest' to validate the module manifest."; - } - var ex = new ArgumentException(message); - var InvalidModuleManifest = new ErrorRecord(ex, "InvalidModuleManifest", ErrorCategory.InvalidData, null); - ThrowTerminatingError(InvalidModuleManifest); - isValid = false; - } - } - - return isValid; - } - private string CreateNuspec( string outputDir, string filePath, diff --git a/src/code/UpdateModuleManifest.cs b/src/code/UpdateModuleManifest.cs new file mode 100644 index 000000000..ee0200282 --- /dev/null +++ b/src/code/UpdateModuleManifest.cs @@ -0,0 +1,638 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.PowerShell.PowerShellGet.UtilClasses; +using System; +using System.Collections; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Reflection; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Updates the module manifest (.psd1) for a resource. + /// + [Cmdlet(VerbsData.Update, "ModuleManifest")] + public sealed class UpdateModuleManifest : PSCmdlet + { + #region Parameters + + /// + /// Specifies the path and file name of the module manifest. + /// + [Parameter (Position = 0, Mandatory = true)] + [ValidateNotNullOrEmpty] + public string Path { get; set; } + + /// + /// Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. + /// + [Parameter] + public object[] NestedModules { get; set; } + + /// + /// Specifies a unique identifier for the module, can be used to distinguish among modules with the same name. + /// + [Parameter] + public Guid Guid { get; set; } + + /// + /// Specifies the module author. + /// + [Parameter] + public string Author { get; set; } + + /// + /// Specifies the company or vendor who created the module. + /// + [Parameter] + public string CompanyName { get; set; } + + /// + /// Specifies a copyright statement for the module. + /// + [Parameter] + public string Copyright { get; set; } + + /// + /// Specifies the primary or root file of the module. + /// + [Parameter] + public string RootModule { get; set; } + + /// + /// Specifies the version of the module. + /// + [Parameter] + public Version ModuleVersion { get; set; } + + /// + /// Specifies a description of the module. + /// + [Parameter] + public string Description { get; set; } + + /// + /// Specifies the processor architecture that the module requires. + /// + [Parameter] + [ValidateNotNullOrEmpty] + public ProcessorArchitecture ProcessorArchitecture { get; set; } + + /// + /// Specifies the compatible PSEditions of the module. + /// + [Parameter] + public string[] CompatiblePSEditions { get; set; } + + /// + /// Specifies the minimum version of PowerShell that will work with this module. + /// + [Parameter] + public Version PowerShellVersion { get; set; } + + /// + /// Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + /// + [Parameter] + public Version ClrVersion { get; set; } + + /// + /// Specifies the minimum version of the Microsoft .NET Framework that the module requires. + /// + [Parameter] + public Version DotNetFrameworkVersion { get; set; } + + /// + /// Specifies the name of the PowerShell host program that the module requires. + /// + [Parameter] + public string PowerShellHostName { get; set; } + + /// + /// Specifies the minimum version of the PowerShell host program that works with the module. + /// + [Parameter] + public Version PowerShellHostVersion { get; set; } + + /// + /// Specifies modules that must be in the global session state. + /// + [Parameter] + public Object[] RequiredModules { get; set; } + + /// + /// Specifies the type files (.ps1xml) that run when the module is imported. + /// + [Parameter] + public string[] TypesToProcess { get; set; } + + /// + /// Specifies the formatting files (.ps1xml) that run when the module is imported. + /// + [Parameter] + public string[] FormatsToProcess { get; set; } + + /// + /// Specifies script (.ps1) files that run in the caller's session state when the module is imported. + /// + [Parameter] + public string[] ScriptsToProcess { get; set; } + + /// + /// Specifies the assembly (.dll) files that the module requires. + /// + [Parameter] + public string[] RequiredAssemblies { get; set; } + + /// + /// Specifies all items that are included in the module. + /// + [Parameter] + public string[] FileList { get; set; } + + /// + /// Specifies an array of modules that are included in the module. + /// + [Parameter] + public Object[] ModuleList { get; set; } + + /// + /// Specifies the functions that the module exports. + /// + [Parameter] + public string[] FunctionsToExport { get; set; } + + /// + /// Specifies the aliases that the module exports. + /// + [Parameter] + public string[] AliasesToExport { get; set; } + + /// + /// Specifies the variables that the module exports. + /// + [Parameter] + public string[] VariablesToExport { get; set; } + + /// + /// Specifies the cmdlets that the module exports. + /// + [Parameter] + public string[] CmdletsToExport { get; set; } + + /// + /// Specifies the Desired State Configuration (DSC) resources that the module exports. + /// + [Parameter] + public string[] DscResourcesToExport { get; set; } + + /// + /// Specifies an array of tags. + /// + [Parameter] + public string[] Tags { get; set; } + + /// + /// Specifies the URL of a web page about this project. + /// + [Parameter] + public Uri ProjectUri { get; set; } + + /// + /// Specifies the URL of licensing terms for the module. + /// + [Parameter] + public Uri LicenseUri { get; set; } + + /// + /// Specifies the URL of an icon for the module. + /// + [Parameter] + public Uri IconUri { get; set; } + + /// + /// Specifies a string that contains release notes or comments that you want available for this version of the script. + + /// + [Parameter] + public string ReleaseNotes { get; set; } + + /// + /// Indicates the prerelease label of the module. + /// + [Parameter] + public string Prerelease { get; set; } + + /// + /// Specifies the internet address of the module's HelpInfo XML file. + /// + [Parameter] + public Uri HelpInfoUri { get; set; } + + /// + /// Returns an object representing the item with which you're working. + /// + [Parameter] + public SwitchParameter PassThru { get; set; } + + /// + /// Specifies the default command prefix. + /// + [Parameter] + public string DefaultCommandPrefix { get; set; } + + /// + /// Specifies an array of external module dependencies. + /// + [Parameter] + public string[] ExternalModuleDependencies { get; set; } + + /// + /// Specifies that a license acceptance is required for the module. + /// + [Parameter] + public SwitchParameter RequireLicenseAcceptance { get; set; } + + /// + /// Specifies data that is passed to the module when it's imported. + /// + [Parameter] + public Hashtable PrivateData { get; set; } + #endregion + + #region Methods + + protected override void EndProcessing() + { + string resolvedManifestPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path).First().Path; + + // Test the path of the module manifest to see if the file exists + if (!File.Exists(resolvedManifestPath) || !resolvedManifestPath.EndsWith(".psd1")) + { + var message = $"The provided file path was not found: '{resolvedManifestPath}'. Please specify a valid module manifest (.psd1) file path."; + + ThrowTerminatingError( + new ErrorRecord( + new ArgumentException(message), + "moduleManifestPathNotFound", + ErrorCategory.ObjectNotFound, + this)); + } + + // Parse the module manifest + if(!Utils.TryReadManifestFile( + manifestFilePath: resolvedManifestPath, + manifestInfo: out Hashtable parsedMetadata, + error: out Exception manifestReadError)) + { + ThrowTerminatingError( + new ErrorRecord( + exception: manifestReadError, + errorId: "ModuleManifestParseFailure", + errorCategory: ErrorCategory.ParserError, + targetObject: this)); + } + + // Prerelease, ReleaseNotes, Tags, ProjectUri, LicenseUri, IconUri, RequireLicenseAcceptance, + // and ExternalModuleDependencies are all properties within a hashtable property called 'PSData' + // which is within another hashtable property called 'PrivateData' + // All of the properties mentioned above have their own parameter in 'New-ModuleManifest', so + // we will parse out these values from the parsedMetadata and create entries for each one in individualy. + // This way any values that were previously specified here will get transfered over to the new manifest. + // Example of the contents of PSData: + // PrivateData = @{ + // PSData = @{ + // # Tags applied to this module. These help with module discovery in online galleries. + // Tags = @('Tag1', 'Tag2') + // + // # A URL to the license for this module. + // LicenseUri = 'https://www.licenseurl.com/' + // + // # A URL to the main website for this project. + // ProjectUri = 'https://www.projecturi.com/' + // + // # A URL to an icon representing this module. + // IconUri = 'https://iconuri.com/' + // + // # ReleaseNotes of this module. + // ReleaseNotes = 'These are the release notes of this module.' + // + // # Prerelease string of this module. + // Prerelease = 'preview' + // + // # Flag to indicate whether the module requires explicit user acceptance for install/update/save. + // RequireLicenseAcceptance = $false + // + // # External dependent modules of this module + // ExternalModuleDependencies = @('ModuleDep1, 'ModuleDep2') + // + // } # End of PSData hashtable + // + // } # End of PrivateData hashtable + var PrivateData = parsedMetadata["PrivateData"] as Hashtable; + var PSData = PrivateData["PSData"] as Hashtable; + + if (PSData.ContainsKey("Prerelease")) + { + parsedMetadata["Prerelease"] = PSData["Prerelease"]; + } + + if (PSData.ContainsKey("ReleaseNotes")) + { + parsedMetadata["ReleaseNotes"] = PSData["ReleaseNotes"]; + } + + if (PSData.ContainsKey("Tags")) + { + parsedMetadata["Tags"] = PSData["Tags"]; + } + + if (PSData.ContainsKey("ProjectUri")) + { + parsedMetadata["ProjectUri"] = PSData["ProjectUri"]; + } + + if (PSData.ContainsKey("LicenseUri")) + { + parsedMetadata["LicenseUri"] = PSData["LicenseUri"]; + } + + if (PSData.ContainsKey("IconUri")) + { + parsedMetadata["IconUri"] = PSData["IconUri"]; + } + + if (PSData.ContainsKey("RequireLicenseAcceptance")) + { + parsedMetadata["RequireLicenseAcceptance"] = PSData["RequireLicenseAcceptance"]; + } + + if (PSData.ContainsKey("ExternalModuleDependencies")) + { + parsedMetadata["ExternalModuleDependencies"] = PSData["ExternalModuleDependencies"]; + } + + // Now we need to remove 'PSData' becaues if we leave this value in the hashtable, + // New-ModuleManifest will keep this value and also attempt to create a new value for 'PSData' + // and then complain that there's two keys within the PrivateData hashtable. + PrivateData.Remove("PSData"); + + // After getting the original module manifest contents, migrate all the fields to the new module manifest, + + // adding in any new values specified via cmdlet parameters. + // Set up params to pass to New-ModuleManifest module + // For now this will be parsedMetadata hashtable and we will just add to it as needed + + if (NestedModules != null) + { + parsedMetadata["NestedModules"] = NestedModules; + } + + if (Guid != Guid.Empty) + { + parsedMetadata["Guid"] = Guid; + } + + if (!string.IsNullOrWhiteSpace(Author)) + { + parsedMetadata["Author"] = Author; + } + + if (CompanyName != null) + { + parsedMetadata["CompanyName"] = CompanyName; + } + + if (Copyright != null) + { + parsedMetadata["Copyright"] = Copyright; + } + + if (RootModule != null) + { + parsedMetadata["RootModule"] = RootModule; + } + + if (ModuleVersion != null) + { + parsedMetadata["ModuleVersion"] = ModuleVersion; + } + + if (Description != null) + { + parsedMetadata["Description"] = Description; + } + + if (ProcessorArchitecture != ProcessorArchitecture.None) + { + parsedMetadata["ProcessorArchitecture"] = ProcessorArchitecture; + } + + if (PowerShellVersion != null) + { + parsedMetadata["PowerShellVersion"] = PowerShellVersion; + } + + if (ClrVersion != null) + { + parsedMetadata["ClrVersion"] = ClrVersion; + } + + if (DotNetFrameworkVersion != null) + { + parsedMetadata["DotNetFrameworkVersion"] = DotNetFrameworkVersion; + } + + if (PowerShellHostName != null) + { + parsedMetadata["PowerShellHostName"] = PowerShellHostName; + } + + if (PowerShellHostVersion != null) + { + parsedMetadata["PowerShellHostVersion"] = PowerShellHostVersion; + } + + if (RequiredModules != null) + { + parsedMetadata["RequiredModules"] = RequiredModules; + } + + if (TypesToProcess != null) + { + parsedMetadata["TypesToProcess"] = TypesToProcess; + } + + if (FormatsToProcess != null) + { + parsedMetadata["FormatsToProcess"] = FormatsToProcess; + } + + if (ScriptsToProcess != null) + { + parsedMetadata["ScriptsToProcess"] = ScriptsToProcess; + } + + if (RequiredAssemblies != null) + { + parsedMetadata["RequiredAssemblies"] = RequiredAssemblies; + } + + if (FileList != null) + { + parsedMetadata["FileList"] = FileList; + } + + if (ModuleList != null) + { + parsedMetadata["ModuleList"] = ModuleList; + } + + if (FunctionsToExport != null) + { + parsedMetadata["FunctionsToExport"] = FunctionsToExport; + } + + if (AliasesToExport != null) + { + parsedMetadata["AliasesToExport"] = AliasesToExport; + } + + if (VariablesToExport != null) + { + parsedMetadata["VariablesToExport"] = VariablesToExport; + } + + if (CmdletsToExport != null) + { + parsedMetadata["CmdletsToExport"] = CmdletsToExport; + } + + if (DscResourcesToExport != null) + { + parsedMetadata["DscResourcesToExport"] = DscResourcesToExport; + } + + if (CompatiblePSEditions != null) + { + parsedMetadata["CompatiblePSEditions"] = CompatiblePSEditions; + } + + if (HelpInfoUri != null) + { + parsedMetadata["HelpInfoUri"] = HelpInfoUri; + } + + if (DefaultCommandPrefix != null) + { + parsedMetadata["DefaultCommandPrefix"] = DefaultCommandPrefix; + } + + if (Tags != null) + { + parsedMetadata["Tags"] = Tags; + } + + if (LicenseUri != null) + { + parsedMetadata["LicenseUri"] = LicenseUri; + } + + if (ProjectUri != null) + { + parsedMetadata["ProjectUri"] = ProjectUri; + } + + if (IconUri != null) + { + parsedMetadata["IconUri"] = IconUri; + } + + if (ReleaseNotes != null) + { + parsedMetadata["ReleaseNotes"] = ReleaseNotes; + } + + if (Prerelease != null) + { + parsedMetadata["Prerelease"] = Prerelease; + } + + if (RequireLicenseAcceptance != null) + { + parsedMetadata["RequireLicenseAcceptance"] = RequireLicenseAcceptance; + } + + if (ExternalModuleDependencies != null) + { + parsedMetadata["ExternalModuleDependencies"] = ExternalModuleDependencies; + } + + // create a tmp path to create the module manifest + string tmpParentPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString()); + try + { + Directory.CreateDirectory(tmpParentPath); + } + catch (Exception e) + { + ThrowTerminatingError( + new ErrorRecord( + new ArgumentException(e.Message), + "ErrorCreatingTempDir", + ErrorCategory.InvalidData, + this)); + } + + string tmpModuleManifestPath = System.IO.Path.Combine(tmpParentPath, System.IO.Path.GetFileName(resolvedManifestPath)); + parsedMetadata["Path"] = tmpModuleManifestPath; + WriteVerbose($"Temp path created for new module manifest is: {tmpModuleManifestPath}"); + + using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) + { + try + { + var results = PowerShellInvoker.InvokeScriptWithHost( + cmdlet: this, + script: @" + param ( + [hashtable] $params + ) + + New-ModuleManifest @params + ", + args: new object[] { parsedMetadata }, + out Exception terminatingErrors); + } + catch (Exception e) + { + ThrowTerminatingError( + new ErrorRecord( + new ArgumentException($"Error occured while running 'New-ModuleManifest': {e.Message}"), + "ErrorExecutingNewModuleManifest", + ErrorCategory.InvalidArgument, + this)); + } + } + + try + { + // Move to the new module manifest back to the original location + WriteVerbose($"Moving '{tmpModuleManifestPath}' to '{resolvedManifestPath}'"); + Utils.MoveFiles(tmpModuleManifestPath, resolvedManifestPath, overwrite: true); + } + finally { + // Clean up temp file if move fails + if (File.Exists(tmpModuleManifestPath)) + { + File.Delete(tmpModuleManifestPath); + } + } + } + + #endregion + } +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index af3687a1f..ae72d6b21 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -818,6 +818,63 @@ private static bool TryReadPSDataFile( } } + public static void ValidateModuleManifest(string moduleManifestPath, out string[] errorMsgs) + { + List errorMsgsList = new List(); + using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) + { + // use PowerShell cmdlet Test-ModuleManifest + // TODO: Test-ModuleManifest will throw an error if RequiredModules specifies a module that does not exist + // locally on the machine. Consider adding a -Syntax param to Test-ModuleManifest so that it only checks that + // the syntax is correct. In build/release pipelines for example, the modules listed under RequiredModules may + // not be locally available, but we still want to allow the user to publish. + Collection results = null; + try + { + results = pwsh.AddCommand("Test-ModuleManifest").AddParameter("Path", moduleManifestPath).Invoke(); + } + catch (Exception e) + { + errorMsgsList.Add($"Error occured while running 'Test-ModuleManifest': {e.Message}"); + + errorMsgs = errorMsgsList.ToArray(); + return; + } + + if (pwsh.HadErrors) + { + var message = string.Empty; + + if (results.Any()) + { + PSModuleInfo psModuleInfoObj = results[0].BaseObject as PSModuleInfo; + if (string.IsNullOrWhiteSpace(psModuleInfoObj.Author)) + { + message = "No author was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + } + else if (string.IsNullOrWhiteSpace(psModuleInfoObj.Description)) + { + message = "No description was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + } + else if (psModuleInfoObj.Version == null) + { + message = "No version or an incorrectly formatted version was provided in the module manifest. The module manifest must specify a version, author and description. Run 'Test-ModuleManifest' to validate the file."; + } + } + + if (string.IsNullOrEmpty(message) && pwsh.Streams.Error.Count > 0) + { + // This will handle version errors + message = $"{pwsh.Streams.Error[0].ToString()} Run 'Test-ModuleManifest' to validate the module manifest."; + } + + errorMsgsList.Add(message); + } + } + errorMsgs = errorMsgsList.ToArray(); + + } + #endregion #region Misc methods diff --git a/test/UpdateModuleManifest.Tests.ps1 b/test/UpdateModuleManifest.Tests.ps1 new file mode 100644 index 000000000..474607ae7 --- /dev/null +++ b/test/UpdateModuleManifest.Tests.ps1 @@ -0,0 +1,406 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$ProgressPreference = "SilentlyContinue" +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe 'Test Update-ModuleManifest' { + + BeforeEach { + # Create temp module manifest to be updated + $script:TempModulesPath = Join-Path $TestDrive "PSGet_$(Get-Random)" + $null = New-Item -Path $script:TempModulesPath -ItemType Directory -Force + + $script:UpdateModuleManifestName = "PSGetTestModule" + $script:UpdateModuleManifestBase = Join-Path $script:TempModulesPath $script:UpdateModuleManifestName + $null = New-Item -Path $script:UpdateModuleManifestBase -ItemType Directory -Force + + $script:testManifestPath = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath "$script:UpdateModuleManifestName.psd1" + } + + AfterEach { + RemoveItem "$script:TempModulesPath" + } + + It "Update module manifest given Path parameter" { + $description = "This is a PowerShellGet test" + New-ModuleManifest -Path $script:testManifestPath + Update-ModuleManifest -Path $script:testManifestPath -Description $description + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Description | Should -Be $description + } + + It "Update module manifest given Guid parameter" { + $Guid = [guid]::NewGuid() + New-ModuleManifest -Path $script:testManifestPath + Update-ModuleManifest -Path $script:testManifestPath -Guid $Guid + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Guid | Should -Be $Guid + } + + It "Update module manifest given Author parameter" { + $Author = "Test Author" + New-ModuleManifest -Path $script:testManifestPath + Update-ModuleManifest -Path $script:testManifestPath -Author $Author + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Author | Should -Be $Author + } + + It "Update module manifest given Description parameter" { + $Description = "PowerShellGet test description" + New-ModuleManifest -Path $script:testManifestPath + Update-ModuleManifest -Path $script:testManifestPath -Description $Description + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Description | Should -Be $Description + } + + It "Update module manifest given ModuleVersion parameter" { + $ModuleVersion = "7.0.0.0" + New-ModuleManifest -Path $script:testManifestPath + Update-ModuleManifest -Path $script:testManifestPath -ModuleVersion $ModuleVersion + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Version.ToString() | Should -Be $ModuleVersion + } + + It "Update module manifest given RequiredModules parameter" { + $requiredModuleName = 'PackageManagement' + $requiredModuleVersion = '1.0.0.0' + $RequiredModules = @(@{ModuleName = $requiredModuleName; ModuleVersion = $requiredModuleVersion }) + New-ModuleManifest -Path $script:testManifestPath + Update-ModuleManifest -Path $script:testManifestPath -RequiredModules $RequiredModules -Description "test" + + $results = Test-ModuleManifest -Path $script:testManifestPath + foreach ($module in $results.RequiredModules) + { + $module | Should -Be $requiredModuleName + $module.Version | Should -Be $requiredModuleVersion + } + } + + It "Update module manifest given Prerelease parameter" { + $Description = "Test Description" + $ModuleVersion = "1.0.0" + $Prerelease = "preview" + New-ModuleManifest -Path $script:testManifestPath -Description $Description -ModuleVersion $ModuleVersion + Update-ModuleManifest -Path $script:testManifestPath -Prerelease $Prerelease + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.Prerelease | Should -Be $Prerelease + } + + It "Update module manifest given ReleaseNotes parameter" { + $Description = "Test Description" + $ReleaseNotes = "Release notes for module." + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -ReleaseNotes $ReleaseNotes + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.ReleaseNotes | Should -Be $ReleaseNotes + } + + It "Update module manifest given Tags parameter" { + $Description = "Test Description" + $Tag1 = "tag1" + $Tag2 = "tag2" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -Tags $Tag1, $Tag2 + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.Tags | Should -Be @($Tag1, $Tag2) + } + + It "Update module manifest given ProjectUri parameter" { + $Description = "Test Description" + $ProjectUri = "https://www.testprojecturi.com/" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -ProjectUri $ProjectUri + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.ProjectUri | Should -Be $ProjectUri + } + + It "Update module manifest given LicenseUri parameter" { + $Description = "Test Description" + $LicenseUri = "https://www.testlicenseuri.com/" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -LicenseUri $LicenseUri + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.LicenseUri | Should -Be $LicenseUri + } + + It "Update module manifest given IconUri parameter" { + $Description = "Test Description" + $IconUri = "https://www.testiconuri.com/" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -IconUri $IconUri + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.IconUri | Should -Be $IconUri + } + + It "Update module manifest given RequireLicenseAcceptance parameter" { + $Description = "PowerShellGet test description" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -RequireLicenseAcceptance + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.RequireLicenseAcceptance | Should -Be $true + } + + It "Update module manifest given ExternalModuleDependencies parameter" { + $Description = "Test Description" + $ExternalModuleDep1 = "ExternalModuleDep1" + $ExternalModuleDep2 = "ExternalModuleDep2" + $ExternalModuleDep1FileName = "ExternalModuleDep1.psm1" + $ExternalModuleDep2FileName = "ExternalModuleDep2.psm1" + $ExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $ExternalModuleDep1FileName + $ExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $ExternalModuleDep2FileName + + $null = New-Item -Path $ExternalModuleDepPath1 -ItemType File -Force + $null = New-Item -Path $ExternalModuleDepPath2 -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description -NestedModules $ExternalModuleDep1, $ExternalModuleDep2 + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.ExternalModuleDependencies | Should -Be $null + + Update-ModuleManifest -Path $script:testManifestPath -ExternalModuleDependencies $ExternalModuleDep1, $ExternalModuleDep2 + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.PrivateData.PSData.ExternalModuleDependencies | Should -Be @($ExternalModuleDep1, $ExternalModuleDep2) + } + + It "Update module manifest given PowerShellHostName parameter" { + $Description = "PowerShellGet test description" + $PowerShellHostName = $Host.Name + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -PowerShellHostName $PowerShellHostName + + $results = Test-ModuleManifest -Path $script:testManifestPath -ErrorAction SilentlyContinue + $results.PowerShellHostName | Should -Be $PowerShellHostName + } + + It "Update module manifest given DefaultCommandPrefix parameter" { + $Description = "PowerShellGet test description" + $DefaultCommandPrefix = "testprefix" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -DefaultCommandPrefix $DefaultCommandPrefix + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Prefix | Should -Be $DefaultCommandPrefix + } + + It "Update module manifest given RootModule parameter" { + $Description = "Test Description" + $RootModuleName = $script:UpdateModuleManifestName + ".psm1" + $RootModulePath = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $RootModuleName + $null = New-Item -Path $RootModulePath -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -RootModule $RootModuleName + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.RootModule | Should -Be $RootModuleName + } + + It "Update module manifest given RequiredAssemblies parameter" { + $Description = "Test Description" + $RequiredAssembly1 = "RequiredAssembly1.dll" + $RequiredAssembly2 = "RequiredAssembly2.dll" + $RequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $RequiredAssembly1 + $RequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $RequiredAssembly2 + + $null = New-Item -Path $RequiredAssemblyPath1 -ItemType File -Force + $null = New-Item -Path $RequiredAssemblyPath2 -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -RequiredAssemblies $RequiredAssembly1, $RequiredAssembly2 + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.RequiredAssemblies | Should -Be @($RequiredAssembly1, $RequiredAssembly2) + } + + It "Update module manifest given NestedModules parameter" { + $Description = "Test Description" + $NestedModule1 = "NestedModule1" + $NestedModule2 = "NestedModule2" + $NestModuleFileName1 = "NestedModule1.dll" + $NestModuleFileName2 = "NestedModule2.dll" + $NestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $NestModuleFileName1 + $NestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $NestModuleFileName2 + + $null = New-Item -Path $NestedModulePath1 -ItemType File -Force + $null = New-Item -Path $NestedModulePath2 -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -NestedModules $NestedModule1, $NestedModule2 + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.NestedModules | Should -Be @($NestedModule1, $NestedModule2) + } + + It "Update module manifest given FileList parameter" { + $Description = "Test Description" + $FileList1 = "FileList1.cs" + $FileList2 = "FileList2.cs" + $FileListPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $FileList1 + $FileListPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $FileList2 + + $null = New-Item -Path $FileListPath1 -ItemType File -Force + $null = New-Item -Path $FileListPath2 -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -FileList $FileList1, $FileList2 + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.FileList | Should -Be @($FileListPath1, $FileListPath2) + } + + It "Update module manifest given TypesToProcess parameter" { + $Description = "Test Description" + $TypeFile = "TypeFile.ps1xml" + $TypeFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $TypeFile + + $null = New-Item -Path $TypeFilePath -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -TypesToProcess $TypeFile + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.ExportedTypeFiles | Should -Be $TypeFilePath + } + + It "Update module manifest given FormatsToProcess parameter" { + $Description = "Test Description" + $FormatFile = "FormatFile.ps1xml" + $FormatFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $FormatFile + + $null = New-Item -Path $FormatFilePath -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -FormatsToProcess $FormatFile + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.ExportedFormatFiles | Should -Be $FormatFilePath + } + + It "Update module manifest given ScriptsToProcess parameter" { + $Description = "Test Description" + $Script1 = "Script1.ps1" + $Script2 = "Script2.ps1" + $ScriptPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $Script1 + $ScriptPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:UpdateModuleManifestBase -ChildPath $Script2 + + $null = New-Item -Path $ScriptPath1 -ItemType File -Force + $null = New-Item -Path $ScriptPath2 -ItemType File -Force + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -ScriptsToProcess $Script1, $Script2 + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Scripts | Should -Be @($ScriptPath1, $ScriptPath2) + } + + It "Update module manifest given ProcessorArchitecture parameter" { + $Description = "Test Description" + $ProcessorArchitecture = [System.Reflection.ProcessorArchitecture]::Amd64 + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -ProcessorArchitecture $ProcessorArchitecture + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.ProcessorArchitecture | Should -Be $ProcessorArchitecture + } + + It "Update module manifest given ModuleList parameter" { + $Description = "Test Description" + $ModuleList1 = "PowerShellGet" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -ModuleList $ModuleList1 + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.ModuleList | Should -Be $ModuleList1 + } + + It "Update module manifest given CompanyName, Copyright, PowerShellHostVersion, ClrVersion, DotnetFrameworkVersion, PowerShellVersion, HelpInfoUri, and CompatiblePSEditions" { + $Description = "Test Description" + $CompanyName = "Test CompanyName" + $Copyright = "Test Copyright" + $PowerShellHostVersion = "5.0" + $ClrVersion = "1.0" + $DotnetFrameworkVersion = "2.0" + $PowerShellVersion = "5.1" + $HelpInfoUri = "https://www.testhelpinfouri.com/" + $CompatiblePSEditions = @("Desktop", "Core") + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath ` + -CompanyName $CompanyName ` + -Copyright $Copyright ` + -PowerShellVersion $PowerShellVersion ` + -ClrVersion $ClrVersion ` + -DotNetFrameworkVersion $DotnetFrameworkVersion ` + -PowerShellHostVersion $PowerShellHostVersion ` + -HelpInfoUri $HelpInfoUri ` + -CompatiblePSEditions $CompatiblePSEditions + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.CompanyName | Should -Be $CompanyName + $results.Copyright | Should -Be $Copyright + $results.PowerShellVersion | Should -Be $PowerShellVersion + $results.ClrVersion | Should -Be $ClrVersion + $results.DotnetFrameworkVersion | Should -Be $DotnetFrameworkVersion + $results.PowerShellHostVersion | Should -Be $PowerShellHostVersion + $results.HelpInfoUri | Should -Be $HelpInfoUri + $results.CompatiblePSEditions | Should -Be $CompatiblePSEditions + } + + It "Update module manifest given FunctionsToExport, AliasesToExport, and VariablesToExport parameters" { + $Description = "Test Description" + $ExportedFunctions = "FunctionToExport1", "FunctionToExport2" + $ExportedAliases = "AliasToExport1", "AliasToExport2" + $ExportedVariables = "VariablesToExport1", "Variables2Export2" + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath ` + -FunctionsToExport $ExportedFunctions ` + -AliasesToExport $ExportedAliases ` + -VariablesToExport $ExportedVariables + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.ExportedFunctions.Keys | Should -Be $ExportedFunctions + $results.ExportedAliases.Keys | Should -Be $ExportedAliases + $results.ExportedVariables.Keys | Should -Be $ExportedVariables + } + + It "Update module manifest given CmdletsToExport parameters" { + $Description = "Test Description" + $CmdletToExport1 = "CmdletToExport1" + $CmdletToExport2 = "CmdletToExport2" + + New-ModuleManifest -Path $script:testManifestPath -Description $Description + Update-ModuleManifest -Path $script:testManifestPath -CmdletsToExport $CmdletToExport1, $CmdletToExport2 + + $results = Get-Content -Path $script:testManifestPath -Raw + $results.Contains($CmdletToExport1) | Should -Be $true + $results.Contains($CmdletToExport2) | Should -Be $true + } + + It "Update module manifest should not overwrite over old data unless explcitly specified" { + $Description = "Test Description" + $ModuleVersion = "2.0.0" + $Author = "Leto Atriedes" + $ProjectUri = "https://www.arrakis.gov/" + $Prerelease = "Preview" + New-ModuleManifest -Path $script:testManifestPath -Description $Description -ModuleVersion $ModuleVersion -Author $Author -ProjectUri $ProjectUri + Update-ModuleManifest -Path $script:testManifestPath -Prerelease $Prerelease + + $results = Test-ModuleManifest -Path $script:testManifestPath + $results.Author | Should -Be $Author + $results.PrivateData.PSData.ProjectUri | Should -Be $ProjectUri + $results.PrivateData.PSData.Prerelease | Should -Be $Prerelease + } +} + From bdebc81be103098980bc8afa9d79438bd81aeb94 Mon Sep 17 00:00:00 2001 From: "msftbot[bot]" <48340428+msftbot[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 17:44:05 -0700 Subject: [PATCH 169/276] Add `.github/fabricbot.json` (#682) --- .github/fabricbot.json | 591 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 591 insertions(+) create mode 100644 .github/fabricbot.json diff --git a/.github/fabricbot.json b/.github/fabricbot.json new file mode 100644 index 000000000..fe8701620 --- /dev/null +++ b/.github/fabricbot.json @@ -0,0 +1,591 @@ +{ + "version": "1.0", + "tasks": [ + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "taskName": "Add needs triage label to new issues", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isPartOfProject", + "parameters": {} + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isAssignedToSomeone", + "parameters": {} + } + ] + } + ] + }, + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "Needs-Triage" + } + } + ], + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ] + }, + "id": "64U3f3byk4NS2gkx5dHo8" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueCommentResponder", + "version": "1.0", + "config": { + "taskName": "Replace needs author feedback label with needs attention label when the author comments on an issue", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "created" + } + }, + { + "name": "isActivitySender", + "parameters": { + "user": { + "type": "author" + } + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs-Repro-Info" + } + }, + { + "name": "isOpen", + "parameters": {} + } + ] + }, + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "Needs-Attention :wave:" + } + }, + { + "name": "removeLabel", + "parameters": { + "label": "Needs-Repro-Info" + } + } + ], + "eventType": "issue", + "eventNames": [ + "issue_comment" + ] + }, + "id": "ow4oIStiYjznkM99ee-GE" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "taskName": "Remove no recent activity label from issues", + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + }, + { + "name": "hasLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + } + ], + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ] + }, + "id": "Dabpw4dOhjizI8p6vuS71" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueCommentResponder", + "version": "1.0", + "config": { + "taskName": "Remove no recent activity label when an issue is commented on", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + } + ], + "eventType": "issue", + "eventNames": [ + "issue_comment" + ] + }, + "id": "MYGvM1vcc7yIps9F_zIuB" + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "config": { + "taskName": "Close stale issues", + "frequency": [ + { + "weekDay": 0, + "hours": [ + 1, + 7, + 13, + 19 + ] + }, + { + "weekDay": 1, + "hours": [ + 1, + 7, + 13, + 19 + ] + }, + { + "weekDay": 2, + "hours": [ + 1, + 7, + 13, + 19 + ] + }, + { + "weekDay": 3, + "hours": [ + 1, + 7, + 13, + 19 + ] + }, + { + "weekDay": 4, + "hours": [ + 1, + 7, + 13, + 19 + ] + }, + { + "weekDay": 5, + "hours": [ + 1, + 7, + 13, + 19 + ] + }, + { + "weekDay": 6, + "hours": [ + 1, + 7, + 13, + 19 + ] + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs-Repro-Info" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 3 + } + } + ], + "actions": [ + { + "name": "closeIssue", + "parameters": {} + } + ] + }, + "id": "epz-looI4jf57oBVjLU--" + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "config": { + "taskName": "Add no recent activity label to issues", + "frequency": [ + { + "weekDay": 0, + "hours": [ + 2, + 8, + 14, + 20 + ] + }, + { + "weekDay": 1, + "hours": [ + 2, + 8, + 14, + 20 + ] + }, + { + "weekDay": 2, + "hours": [ + 2, + 8, + 14, + 20 + ] + }, + { + "weekDay": 3, + "hours": [ + 2, + 8, + 14, + 20 + ] + }, + { + "weekDay": 4, + "hours": [ + 2, + 8, + 14, + 20 + ] + }, + { + "weekDay": 5, + "hours": [ + 2, + 8, + 14, + 20 + ] + }, + { + "weekDay": 6, + "hours": [ + 2, + 8, + 14, + 20 + ] + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs-Repro-Info" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 4 + } + }, + { + "name": "noLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + } + ], + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "Status-No Recent Activity" + } + }, + { + "name": "addReply", + "parameters": { + "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**." + } + } + ] + }, + "id": "nDV4O1bBVF-24-i7FJhLa" + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "config": { + "taskName": "Close duplicate issues", + "frequency": [ + { + "weekDay": 0, + "hours": [ + 3, + 9, + 15, + 21 + ] + }, + { + "weekDay": 1, + "hours": [ + 3, + 9, + 15, + 21 + ] + }, + { + "weekDay": 2, + "hours": [ + 3, + 9, + 15, + 21 + ] + }, + { + "weekDay": 3, + "hours": [ + 3, + 9, + 15, + 21 + ] + }, + { + "weekDay": 4, + "hours": [ + 3, + 9, + 15, + 21 + ] + }, + { + "weekDay": 5, + "hours": [ + 3, + 9, + 15, + 21 + ] + }, + { + "weekDay": 6, + "hours": [ + 3, + 9, + 15, + 21 + ] + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Resolution-Duplicate" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 1 + } + } + ], + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes." + } + }, + { + "name": "closeIssue", + "parameters": {} + } + ] + }, + "id": "uwpGFYfdNjH8NPSXmljnk" + }, + { + "taskType": "trigger", + "capabilityId": "InPrLabel", + "subCapability": "InPrLabel", + "version": "1.0", + "config": { + "taskName": "Add 'In-PR' label on issue when an open pull request is targeting it", + "inPrLabelText": "Status: In PR", + "fixedLabelText": "Status: Fixed", + "fixedLabelEnabled": true + }, + "id": "A3RoD09RLatD611QQx2wW" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "PesPknG_mSz7cQr3XRnem", + "config": { + "conditions": { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "Resolution-Answered" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "Resolution-External" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "Resolution-Fixed" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "Resolution-Inactive" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "Close resolved issues", + "actions": [ + { + "name": "closeIssue", + "parameters": {} + } + ] + } + } + ], + "userGroups": [] +} From 0c6942f7f6d8ff7b2cbaa7b954b5654de98b99a8 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 13 Jul 2022 13:45:14 -0700 Subject: [PATCH 170/276] Add some code clean up changes (#703) * Some minor code clean up * Update comments --- src/code/InstallHelper.cs | 6 ++++- src/code/Utils.cs | 50 +++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 5f2a7b06f..35fea684c 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -501,7 +501,11 @@ private List InstallPackage( : _pathsToInstallPkg.Find(path => path.EndsWith("Scripts", StringComparison.InvariantCultureIgnoreCase)); } - if (_authenticodeCheck && !AuthenticodeSignature.CheckAuthenticodeSignature(pkg.Name, tempDirNameVersion, _versionRange, _pathsToSearch, installPath, _cmdletPassedIn, out ErrorRecord errorRecord)) + if (_authenticodeCheck && !AuthenticodeSignature.CheckAuthenticodeSignature( + pkg.Name, + tempDirNameVersion, + _cmdletPassedIn, + out ErrorRecord errorRecord)) { ThrowTerminatingError(errorRecord); } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ae72d6b21..f19861847 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -819,7 +819,7 @@ private static bool TryReadPSDataFile( } public static void ValidateModuleManifest(string moduleManifestPath, out string[] errorMsgs) - { + { List errorMsgsList = new List(); using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create()) { @@ -866,11 +866,11 @@ public static void ValidateModuleManifest(string moduleManifestPath, out string[ { // This will handle version errors message = $"{pwsh.Streams.Error[0].ToString()} Run 'Test-ModuleManifest' to validate the module manifest."; - } - + } + errorMsgsList.Add(message); } - } + } errorMsgs = errorMsgsList.ToArray(); } @@ -1236,7 +1236,11 @@ internal static class AuthenticodeSignature { #region Methods - internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNameVersion, VersionRange versionRange, List pathsToSearch, string installPath, PSCmdlet cmdletPassedIn, out ErrorRecord errorRecord) + internal static bool CheckAuthenticodeSignature( + string pkgName, + string tempDirNameVersion, + PSCmdlet cmdletPassedIn, + out ErrorRecord errorRecord) { errorRecord = null; @@ -1246,16 +1250,16 @@ internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNa return true; } - // Check that the catalog file is signed properly + // First check if the files are catalog signed. string catalogFilePath = Path.Combine(tempDirNameVersion, pkgName + ".cat"); if (File.Exists(catalogFilePath)) { - // Run catalog validation - Collection TestFileCatalogResult = new Collection(); + // Run catalog validation. + Collection TestFileCatalogResult; string moduleBasePath = tempDirNameVersion; try { - // By default "Test-FileCatalog will look through all files in the provided directory, -FilesToSkip allows us to ignore specific files + // By default "Test-FileCatalog will look through all files in the provided directory, -FilesToSkip allows us to ignore specific files. TestFileCatalogResult = cmdletPassedIn.InvokeCommand.InvokeScript( script: @"param ( [string] $moduleBasePath, @@ -1283,7 +1287,7 @@ internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNa return false; } - bool catalogValidation = (TestFileCatalogResult[0] != null) ? (bool)TestFileCatalogResult[0].BaseObject : false; + bool catalogValidation = TestFileCatalogResult.Count > 0 ? (bool)TestFileCatalogResult[0].BaseObject : false; if (!catalogValidation) { var exMessage = String.Format("The catalog file '{0}' is invalid.", pkgName + ".cat"); @@ -1292,13 +1296,16 @@ internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNa errorRecord = new ErrorRecord(ex, "TestFileCatalogError", ErrorCategory.InvalidResult, cmdletPassedIn); return false; } + + return true; } - Collection authenticodeSignature = new Collection(); + // Otherwise check for signatures on individual files. + Collection authenticodeSignatures; try { string[] listOfExtensions = { "*.ps1", "*.psd1", "*.psm1", "*.mof", "*.cat", "*.ps1xml" }; - authenticodeSignature = cmdletPassedIn.InvokeCommand.InvokeScript( + authenticodeSignatures = cmdletPassedIn.InvokeCommand.InvokeScript( script: @"param ( [string] $tempDirNameVersion, [string[]] $listOfExtensions @@ -1315,20 +1322,17 @@ internal static bool CheckAuthenticodeSignature(string pkgName, string tempDirNa return false; } - // If the authenticode signature is not valid, return false - if (authenticodeSignature.Any() && authenticodeSignature[0] != null) + // If any file authenticode signatures are not valid, return false. + foreach (var signatureObject in authenticodeSignatures) { - foreach (var sign in authenticodeSignature) + Signature signature = (Signature)signatureObject.BaseObject; + if (!signature.Status.Equals(SignatureStatus.Valid)) { - Signature signature = (Signature)sign.BaseObject; - if (!signature.Status.Equals(SignatureStatus.Valid)) - { - var exMessage = String.Format("The signature for '{0}' is '{1}.", pkgName, signature.Status.ToString()); - var ex = new ArgumentException(exMessage); - errorRecord = new ErrorRecord(ex, "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); + var exMessage = String.Format("The signature for '{0}' is '{1}.", pkgName, signature.Status.ToString()); + var ex = new ArgumentException(exMessage); + errorRecord = new ErrorRecord(ex, "GetAuthenticodeSignatureError", ErrorCategory.InvalidResult, cmdletPassedIn); - return false; - } + return false; } } From 9a06d54151bd302f5c9c7972c1a8c1e208a112f4 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 19 Jul 2022 13:20:55 -0700 Subject: [PATCH 171/276] Downgrade NuGet client packages to v5.11.2 (#719) --- src/code/PowerShellGet.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index e9d2e9a88..68ada6965 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -15,12 +15,12 @@ - - - - - - + + + + + + From 6e995f271e04a1c3a948bdb75af2a982dc81725a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 20 Jul 2022 09:27:36 -0400 Subject: [PATCH 172/276] Script info cmdlets with Line parsing and class implementations (#708) Script info cmdlets with Line parsing and class implementations --- src/PowerShellGet.psd1 | 3 + src/code/NewPSScriptFileInfo.cs | 258 +++++++++ src/code/PSScriptContents.cs | 117 +++++ src/code/PSScriptFileInfo.cs | 492 ++++++++++++++++++ src/code/PSScriptHelp.cs | 325 ++++++++++++ src/code/PSScriptMetadata.cs | 458 ++++++++++++++++ src/code/PSScriptRequires.cs | 144 +++++ src/code/TestPSScriptFileInfo.cs | 85 +++ src/code/UpdatePSScriptFileInfo.cs | 319 ++++++++++++ src/code/Utils.cs | 191 +++++++ test/NewPSScriptFileInfo.Tests.ps1 | 356 ++++++------- test/TestPSScriptFileInfo.Tests.ps1 | 60 +++ test/TestPSScriptInfo.Tests.ps1 | 42 -- test/UpdatePSScriptFileInfo.Tests.ps1 | 314 +++++++++++ test/UpdatePSScriptInfo.Tests.ps1 | 415 --------------- .../testScripts/ScriptWithSignature.ps1 | 75 +++ 16 files changed, 2990 insertions(+), 664 deletions(-) create mode 100644 src/code/NewPSScriptFileInfo.cs create mode 100644 src/code/PSScriptContents.cs create mode 100644 src/code/PSScriptFileInfo.cs create mode 100644 src/code/PSScriptHelp.cs create mode 100644 src/code/PSScriptMetadata.cs create mode 100644 src/code/PSScriptRequires.cs create mode 100644 src/code/TestPSScriptFileInfo.cs create mode 100644 src/code/UpdatePSScriptFileInfo.cs create mode 100644 test/TestPSScriptFileInfo.Tests.ps1 delete mode 100644 test/TestPSScriptInfo.Tests.ps1 create mode 100644 test/UpdatePSScriptFileInfo.Tests.ps1 delete mode 100644 test/UpdatePSScriptInfo.Tests.ps1 create mode 100644 test/testFiles/testScripts/ScriptWithSignature.ps1 diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 2c9b767b2..2b4953d39 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -21,6 +21,9 @@ 'Register-PSResourceRepository', 'Save-PSResource', 'Set-PSResourceRepository', + 'New-PSScriptFileInfo', + 'Test-PSScriptFileInfo', + 'Update-PSScriptFileInfo', 'Publish-PSResource', 'Uninstall-PSResource', 'Unregister-PSResourceRepository', diff --git a/src/code/NewPSScriptFileInfo.cs b/src/code/NewPSScriptFileInfo.cs new file mode 100644 index 000000000..0e1bf0031 --- /dev/null +++ b/src/code/NewPSScriptFileInfo.cs @@ -0,0 +1,258 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.IO; +using System.Management.Automation; +using Microsoft.PowerShell.Commands; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Creates a new .ps1 file with script information required for publishing a script. + /// + [Cmdlet(VerbsCommon.New, "PSScriptFileInfo")] + public sealed class NewPSScriptFileInfo : PSCmdlet + { + #region Parameters + + /// + /// The path the .ps1 script info file will be created at. + /// + [Parameter(Position = 0, Mandatory = true)] + [ValidateNotNullOrEmpty] + public string FilePath { get; set; } + + /// + /// The version of the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string Version { get; set; } + + /// + /// The author of the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string Author { get; set; } + + /// + /// The description of the script. + /// + [Parameter(Mandatory = true)] + [ValidateNotNullOrEmpty()] + public string Description { get; set; } + + /// + /// A unique identifier for the script. The GUID can be used to distinguish among scripts with the same name. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public Guid Guid { get; set; } + + /// + /// The name of the company owning the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string CompanyName { get; set; } + + /// + /// The copyright statement for the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string Copyright { get; set; } + + /// + /// The list of modules required by the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public Hashtable[] RequiredModules { get; set; } + + /// + /// The list of external module dependencies taken by this script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] ExternalModuleDependencies { get; set; } + + /// + /// The list of scripts required by the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] RequiredScripts { get; set; } + + /// + /// The list of external script dependencies taken by this script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] ExternalScriptDependencies { get; set; } + + /// + /// The tags associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] Tags { get; set; } + + /// + /// The Uri for the project associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string ProjectUri { get; set; } + + /// + /// The Uri for the license associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string LicenseUri { get; set; } + + /// + /// The Uri for the icon associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string IconUri { get; set; } + + /// + /// The release notes for the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string ReleaseNotes { get; set; } + + /// + /// The private data associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string PrivateData { get; set; } + + /// + /// If used with Path parameter and .ps1 file specified at the path exists, it rewrites the file. + /// + [Parameter] + public SwitchParameter Force { get; set; } + + #endregion + + #region Methods + + protected override void EndProcessing() + { + // validate Uri related parameters passed in as strings + Uri projectUri = null; + if (!String.IsNullOrEmpty(ProjectUri) && !Utils.TryCreateValidUri(uriString: ProjectUri, + cmdletPassedIn: this, + uriResult: out projectUri, + errorRecord: out ErrorRecord projectErrorRecord)) + { + ThrowTerminatingError(projectErrorRecord); + } + + Uri licenseUri = null; + if (!String.IsNullOrEmpty(LicenseUri) && !Utils.TryCreateValidUri(uriString: LicenseUri, + cmdletPassedIn: this, + uriResult: out licenseUri, + errorRecord: out ErrorRecord licenseErrorRecord)) + { + ThrowTerminatingError(licenseErrorRecord); + } + + Uri iconUri = null; + if (!String.IsNullOrEmpty(IconUri) && !Utils.TryCreateValidUri(uriString: IconUri, + cmdletPassedIn: this, + uriResult: out iconUri, + errorRecord: out ErrorRecord iconErrorRecord)) + { + ThrowTerminatingError(iconErrorRecord); + } + + if (!FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + { + var exMessage = "Path needs to end with a .ps1 file. Example: C:/Users/john/x/MyScript.ps1"; + var ex = new ArgumentException(exMessage); + var InvalidPathError = new ErrorRecord(ex, "InvalidPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidPathError); + } + + var resolvedFilePath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(FilePath); + if (String.IsNullOrEmpty(resolvedFilePath)) + { + var exMessage = "Error: Could not resolve provided Path argument into a single path."; + var ex = new PSArgumentException(exMessage); + var InvalidPathArgumentError = new ErrorRecord(ex, "InvalidPathArgumentError", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidPathArgumentError); + } + + if (File.Exists(resolvedFilePath) && !Force) + { + // .ps1 file at specified location already exists and Force parameter isn't used to rewrite the file + var exMessage = ".ps1 file at specified path already exists. Specify a different location or use -Force parameter to overwrite the .ps1 file."; + var ex = new ArgumentException(exMessage); + var ScriptAtPathAlreadyExistsError = new ErrorRecord(ex, "ScriptAtPathAlreadyExists", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(ScriptAtPathAlreadyExistsError); + } + + ModuleSpecification[] validatedRequiredModuleSpecifications = Array.Empty(); + if (RequiredModules != null && RequiredModules.Length > 0) + { + if (!Utils.TryCreateModuleSpecification( + moduleSpecHashtables: RequiredModules, + out validatedRequiredModuleSpecifications, + out ErrorRecord[] moduleSpecErrors)) + { + foreach (ErrorRecord err in moduleSpecErrors) + { + WriteError(err); + } + + return; + } + } + + PSScriptFileInfo scriptInfo = new PSScriptFileInfo( + version: Version, + guid: Guid, + author: Author, + companyName: CompanyName, + copyright: Copyright, + tags: Tags, + licenseUri: licenseUri, + projectUri: projectUri, + iconUri: iconUri, + requiredModules: validatedRequiredModuleSpecifications, + externalModuleDependencies: ExternalModuleDependencies, + requiredScripts: RequiredScripts, + externalScriptDependencies: ExternalScriptDependencies, + releaseNotes: ReleaseNotes, + privateData: PrivateData, + description: Description); + + if (!scriptInfo.TryCreateScriptFileInfoString( + psScriptFileContents: out string[] psScriptFileContents, + errors: out ErrorRecord[] errors)) + { + foreach (ErrorRecord err in errors) + { + WriteError(err); + } + + return; + } + + File.WriteAllLines(resolvedFilePath, psScriptFileContents); + } + + #endregion + } +} diff --git a/src/code/PSScriptContents.cs b/src/code/PSScriptContents.cs new file mode 100644 index 000000000..c04f1dc49 --- /dev/null +++ b/src/code/PSScriptContents.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a PSScriptFileInfo (representing a .ps1 file contents). + /// + public sealed class PSScriptContents + { + #region Properties + + /// + /// End of file contents for the .ps1 file. + /// + public string[] EndOfFileContents { get; private set; } = Utils.EmptyStrArray; + + /// + /// End of file contents for the .ps1 file. + /// + public bool ContainsSignature { get; set; } = false; + + #endregion + + #region Private Members + + private const string signatureStartString = "# SIG # Begin signature block"; + private int _signatureStartIndex = -1; + + #endregion + + #region Constructor + + /// + /// This constructor takes end of file contents as a string and checks if it has a signature. + /// + public PSScriptContents(string[] endOfFileContents) + { + EndOfFileContents = endOfFileContents; + ContainsSignature = CheckForSignature(); + } + + /// + /// This constructor creates a PSScriptContents instance with default values for its properties. + /// The calling method, like PSScriptContents.ParseContent() could then populate the properties. + /// + internal PSScriptContents() {} + + #endregion + + #region Internal Methods + + /// + /// Parses end of file contents as a string from the file lines passed in + /// and sets property indicating whether those contents contain a signature. + /// + internal void ParseContent(string[] commentLines) + { + if (commentLines.Length != 0) + { + EndOfFileContents = commentLines; + ContainsSignature = CheckForSignature(); + } + } + + /// + /// This function is called by PSScriptFileInfo.TryCreateScriptFileInfoString(), + /// by the New-PSScriptFileInfo cmdlet (in which case EndOfFileContents is an empty string so there's no signature that'll get removed) + /// or by Update-PSScriptFileInfo cmdlet (in which case EndOfFileContents may not be empty and may contain a signature. + /// When emitting contents, any file signature is always removed because it is invalidated when the content is updated. + /// + internal string[] EmitContent() + { + RemoveSignatureString(); + return EndOfFileContents; + } + + #endregion + + #region Private Methods + + /// + /// Checks if the end of file contents contain a signature. + /// + private bool CheckForSignature() + { + for (int i = 0; i < EndOfFileContents.Length; i++) + { + if (String.Equals(EndOfFileContents[i], signatureStartString, StringComparison.InvariantCultureIgnoreCase)) + { + _signatureStartIndex = i; + } + } + + return _signatureStartIndex != -1; + } + + /// + /// Removes the signature from EndOfFileContents property + /// as the signature would be invalidated during update. + /// + private void RemoveSignatureString() + { + if (ContainsSignature) + { + string[] newEndOfFileContents = new string[EndOfFileContents.Length - _signatureStartIndex]; + Array.Copy(EndOfFileContents, newEndOfFileContents, _signatureStartIndex); + EndOfFileContents = newEndOfFileContents; + + ContainsSignature = false; + } + } + #endregion + } +} diff --git a/src/code/PSScriptFileInfo.cs b/src/code/PSScriptFileInfo.cs new file mode 100644 index 000000000..f3c4f3b5b --- /dev/null +++ b/src/code/PSScriptFileInfo.cs @@ -0,0 +1,492 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Management.Automation; +using System.Linq; +using Microsoft.PowerShell.Commands; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a PSScriptFileInfo (representing a .ps1 file contents). + /// + public sealed class PSScriptFileInfo + { + #region Properties + public PSScriptMetadata ScriptMetadataComment { get; set; } + + public PSScriptHelp ScriptHelpComment { get; set; } + + public PSScriptRequires ScriptRequiresComment { get; set; } + + public PSScriptContents ScriptContent { get; set; } + + #endregion + + #region Constructor + + /// + /// This constructor takes metadata values that could have been passed in by the calling cmdlet + /// and uses those to create associated script class properties (PSScriptMetadata, PSScriptHelp, PSScriptRequires, PSScriptContents) + /// + public PSScriptFileInfo( + string version, + Guid guid, + string author, + string companyName, + string copyright, + string[] tags, + Uri licenseUri, + Uri projectUri, + Uri iconUri, + ModuleSpecification[] requiredModules, + string[] externalModuleDependencies, + string[] requiredScripts, + string[] externalScriptDependencies, + string releaseNotes, + string privateData, + string description) + { + PSScriptMetadata scriptMetadataComment = new PSScriptMetadata( + version, + guid, + author, + companyName, + copyright, + tags, + licenseUri, + projectUri, + iconUri, + externalModuleDependencies, + requiredScripts, + externalScriptDependencies, + releaseNotes, + privateData); + + PSScriptHelp scriptHelpComment = new PSScriptHelp(description); + PSScriptRequires scriptRequiresComment = new PSScriptRequires(requiredModules); + PSScriptContents scriptRemainingContent = new PSScriptContents(Utils.EmptyStrArray); + + ScriptMetadataComment = scriptMetadataComment; + ScriptHelpComment = scriptHelpComment; + ScriptRequiresComment = scriptRequiresComment; + ScriptContent = scriptRemainingContent; + } + + /// + /// This constructor takes script class properties' values that could have been passed in by the calling internal methods. + /// + public PSScriptFileInfo( + PSScriptMetadata scriptMetadataComment, + PSScriptHelp scriptHelpComment, + PSScriptRequires scriptRequiresComment, + PSScriptContents scriptRemainingContent + ) + { + ScriptMetadataComment = scriptMetadataComment; + ScriptHelpComment = scriptHelpComment; + ScriptRequiresComment = scriptRequiresComment; + ScriptContent = scriptRemainingContent; + } + + #endregion + + #region Internal Static Methods + + /// + /// Parses .ps1 file contents for PSScriptInfo, PSHelpInfo, Requires comments + /// + internal static bool TryParseScriptFileContents( + string scriptFileInfoPath, + ref List psScriptInfoCommentContent, + ref List helpInfoCommentContent, + ref List requiresCommentContent, + ref string[] remainingFileContent, + out ErrorRecord error) + { + error= null; + + psScriptInfoCommentContent = new List(); + helpInfoCommentContent = new List(); + requiresCommentContent = new List(); + remainingFileContent = Utils.EmptyStrArray; + + string[] fileContents = File.ReadAllLines(scriptFileInfoPath); + + bool reachedPSScriptInfoCommentEnd = false; + bool reachedHelpInfoCommentEnd = false; + + int i = 0; + int endOfFileContentsStartIndex = 0; + while (i < fileContents.Length) + { + string line = fileContents[i]; + + if (line.StartsWith("<#PSScriptInfo")) + { + int j = i + 1; // start at the next line + // keep grabbing lines until we get to closing #> + while (j < fileContents.Length) + { + string blockLine = fileContents[j]; + if (blockLine.StartsWith("#>")) + { + reachedPSScriptInfoCommentEnd = true; + i = j + 1; + break; + } + + psScriptInfoCommentContent.Add(blockLine); + j++; + } + + if (!reachedPSScriptInfoCommentEnd) + { + var message = String.Format("Could not parse '{0}' as a PowerShell script file due to missing the closing '#>' for <#PSScriptInfo comment block", scriptFileInfoPath); + var ex = new InvalidOperationException(message); + error = new ErrorRecord(ex, "MissingEndBracketToPSScriptInfoParseError", ErrorCategory.ParserError, null); + return false; + } + } + else if (line.StartsWith("<#")) + { + // The next comment block must be the help comment block (containing description) + // keep grabbing lines until we get to closing #> + int j = i + 1; + while (j < fileContents.Length) + { + string blockLine = fileContents[j]; + if (blockLine.StartsWith("#>")) + { + reachedHelpInfoCommentEnd = true; + i = j + 1; + endOfFileContentsStartIndex = i; + break; + } + + helpInfoCommentContent.Add(blockLine); + j++; + } + + if (!reachedHelpInfoCommentEnd) + { + var message = String.Format("Could not parse '{0}' as a PowerShell script file due to missing the closing '#>' for HelpInfo comment block", scriptFileInfoPath); + var ex = new InvalidOperationException(message); + error = new ErrorRecord(ex, "MissingEndBracketToHelpInfoCommentParseError", ErrorCategory.ParserError, null); + return false; + } + } + else if (line.StartsWith("#Requires")) + { + requiresCommentContent.Add(line); + i++; + } + else if (endOfFileContentsStartIndex != 0) + { + break; + } + else + { + // this would be newlines between blocks, or if there was other (unexpected) data between PSScriptInfo, Requires, and HelpInfo blocks + i++; + } + } + + if (endOfFileContentsStartIndex != 0 && (endOfFileContentsStartIndex < fileContents.Length)) + { + // from this line to fileContents.Length is the endOfFileContents, if any + remainingFileContent = new string[fileContents.Length - endOfFileContentsStartIndex]; + + Array.Copy(fileContents, endOfFileContentsStartIndex, remainingFileContent, 0, (fileContents.Length - endOfFileContentsStartIndex)); + } + + if (psScriptInfoCommentContent.Count() == 0) + { + // check for file not containing '<#PSScriptInfo ... #>' comment + var message = String.Format("Could not parse '{0}' as a PowerShell script due to it missing '<#PSScriptInfo #> block", scriptFileInfoPath); + var ex = new InvalidOperationException(message); + error = new ErrorRecord(ex, "MissingEndBracketToHelpInfoCommentParseError", ErrorCategory.ParserError, null); + return false; + } + + if (helpInfoCommentContent.Count() == 0) + { + // check for file not containing HelpInfo comment + var message = String.Format("Could not parse '{0}' as a PowerShell script due to it missing HelpInfo comment block", scriptFileInfoPath); + var ex = new InvalidOperationException(message); + error = new ErrorRecord(ex, "missingHelpInfoCommentError", ErrorCategory.ParserError, null); + return false; + } + + return true; + } + + /// + /// Populates script info classes (PSScriptMetadata, PSScriptHelp, PSScriptRequires, PSScriptContents) with previosuly + /// parsed metadata from the ps1 file. + /// + internal static bool TryPopulateScriptClassesWithParsedContent( + List psScriptInfoCommentContent, + List helpInfoCommentContent, + List requiresCommentContent, + string[] remainingFileContent, + out PSScriptMetadata currentMetadata, + out PSScriptHelp currentHelpInfo, + out PSScriptRequires currentRequiresComment, + out PSScriptContents currentEndOfFileContents, + out ErrorRecord[] errors, + out string[] verboseMsgs) + { + List errorsList = new List(); + + bool parsedContentSuccessfully = true; + + currentMetadata = new PSScriptMetadata(); + if (!currentMetadata.ParseContentIntoObj( + commentLines: psScriptInfoCommentContent.ToArray(), + out ErrorRecord[] metadataErrors, + out verboseMsgs)) + { + errorsList.AddRange(metadataErrors); + parsedContentSuccessfully = false; + } + + currentHelpInfo = new PSScriptHelp(); + if (!currentHelpInfo.ParseContentIntoObj( + commentLines: helpInfoCommentContent.ToArray(), + out ErrorRecord helpError)) + { + errorsList.Add(helpError); + parsedContentSuccessfully = false; + } + + currentRequiresComment = new PSScriptRequires(); + if (!currentRequiresComment.ParseContentIntoObj( + commentLines: requiresCommentContent.ToArray(), + out ErrorRecord[] requiresErrors)) + { + errorsList.AddRange(requiresErrors); + parsedContentSuccessfully = false; + } + + currentEndOfFileContents = new PSScriptContents(); + currentEndOfFileContents.ParseContent(commentLines: remainingFileContent); + + errors = errorsList.ToArray(); + return parsedContentSuccessfully; + } + + /// + /// Tests .ps1 file for validity + /// + internal static bool TryTestPSScriptFile( + string scriptFileInfoPath, + out PSScriptFileInfo parsedScript, + out ErrorRecord[] errors, + // this is for Uri errors, which aren't required by script but we check if those in the script aren't valid Uri's. + out string[] verboseMsgs) + { + verboseMsgs = Utils.EmptyStrArray; + List errorsList = new List(); + parsedScript = null; + + List psScriptInfoCommentContent = new List(); + List helpInfoCommentContent = new List(); + List requiresCommentContent = new List(); + string[] remainingFileContent = Utils.EmptyStrArray; + + // Parse .ps1 contents out of file into list objects + if (!TryParseScriptFileContents( + scriptFileInfoPath: scriptFileInfoPath, + psScriptInfoCommentContent: ref psScriptInfoCommentContent, + helpInfoCommentContent: ref helpInfoCommentContent, + requiresCommentContent: ref requiresCommentContent, + remainingFileContent: ref remainingFileContent, + out ErrorRecord parseError)) + { + errors = new ErrorRecord[]{parseError}; + return false; + } + + // Populate PSScriptFileInfo object by first creating instances for the property objects + // i.e (PSScriptMetadata, PSScriptHelp, PSScriptRequires, PSScriptContents) + if (!TryPopulateScriptClassesWithParsedContent( + psScriptInfoCommentContent: psScriptInfoCommentContent, + helpInfoCommentContent: helpInfoCommentContent, + requiresCommentContent: requiresCommentContent, + remainingFileContent: remainingFileContent, + currentMetadata: out PSScriptMetadata currentMetadata, + currentHelpInfo: out PSScriptHelp currentHelpInfo, + currentRequiresComment: out PSScriptRequires currentRequiresComment, + currentEndOfFileContents: out PSScriptContents currentEndOfFileContents, + errors: out errors, + out verboseMsgs)) + { + return false; + } + + // Create PSScriptFileInfo instance with script metadata class instances (PSScriptMetadata, PSScriptHelp, PSScriptRequires, PSScriptContents) + try + { + parsedScript = new PSScriptFileInfo( + scriptMetadataComment: currentMetadata, + scriptHelpComment: currentHelpInfo, + scriptRequiresComment: currentRequiresComment, + scriptRemainingContent: currentEndOfFileContents); + } + catch (Exception e) + { + var message = String.Format("PSScriptFileInfo object could not be created from passed in file due to {0}", e.Message); + var ex = new ArgumentException(message); + var PSScriptFileInfoObjectNotCreatedFromFileError = new ErrorRecord(ex, "PSScriptFileInfoObjectNotCreatedFromFileError", ErrorCategory.ParserError, null); + errors = new ErrorRecord[]{PSScriptFileInfoObjectNotCreatedFromFileError}; + return false; + } + + errors = errorsList.ToArray(); + return true; + } + + /// + /// Updates .ps1 file. + /// Caller must check that the file to update doesn't have a signature or if it does permission to remove signature has been granted + /// as this method will remove original signature, as updating would have invalidated it. + /// + internal static bool TryUpdateScriptFileContents( + PSScriptFileInfo scriptInfo, + out string[] updatedPSScriptFileContents, + out ErrorRecord[] errors, + string version, + Guid guid, + string author, + string companyName, + string copyright, + string[] tags, + Uri licenseUri, + Uri projectUri, + Uri iconUri, + ModuleSpecification[] requiredModules, + string[] externalModuleDependencies, + string[] requiredScripts, + string[] externalScriptDependencies, + string releaseNotes, + string privateData, + string description) + { + updatedPSScriptFileContents = Utils.EmptyStrArray; + List errorsList = new List(); + bool successfullyUpdated = true; + + if (scriptInfo == null) + { + throw new ArgumentNullException(nameof(scriptInfo)); + } + + if (!scriptInfo.ScriptMetadataComment.UpdateContent( + version: version, + guid: guid, + author: author, + companyName: companyName, + copyright: copyright, + tags: tags, + licenseUri: licenseUri, + projectUri: projectUri, + iconUri: iconUri, + externalModuleDependencies: externalModuleDependencies, + requiredScripts: requiredScripts, + externalScriptDependencies: externalScriptDependencies, + releaseNotes: releaseNotes, + privateData: privateData, + out ErrorRecord metadataUpdateError)) + { + errorsList.Add(metadataUpdateError); + successfullyUpdated = false; + } + + if (!scriptInfo.ScriptHelpComment.UpdateContent( + description: description, + out ErrorRecord helpUpdateError)) + { + errorsList.Add(helpUpdateError); + successfullyUpdated = false; + } + + // this doesn't produce errors, as ModuleSpecification creation is already validated before param passed in + // and user can't update endOfFileContents + scriptInfo.ScriptRequiresComment.UpdateContent(requiredModules: requiredModules); + + if (!successfullyUpdated) + { + errors = errorsList.ToArray(); + return successfullyUpdated; + } + + // create string contents for .ps1 file + if (!scriptInfo.TryCreateScriptFileInfoString( + psScriptFileContents: out updatedPSScriptFileContents, + errors: out ErrorRecord[] createUpdatedFileContentErrors)) + { + errorsList.AddRange(createUpdatedFileContentErrors); + successfullyUpdated = false; + } + + errors = errorsList.ToArray(); + return successfullyUpdated; + } + + #endregion + + #region Internal Methods + + /// + /// Creates .ps1 file content string representation for the PSScriptFileInfo object this called upon, which is used by the caller to write the .ps1 file. + /// + internal bool TryCreateScriptFileInfoString( + out string[] psScriptFileContents, + out ErrorRecord[] errors + ) + { + psScriptFileContents = Utils.EmptyStrArray; + List fileContentsList = new List(); + errors = Array.Empty(); + List errorsList = new List(); + + bool fileContentsSuccessfullyCreated = true; + + // Step 1: validate object properties for required script properties. + if (!ScriptMetadataComment.ValidateContent(out ErrorRecord[] metadataValidationErrors)) + { + errorsList.AddRange(metadataValidationErrors); + fileContentsSuccessfullyCreated = false; + } + + if (!ScriptHelpComment.ValidateContent(out ErrorRecord helpValidationError)) + { + errorsList.Add(helpValidationError); + fileContentsSuccessfullyCreated = false; + } + + if (!fileContentsSuccessfullyCreated) + { + errors = errorsList.ToArray(); + return fileContentsSuccessfullyCreated; + } + + // Step 2: create string [] that will be used to write to file later + fileContentsList.AddRange(ScriptMetadataComment.EmitContent()); + + // string psRequiresCommentBlock = ScriptRequiresComment.EmitContent(); + fileContentsList.AddRange(ScriptRequiresComment.EmitContent()); + fileContentsList.AddRange(ScriptHelpComment.EmitContent()); + fileContentsList.AddRange(ScriptContent.EmitContent()); + + psScriptFileContents = fileContentsList.ToArray(); + return fileContentsSuccessfullyCreated; + } + + #endregion + } +} diff --git a/src/code/PSScriptHelp.cs b/src/code/PSScriptHelp.cs new file mode 100644 index 000000000..9964d2159 --- /dev/null +++ b/src/code/PSScriptHelp.cs @@ -0,0 +1,325 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Management.Automation; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a PSScriptFileInfo (representing a .ps1 file contents). + /// + public sealed class PSScriptHelp + { + #region Properties + + /// + /// The description of the script. + /// + public string Description { get; private set; } + + /// + /// The synopsis of the script. + /// + public string Synopsis { get; private set; } + + /// + /// The example(s) relating to the script's usage. + /// + public string[] Example { get; private set; } = Utils.EmptyStrArray; + + /// + /// The inputs to the script. + /// + public string[] Inputs { get; private set; } = Utils.EmptyStrArray; + + /// + /// The outputs to the script. + /// + public string[] Outputs { get; private set; } = Utils.EmptyStrArray; + + /// + /// The notes for the script. + /// + public string[] Notes { get; private set; } = Utils.EmptyStrArray; + + /// + /// The links for the script. + /// + public string[] Links { get; private set; } = Utils.EmptyStrArray; + + /// + /// The components for the script. + /// + public string[] Component { get; private set; } = Utils.EmptyStrArray; + + /// + /// The roles for the script. + /// + public string[] Role { get; private set; } = Utils.EmptyStrArray; + + /// + /// The functionality components for the script. + /// + public string[] Functionality { get; private set; } = Utils.EmptyStrArray; + + #endregion + + #region Constructor + + /// + /// This constructor takes a value for description and creates a new PSScriptHelp instance. + /// + public PSScriptHelp (string description) + { + this.Description = description; + } + + /// + /// This constructor takes values for description as well as other properties and creates a new PSScriptHelp instance. + /// Currently, the New-PSScriptFileInfo and Update-PSScriptFileInfo cmdlets don't support the user providing these values. + /// + public PSScriptHelp ( + string description, + string synopsis, + string[] example, + string[] inputs, + string[] outputs, + string[] notes, + string[] links, + string[] component, + string[] role, + string[] functionality) + { + this.Description = description; + this.Synopsis = synopsis; + this.Example = example; + this.Inputs = inputs; + this.Outputs = outputs; + this.Notes = notes; + this.Links = links; + this.Component = component; + this.Role = role; + this.Functionality = functionality; + } + + /// + /// This constructor is called by internal cmdlet methods and creates a PSScriptHelp with default values + /// for the parameters. Calling a method like PSScriptHelp.ParseConentIntoObj() would then populate those properties. + /// + internal PSScriptHelp() {} + + #endregion + + #region Internal Methods + + /// + /// Parses HelpInfo metadata out of the HelpInfo comment lines found while reading the file + /// and populates PSScriptHelp properties from that metadata. + /// + internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord error) + { + bool successfullyParsed = true; + string[] spaceDelimeter = new string[]{" "}; + string[] newlineDelimeter = new string[]{Environment.NewLine}; + + // parse content into a hashtable + Hashtable parsedHelpMetadata = Utils.ParseCommentBlockContent(commentLines); + + if (!ValidateParsedContent(parsedHelpMetadata, out error)) + { + return false; + } + + // populate object + Description = (string) parsedHelpMetadata["DESCRIPTION"]; + Synopsis = (string) parsedHelpMetadata["SYNOPSIS"] ?? String.Empty; + Example = Utils.GetStringArrayFromString(newlineDelimeter, (string) parsedHelpMetadata["EXAMPLE"]); + Inputs = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["INPUT"]); + Outputs = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["OUTPUTS"]); + Notes = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["NOTES"]); + Links = Utils.GetStringArrayFromString(newlineDelimeter, (string) parsedHelpMetadata["LINKS"]); + Component = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["COMPONENT"]); + Role = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["ROLE"]); + Functionality = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["FUNCTIONALITY"]); + + return successfullyParsed; + } + + /// + /// Valides parsed help info content from the hashtable to ensure required help metadata (Description) is present + /// and does not contain empty values. + /// + internal bool ValidateParsedContent(Hashtable parsedHelpMetadata, out ErrorRecord error) + { + error = null; + if (!parsedHelpMetadata.ContainsKey("DESCRIPTION") || String.IsNullOrEmpty((string) parsedHelpMetadata["DESCRIPTION"]) || String.Equals(((string) parsedHelpMetadata["DESCRIPTION"]).Trim(), String.Empty)) + { + var exMessage = "PSScript file must contain value for Description. Ensure value for Description is passed in and try again."; + var ex = new ArgumentException(exMessage); + var PSScriptInfoMissingDescriptionError = new ErrorRecord(ex, "PSScriptInfoMissingDescription", ErrorCategory.InvalidArgument, null); + error = PSScriptInfoMissingDescriptionError; + return false; + } + + if (StringContainsComment((string) parsedHelpMetadata["DESCRIPTION"])) + { + var exMessage = "PSScript file's value for Description cannot contain '<#' or '#>'. Pass in a valid value for Description and try again."; + var ex = new ArgumentException(exMessage); + var DescriptionContainsCommentError = new ErrorRecord(ex, "DescriptionContainsComment", ErrorCategory.InvalidArgument, null); + error = DescriptionContainsCommentError; + return false; + } + + return true; + } + + /// + /// Validates help info properties contain required script Help properties + /// i.e Description. + /// + internal bool ValidateContent(out ErrorRecord error) + { + error = null; + if (String.IsNullOrEmpty(Description)) + { + var exMessage = "PSScript file must contain value for Description. Ensure value for Description is passed in and try again."; + var ex = new ArgumentException(exMessage); + var PSScriptInfoMissingDescriptionError = new ErrorRecord(ex, "PSScriptInfoMissingDescription", ErrorCategory.InvalidArgument, null); + error = PSScriptInfoMissingDescriptionError; + return false; + } + + if (StringContainsComment(Description)) + { + var exMessage = "PSScript file's value for Description cannot contain '<#' or '#>'. Pass in a valid value for Description and try again."; + var ex = new ArgumentException(exMessage); + var DescriptionContainsCommentError = new ErrorRecord(ex, "DescriptionContainsComment", ErrorCategory.InvalidArgument, null); + error = DescriptionContainsCommentError; + return false; + } + + return true; + } + + /// + /// Emits string representation of 'HelpInfo <# ... #>' comment and its metadata contents. + /// + internal string[] EmitContent() + { + // Note: we add a newline to the end of each property entry in HelpInfo so that there's an empty line separating them. + List psHelpInfoLines = new List(); + + psHelpInfoLines.Add($"<#{Environment.NewLine}"); + psHelpInfoLines.Add($".DESCRIPTION"); + psHelpInfoLines.Add($"{Description}{Environment.NewLine}"); + + if (!String.IsNullOrEmpty(Synopsis)) + { + psHelpInfoLines.Add($".SYNOPSIS"); + psHelpInfoLines.Add($"{Synopsis}{Environment.NewLine}"); + } + + foreach (string currentExample in Example) + { + psHelpInfoLines.Add($".EXAMPLE"); + psHelpInfoLines.Add($"{currentExample}{Environment.NewLine}"); + } + + foreach (string input in Inputs) + { + psHelpInfoLines.Add($".INPUTS"); + psHelpInfoLines.Add($"{input}{Environment.NewLine}"); + } + + foreach (string output in Outputs) + { + psHelpInfoLines.Add($".OUTPUTS"); + psHelpInfoLines.Add($"{output}{Environment.NewLine}"); + } + + if (Notes.Length > 0) + { + psHelpInfoLines.Add($".NOTES"); + psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Notes)}{Environment.NewLine}"); + } + + foreach (string link in Links) + { + psHelpInfoLines.Add($".LINK"); + psHelpInfoLines.Add($"{link}{Environment.NewLine}"); + } + + if (Component.Length > 0) + { + psHelpInfoLines.Add($".COMPONENT"); + psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Component)}{Environment.NewLine}"); + } + + if (Role.Length > 0) + { + psHelpInfoLines.Add($".ROLE"); + psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Role)}{Environment.NewLine}"); + } + + if (Functionality.Length > 0) + { + psHelpInfoLines.Add($".FUNCTIONALITY"); + psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Functionality)}{Environment.NewLine}"); + } + + psHelpInfoLines.Add("#>"); + + return psHelpInfoLines.ToArray(); + } + + /// + /// Updates contents of the HelpInfo properties from any (non-default) values passed in. + /// + internal bool UpdateContent(string description, out ErrorRecord error) + { + error = null; + + if (!String.IsNullOrEmpty(description)) + { + if (String.Equals(description.Trim(), String.Empty)) + { + var exMessage = "Description value can't be updated to whitespace as this would invalidate the script."; + var ex = new ArgumentException(exMessage); + var descriptionUpdateValueIsWhitespaceError = new ErrorRecord(ex, "descriptionUpdateValueIsWhitespaceError", ErrorCategory.InvalidArgument, null); + error = descriptionUpdateValueIsWhitespaceError; + return false; + } + + if (StringContainsComment(description)) + { + var exMessage = "Description value can't be updated to value containing comment '<#' or '#>' as this would invalidate the script."; + var ex = new ArgumentException(exMessage); + var descriptionUpdateValueContainsCommentError = new ErrorRecord(ex, "descriptionUpdateValueContainsCommentError", ErrorCategory.InvalidArgument, null); + error = descriptionUpdateValueContainsCommentError; + return false; + } + + Description = description; + } + + return true; + } + + #endregion + + #region Private Methods + + /// + /// Ensure description field (passed as stringToValidate) does not contain '<#' or '#>'. + /// + private bool StringContainsComment(string stringToValidate) + { + return stringToValidate.Contains("<#") || stringToValidate.Contains("#>"); + } + + #endregion + } +} diff --git a/src/code/PSScriptMetadata.cs b/src/code/PSScriptMetadata.cs new file mode 100644 index 000000000..ded8088e7 --- /dev/null +++ b/src/code/PSScriptMetadata.cs @@ -0,0 +1,458 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Management.Automation; +using NuGet.Versioning; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a PSScriptFileInfo (representing a .ps1 file contents). + /// + public sealed class PSScriptMetadata + { + #region Properties + + /// + /// the version of the script. + /// + public NuGetVersion Version { get; private set; } + + /// + /// the GUID for the script. + /// + public Guid Guid { get; private set; } + + /// + /// the author for the script. + /// + public string Author { get; private set; } + + /// + /// the name of the company owning the script. + /// + public string CompanyName { get; private set; } + + /// + /// the copyright statement for the script. + /// + public string Copyright { get; private set; } + + /// + /// the tags for the script. + /// + public string[] Tags { get; private set; } + + /// + /// the Uri for the license of the script. + /// + public Uri LicenseUri { get; private set; } + + /// + /// the Uri for the project relating to the script. + /// + public Uri ProjectUri { get; private set; } + + /// + /// the Uri for the icon relating to the script. + /// + public Uri IconUri { get; private set; } + + /// + /// the list of external module dependencies for the script. + /// + public string[] ExternalModuleDependencies { get; private set; } = Utils.EmptyStrArray; + + /// + /// the list of required scripts for the parent script. + /// + public string[] RequiredScripts { get; private set; } = Utils.EmptyStrArray; + + /// + /// the list of external script dependencies for the script. + /// + public string[] ExternalScriptDependencies { get; private set; } = Utils.EmptyStrArray; + + /// + /// the release notes relating to the script. + /// + public string ReleaseNotes { get; private set; } = String.Empty; + + /// + /// The private data associated with the script. + /// + public string PrivateData { get; private set; } + + #endregion + + #region Constructor + + /// + /// This constructor takes metadata properties and creates PSScriptMetadata instance. + /// + public PSScriptMetadata( + string version, + Guid guid, + string author, + string companyName, + string copyright, + string[] tags, + Uri licenseUri, + Uri projectUri, + Uri iconUri, + string[] externalModuleDependencies, + string[] requiredScripts, + string[] externalScriptDependencies, + string releaseNotes, + string privateData) + { + if (String.IsNullOrEmpty(author)) + { + author = Environment.UserName; + } + + Version = !String.IsNullOrEmpty(version) ? new NuGetVersion (version) : new NuGetVersion("1.0.0.0"); + Guid = (guid == null || guid == Guid.Empty) ? Guid.NewGuid() : guid; + Author = !String.IsNullOrEmpty(author) ? author : Environment.UserName; + CompanyName = companyName; + Copyright = copyright; + Tags = tags ?? Utils.EmptyStrArray; + LicenseUri = licenseUri; + ProjectUri = projectUri; + IconUri = iconUri; + ExternalModuleDependencies = externalModuleDependencies ?? Utils.EmptyStrArray; + RequiredScripts = requiredScripts ?? Utils.EmptyStrArray; + ExternalScriptDependencies = externalScriptDependencies ?? Utils.EmptyStrArray; + ReleaseNotes = releaseNotes; + PrivateData = privateData; + } + + /// + /// This constructor is called by internal cmdlet methods and creates a PSScriptFileInfo with default values + /// for the parameters. Calling a method like PSScriptMetadata.ParseConentIntoObj() would then populate those properties. + /// + internal PSScriptMetadata() {} + + #endregion + + #region Internal Methods + + /// + /// Parses script metadata comment (passed in as its lines) into PSScriptMetadata instance's properties + /// Also validates that this metadata has required script properties. + /// + internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] errors, out string[] msgs) + { + msgs = Utils.EmptyStrArray; + List msgsList = new List(); + + // parse content into a hashtable + Hashtable parsedMetadata = Utils.ParseCommentBlockContent(commentLines); + + if (parsedMetadata.Count == 0) + { + var message = String.Format("PowerShell script '<#PSScriptInfo .. #>' comment block contains no metadata"); + var ex = new InvalidOperationException(message); + var psScriptInfoBlockMissingMetadata = new ErrorRecord(ex, "psScriptInfoBlockMissingMetadataError", ErrorCategory.ParserError, null); + errors = new ErrorRecord[]{psScriptInfoBlockMissingMetadata}; + return false; + } + + // check parsed metadata contains required Author, Version, Guid key values + if (!ValidateParsedContent(parsedMetadata, out errors)) + { + return false; + } + + // now populate the object instance + string[] spaceDelimeter = new string[]{" "}; + + Uri parsedLicenseUri = null; + if (!String.IsNullOrEmpty((string) parsedMetadata["LICENSEURI"])) + { + if (!Uri.TryCreate((string) parsedMetadata["LICENSEURI"], UriKind.Absolute, out parsedLicenseUri)) + { + msgsList.Add($"LicenseUri property {(string) parsedMetadata["LICENSEURI"]} could not be created as a Uri"); + } + } + + Uri parsedProjectUri = null; + if (!String.IsNullOrEmpty((string) parsedMetadata["PROJECTURI"])) + { + if (!Uri.TryCreate((string) parsedMetadata["PROJECTURI"], UriKind.Absolute, out parsedProjectUri)) + { + msgsList.Add($"ProjectUri property {(string) parsedMetadata["PROJECTURI"]} could not be created as Uri"); + } + } + + Uri parsedIconUri = null; + if (!String.IsNullOrEmpty((string) parsedMetadata["ICONURI"])) + { + if (!Uri.TryCreate((string) parsedMetadata["ICONURI"], UriKind.Absolute, out parsedIconUri)) + { + msgsList.Add($"IconUri property {(string) parsedMetadata["ICONURI"]} could not be created as Uri"); + } + } + + // now populate PSScriptMetadata object properties with parsed metadata + Author = (string) parsedMetadata["AUTHOR"]; + Version = new NuGetVersion((string) parsedMetadata["VERSION"]); + Guid = new Guid((string) parsedMetadata["GUID"]); + + CompanyName = (string) parsedMetadata["COMPANYNAME"] ?? String.Empty; + Copyright = (string) parsedMetadata["COPYRIGHT"] ?? String.Empty; + + LicenseUri = parsedLicenseUri; + ProjectUri = parsedProjectUri; + IconUri = parsedIconUri; + + Tags = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedMetadata["TAGS"]);; + ExternalModuleDependencies = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedMetadata["EXTERNALMODULEDEPENDENCIES"]); + RequiredScripts = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedMetadata["REQUIREDSCRIPTS"]); + ExternalScriptDependencies = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedMetadata["EXTERNALSCRIPTDEPENDENCIES"]); + ReleaseNotes = (string) parsedMetadata["RELEASENOTES"] ?? String.Empty; + PrivateData = (string) parsedMetadata["PRIVATEDATA"] ?? String.Empty; + + msgs = msgsList.ToArray(); + return true; + } + + /// + /// Valides parsed metadata content from the hashtable to ensure required metadata (Author, Version, Guid) is present + /// and does not contain empty values. + /// + internal bool ValidateParsedContent(Hashtable parsedMetadata, out ErrorRecord[] errors) + { + List errorsList = new List(); + + if (!parsedMetadata.ContainsKey("VERSION") || String.IsNullOrEmpty((string) parsedMetadata["VERSION"]) || String.Equals(((string) parsedMetadata["VERSION"]).Trim(), String.Empty)) + { + var message = String.Format("PSScript file is missing the required Version property"); + var ex = new ArgumentException(message); + var psScriptMissingVersionError = new ErrorRecord(ex, "psScriptMissingVersion", ErrorCategory.ParserError, null); + errorsList.Add(psScriptMissingVersionError); + } + + if (!parsedMetadata.ContainsKey("AUTHOR") || String.IsNullOrEmpty((string) parsedMetadata["AUTHOR"]) || String.Equals(((string) parsedMetadata["AUTHOR"]).Trim(), String.Empty)) + { + var message = String.Format("PSScript file is missing the required Author property"); + var ex = new ArgumentException(message); + var psScriptMissingAuthorError = new ErrorRecord(ex, "psScriptMissingAuthor", ErrorCategory.ParserError, null); + errorsList.Add(psScriptMissingAuthorError); + } + + if (!parsedMetadata.ContainsKey("GUID") || String.IsNullOrEmpty((string) parsedMetadata["GUID"]) || String.Equals(((string) parsedMetadata["GUID"]).Trim(), String.Empty)) + { + var message = String.Format("PSScript file is missing the required Guid property"); + var ex = new ArgumentException(message); + var psScriptMissingGuidError = new ErrorRecord(ex, "psScriptMissingGuid", ErrorCategory.ParserError, null); + errorsList.Add(psScriptMissingGuidError); + } + + errors = errorsList.ToArray(); + return errors.Length == 0; + } + /// + /// Validates metadata properties are valid and contains required script properties + /// i.e Author, Version, Guid. + /// + internal bool ValidateContent(out ErrorRecord[] errors) + { + bool validPSScriptInfo = true; + List errorsList = new List(); + + if (Version == null || String.IsNullOrEmpty(Version.ToString())) + { + var message = String.Format("PSScript file is missing the required Version property"); + var ex = new ArgumentException(message); + var psScriptMissingVersionError = new ErrorRecord(ex, "psScriptMissingVersion", ErrorCategory.ParserError, null); + errorsList.Add(psScriptMissingVersionError); + validPSScriptInfo = false; + } + + if (String.IsNullOrEmpty(Author)) + { + var message = String.Format("PSScript file is missing the required Author property"); + var ex = new ArgumentException(message); + var psScriptMissingAuthorError = new ErrorRecord(ex, "psScriptMissingAuthor", ErrorCategory.ParserError, null); + errorsList.Add(psScriptMissingAuthorError); + validPSScriptInfo = false; + } + + if (Guid == Guid.Empty) + { + var message = String.Format("PSScript file is missing the required Guid property"); + var ex = new ArgumentException(message); + var psScriptMissingGuidError = new ErrorRecord(ex, "psScriptMissingGuid", ErrorCategory.ParserError, null); + errorsList.Add(psScriptMissingGuidError); + validPSScriptInfo = false; + } + + errors = errorsList.ToArray(); + return validPSScriptInfo; + } + + /// + /// Emits string representation of '<#PSScriptInfo ... #>' comment and its metadata contents. + /// + internal string[] EmitContent() + { + /** + PSScriptInfo comment will be in following format: + <#PSScriptInfo + .VERSION 1.0 + .GUID 544238e3-1751-4065-9227-be105ff11636 + .AUTHOR manikb + .COMPANYNAME Microsoft Corporation + .COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. + .TAGS Tag1 Tag2 Tag3 + .LICENSEURI https://contoso.com/License + .PROJECTURI https://contoso.com/ + .ICONURI https://contoso.com/Icon + .EXTERNALMODULEDEPENDENCIES ExternalModule1 + .REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript + .EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript + .RELEASENOTES + contoso script now supports following features + Feature 1 + Feature 2 + Feature 3 + Feature 4 + Feature 5 + .PRIVATEDATA + #> + */ + + string liceseUriString = LicenseUri == null ? String.Empty : LicenseUri.ToString(); + string projectUriString = ProjectUri == null ? String.Empty : ProjectUri.ToString(); + string iconUriString = IconUri == null ? String.Empty : IconUri.ToString(); + + string tagsString = String.Join(" ", Tags); + string externalModuleDependenciesString = String.Join(" ", ExternalModuleDependencies); + string requiredScriptsString = String.Join(" ", RequiredScripts); + string externalScriptDependenciesString = String.Join(" ", ExternalScriptDependencies); + + List psScriptInfoLines = new List(); + + // Note: we add a newline to the end of each property entry in HelpInfo so that there's an empty line separating them. + psScriptInfoLines.Add($"<#PSScriptInfo{Environment.NewLine}"); + psScriptInfoLines.Add($".VERSION {Version.ToString()}{Environment.NewLine}"); + psScriptInfoLines.Add($".GUID {Guid.ToString()}{Environment.NewLine}"); + psScriptInfoLines.Add($".AUTHOR {Author}{Environment.NewLine}"); + psScriptInfoLines.Add($".COMPANYNAME {CompanyName}{Environment.NewLine}"); + psScriptInfoLines.Add($".COPYRIGHT {Copyright}{Environment.NewLine}"); + psScriptInfoLines.Add($".TAGS {tagsString}{Environment.NewLine}"); + psScriptInfoLines.Add($".LICENSEURI {liceseUriString}{Environment.NewLine}"); + psScriptInfoLines.Add($".PROJECTURI {projectUriString}{Environment.NewLine}"); + psScriptInfoLines.Add($".ICONURI {iconUriString}{Environment.NewLine}"); + psScriptInfoLines.Add($".EXTERNALMODULEDEPENDENCIES {externalModuleDependenciesString}{Environment.NewLine}"); + psScriptInfoLines.Add($".REQUIREDSCRIPTS {requiredScriptsString}{Environment.NewLine}"); + psScriptInfoLines.Add($".EXTERNALSCRIPTDEPENDENCIES {externalScriptDependenciesString}{Environment.NewLine}"); + psScriptInfoLines.Add($".RELEASENOTES{Environment.NewLine}{ReleaseNotes}{Environment.NewLine}"); + psScriptInfoLines.Add($".PRIVATEDATA{Environment.NewLine}{PrivateData}{Environment.NewLine}"); + psScriptInfoLines.Add("#>"); + + return psScriptInfoLines.ToArray(); + } + + /// + /// Updates contents of the script metadata properties from any (non-default) values passed in. + /// + internal bool UpdateContent( + string version, + Guid guid, + string author, + string companyName, + string copyright, + string[] tags, + Uri licenseUri, + Uri projectUri, + Uri iconUri, + string[] externalModuleDependencies, + string[] requiredScripts, + string[] externalScriptDependencies, + string releaseNotes, + string privateData, + out ErrorRecord error) + { + error = null; + if (!String.IsNullOrEmpty(version)) + { + if (!NuGetVersion.TryParse(version, out NuGetVersion updatedVersion)) + { + var message = String.Format("Version provided for update could not be parsed successfully into NuGetVersion"); + var ex = new ArgumentException(message); + var versionParseIntoNuGetVersionError = new ErrorRecord(ex, "VersionParseIntoNuGetVersion", ErrorCategory.ParserError, null); + error = versionParseIntoNuGetVersionError; + return false; + } + + Version = updatedVersion; + } + + if (guid != Guid.Empty) + { + Guid = guid; + } + + if (!String.IsNullOrEmpty(author)) + { + Author = author; + } + + if (!String.IsNullOrEmpty(companyName)){ + CompanyName = companyName; + } + + if (!String.IsNullOrEmpty(copyright)){ + Copyright = copyright; + } + + if (tags != null && tags.Length != 0){ + Tags = tags; + } + + if (licenseUri != null && !licenseUri.Equals(default(Uri))){ + LicenseUri = licenseUri; + } + + if (projectUri != null && !projectUri.Equals(default(Uri))){ + ProjectUri = projectUri; + } + + if (iconUri != null && !iconUri.Equals(default(Uri))){ + IconUri = iconUri; + } + + if (externalModuleDependencies != null && externalModuleDependencies.Length != 0){ + ExternalModuleDependencies = externalModuleDependencies; + } + + if (requiredScripts != null && requiredScripts.Length != 0) + { + RequiredScripts = requiredScripts; + } + + if (externalScriptDependencies != null && externalScriptDependencies.Length != 0){ + ExternalScriptDependencies = externalScriptDependencies; + } + + if (!String.IsNullOrEmpty(releaseNotes)) + { + ReleaseNotes = releaseNotes; + } + + if (!String.IsNullOrEmpty(privateData)) + { + PrivateData = privateData; + } + + return true; + } + + #endregion + } +} diff --git a/src/code/PSScriptRequires.cs b/src/code/PSScriptRequires.cs new file mode 100644 index 000000000..4c2e551d4 --- /dev/null +++ b/src/code/PSScriptRequires.cs @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Linq; +using System.Collections.ObjectModel; +using Microsoft.PowerShell.Commands; + +namespace Microsoft.PowerShell.PowerShellGet.UtilClasses +{ + /// + /// This class contains information for a PSScriptFileInfo (representing a .ps1 file contents). + /// + public sealed class PSScriptRequires + { + #region Properties + + /// + /// The list of modules required by the script. + /// Hashtable keys: GUID, MaxVersion, ModuleName (Required), RequiredVersion, Version. + /// + public ModuleSpecification[] RequiredModules { get; private set; } = Array.Empty(); + + #endregion + + #region Constructor + + /// + /// This constructor creates a new PSScriptRequires instance with specified required modules. + /// + public PSScriptRequires(ModuleSpecification[] requiredModules) + { + RequiredModules = requiredModules ?? Array.Empty(); + } + + /// + /// This constructor is called by internal cmdlet methods and creates a PSScriptHelp with default values + /// for the parameters. Calling a method like PSScriptRequires.ParseConentIntoObj() would then populate those properties. + /// + internal PSScriptRequires() {} + + #endregion + + #region Internal Methods + + /// + /// Parses RequiredModules out of comment lines and validates during parse process. + /// + internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] errors) + { + /** + When Requires comment lines are obtained from .ps1 file they will have this format: + + #Requires -Module RequiredModule1 + #Requires -Module @{ ModuleName = 'RequiredModule2'; ModuleVersion = '2.0' } + #Requires -Module @{ ModuleName = 'RequiredModule3'; RequiredVersion = '2.5' } + #Requires -Module @{ ModuleName = 'RequiredModule4'; ModuleVersion = '1.1'; MaximumVersion = '2.0' } + #Requires -Module @{ ModuleName = 'RequiredModule5'; MaximumVersion = '1.5' } + + */ + + errors = Array.Empty(); + List errorsList = new List(); + string requiresComment = String.Join(Environment.NewLine, commentLines); + + try + { + var ast = Parser.ParseInput( + requiresComment, + out Token[] tokens, + out ParseError[] parserErrors); + + if (parserErrors.Length > 0) + { + foreach (ParseError err in parserErrors) + { + var message = String.Format("Could not requires comments as valid PowerShell input due to {0}.", err.Message); + var ex = new InvalidOperationException(message); + var requiresCommentParseError = new ErrorRecord(ex, err.ErrorId, ErrorCategory.ParserError, null); + errorsList.Add(requiresCommentParseError); + } + + errors = errorsList.ToArray(); + return false; + } + + // get .REQUIREDMODULES property, by accessing the System.Management.Automation.Language.ScriptRequirements object ScriptRequirements.RequiredModules property + ScriptRequirements parsedScriptRequirements = ast.ScriptRequirements; + ReadOnlyCollection parsedModules = new List().AsReadOnly(); + + if (parsedScriptRequirements != null && parsedScriptRequirements.RequiredModules != null) + { + RequiredModules = parsedScriptRequirements.RequiredModules.ToArray(); + } + } + catch (Exception e) + { + var message = $"Parsing RequiredModules failed due to {e.Message}"; + var ex = new ArgumentException(message); + var requiredModulesAstParseError = new ErrorRecord(ex, "requiredModulesAstParseThrewError", ErrorCategory.ParserError, null); + errorsList.Add(requiredModulesAstParseError); + errors = errorsList.ToArray(); + return false; + } + + return true; + } + + /// + /// Emits string representation of '#Requires ...' comment(s). + /// + internal string[] EmitContent() + { + List psRequiresLines = new List(); + if (RequiredModules.Length > 0) + { + psRequiresLines.Add(String.Empty); + foreach (ModuleSpecification moduleSpec in RequiredModules) + { + psRequiresLines.Add(String.Format("#Requires -Module {0}", moduleSpec.ToString())); + } + + psRequiresLines.Add(String.Empty); + } + + return psRequiresLines.ToArray(); + } + + /// + /// Updates the current Requires content with another (passed in), effectively replaces it. + /// + internal void UpdateContent(ModuleSpecification[] requiredModules) + { + if (requiredModules != null && requiredModules.Length != 0){ + RequiredModules = requiredModules; + } + } + + #endregion + } +} diff --git a/src/code/TestPSScriptFileInfo.cs b/src/code/TestPSScriptFileInfo.cs new file mode 100644 index 000000000..931d04c7c --- /dev/null +++ b/src/code/TestPSScriptFileInfo.cs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Management.Automation; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Tests the contents of a .ps1 file to see if it has all properties and is in correct format + /// for publishing the script with the file. + /// + [Cmdlet(VerbsDiagnostic.Test, "PSScriptFileInfo")] + [OutputType(typeof(bool))] + public sealed class TestPSScriptFileInfo : PSCmdlet + { + #region Parameters + + /// + /// The path to the .ps1 file to test. + /// + [Parameter(Position = 0, Mandatory = true)] + [ValidateNotNullOrEmpty] + public string FilePath { get; set; } + + #endregion + + #region Methods + + protected override void EndProcessing() + { + if (!FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + { + var exMessage = "Path needs to end with a .ps1 file. Example: C:/Users/john/x/MyScript.ps1"; + var ex = new ArgumentException(exMessage); + var InvalidPathError = new ErrorRecord(ex, "InvalidPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidPathError); + } + + var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(FilePath); + if (resolvedPaths.Count != 1) + { + var exMessage = "Error: Could not resolve provided Path argument into a single path."; + var ex = new PSArgumentException(exMessage); + var InvalidPathArgumentError = new ErrorRecord(ex, "InvalidPathArgumentError", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidPathArgumentError); + } + + var resolvedFilePath = resolvedPaths[0].Path; + + if (!File.Exists(resolvedFilePath)) + { + var exMessage = "A .ps1 file does not exist at the location specified."; + var ex = new ArgumentException(exMessage); + var FileDoesNotExistError = new ErrorRecord(ex, "FileDoesNotExistAtPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(FileDoesNotExistError); + } + + bool isValidScript = PSScriptFileInfo.TryTestPSScriptFile( + scriptFileInfoPath: resolvedFilePath, + parsedScript: out PSScriptFileInfo _, + errors: out ErrorRecord[] errors, + out string[] verboseMsgs); + + if (!isValidScript) + { + foreach (ErrorRecord error in errors) + { + WriteVerbose("The .ps1 script file passed in was not valid due to: " + error.Exception.Message); + } + } + + foreach (string msg in verboseMsgs) + { + WriteVerbose(msg); + } + + WriteObject(isValidScript); + } + + #endregion + } +} diff --git a/src/code/UpdatePSScriptFileInfo.cs b/src/code/UpdatePSScriptFileInfo.cs new file mode 100644 index 000000000..8803873d7 --- /dev/null +++ b/src/code/UpdatePSScriptFileInfo.cs @@ -0,0 +1,319 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.IO; +using System.Management.Automation; +using Microsoft.PowerShell.Commands; +using Microsoft.PowerShell.PowerShellGet.UtilClasses; + +namespace Microsoft.PowerShell.PowerShellGet.Cmdlets +{ + /// + /// Updates a .ps1 file with specified properties. + /// + [Cmdlet(VerbsData.Update, "PSScriptFileInfo")] + public sealed class UpdatePSScriptFileInfo : PSCmdlet + { + #region Parameters + + /// + /// The author of the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string Author { get; set; } + + /// + /// The name of the company owning the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string CompanyName { get; set; } + + /// + /// The copyright statement for the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string Copyright { get; set; } + + /// + /// The description of the script. + /// + [Parameter()] + [ValidateNotNullOrEmpty()] + public string Description { get; set; } + + /// + /// The list of external module dependencies taken by this script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] ExternalModuleDependencies { get; set; } + + /// + /// The list of external script dependencies taken by this script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] ExternalScriptDependencies { get; set; } + + /// + /// The unique identifier for the script. The GUID can be used to distinguish among scripts with the same name. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public Guid Guid { get; set; } + + /// + /// The Uri for the icon associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string IconUri { get; set; } + + /// + /// The Uri for the license associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string LicenseUri { get; set; } + + /// + /// The path the .ps1 script info file will be created at. + /// + [Parameter(Position = 0, Mandatory = true)] + [ValidateNotNullOrEmpty] + public string FilePath { get; set; } + + /// + /// The private data associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string PrivateData { get; set; } + + /// + /// The Uri for the project associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string ProjectUri { get; set; } + + /// + /// The release notes for the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string ReleaseNotes { get; set; } + + /// + /// Remove signature from signed .ps1 (if present) thereby allowing update of script to happen + /// User should re-sign the updated script afterwards. + /// + [Parameter] + public SwitchParameter RemoveSignature { get; set; } + + /// + /// The list of modules required by the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public Hashtable[] RequiredModules { get; set; } + + /// + /// The list of scripts required by the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] RequiredScripts { get; set; } + + /// + /// The tags associated with the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string[] Tags { get; set; } + + /// + /// The version of the script. + /// + [Parameter] + [ValidateNotNullOrEmpty()] + public string Version { get; set; } + + #endregion + + #region Methods + + protected override void EndProcessing() + { + Uri projectUri = null; + if (!String.IsNullOrEmpty(ProjectUri) && !Utils.TryCreateValidUri(uriString: ProjectUri, + cmdletPassedIn: this, + uriResult: out projectUri, + errorRecord: out ErrorRecord projectErrorRecord)) + { + ThrowTerminatingError(projectErrorRecord); + } + + Uri licenseUri = null; + if (!String.IsNullOrEmpty(LicenseUri) && !Utils.TryCreateValidUri(uriString: LicenseUri, + cmdletPassedIn: this, + uriResult: out licenseUri, + errorRecord: out ErrorRecord licenseErrorRecord)) + { + ThrowTerminatingError(licenseErrorRecord); + } + + Uri iconUri = null; + if (!String.IsNullOrEmpty(IconUri) && !Utils.TryCreateValidUri(uriString: IconUri, + cmdletPassedIn: this, + uriResult: out iconUri, + errorRecord: out ErrorRecord iconErrorRecord)) + { + ThrowTerminatingError(iconErrorRecord); + } + + if (!FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + { + var exMessage = "File path needs to end with a .ps1 extension. Example: C:/Users/john/x/MyScript.ps1"; + var ex = new ArgumentException(exMessage); + var InvalidOrNonExistantPathError = new ErrorRecord(ex, "InvalidOrNonExistantPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidOrNonExistantPathError); + } + + var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(FilePath); + if (resolvedPaths.Count != 1) + { + var exMessage = "Error: Could not resolve provided Path argument into a single path."; + var ex = new PSArgumentException(exMessage); + var InvalidPathArgumentError = new ErrorRecord(ex, "InvalidPathArgumentError", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(InvalidPathArgumentError); + } + + string resolvedFilePath = resolvedPaths[0].Path; + + if (!File.Exists(resolvedFilePath)) + { + var exMessage = "A script file does not exist at the location specified"; + var ex = new ArgumentException(exMessage); + var FileDoesNotExistError = new ErrorRecord(ex, "FileDoesNotExistAtPath", ErrorCategory.InvalidArgument, null); + ThrowTerminatingError(FileDoesNotExistError); + } + + ModuleSpecification[] validatedRequiredModuleSpecifications = Array.Empty(); + if (RequiredModules != null && RequiredModules.Length > 0) + { + if (!Utils.TryCreateModuleSpecification( + moduleSpecHashtables: RequiredModules, + out validatedRequiredModuleSpecifications, + out ErrorRecord[] moduleSpecErrors)) + { + foreach (ErrorRecord err in moduleSpecErrors) + { + WriteError(err); + } + + return; + } + } + + if (!PSScriptFileInfo.TryTestPSScriptFile( + scriptFileInfoPath: resolvedFilePath, + parsedScript: out PSScriptFileInfo parsedScriptInfo, + errors: out ErrorRecord[] errors, + out string[] verboseMsgs)) + { + foreach (string msg in verboseMsgs) + { + WriteVerbose(msg); + } + + foreach (ErrorRecord error in errors) + { + WriteError(error); + } + + return; + } + + bool signatureRemoved = false; + if (parsedScriptInfo.ScriptContent.ContainsSignature) + { + if (!RemoveSignature) + { + var exMessage = "Cannot update the script file because the file contains a signature block and updating will invalidate the signature. Use -RemoveSignature to remove the signature block, and then re-sign the file after it is updated."; + var ex = new PSInvalidOperationException(exMessage); + var ScriptToBeUpdatedContainsSignatureError = new ErrorRecord(ex, "ScriptToBeUpdatedContainsSignature", ErrorCategory.InvalidOperation, null); + ThrowTerminatingError(ScriptToBeUpdatedContainsSignatureError); + } + + signatureRemoved = true; + } + + if (!PSScriptFileInfo.TryUpdateScriptFileContents( + scriptInfo: parsedScriptInfo, + updatedPSScriptFileContents: out string[] updatedPSScriptFileContents, + errors: out ErrorRecord[] updateErrors, + version: Version, + guid: Guid, + author: Author, + companyName: CompanyName, + copyright: Copyright, + tags: Tags, + licenseUri: licenseUri, + projectUri: projectUri, + iconUri: iconUri, + requiredModules: validatedRequiredModuleSpecifications, + externalModuleDependencies: ExternalModuleDependencies, + requiredScripts: RequiredScripts, + externalScriptDependencies: ExternalScriptDependencies, + releaseNotes: ReleaseNotes, + privateData: PrivateData, + description: Description)) + { + WriteWarning("Updating the specified script file failed due to the following error(s):"); + foreach (ErrorRecord error in updateErrors) + { + WriteError(error); + } + + return; + } + + string tempScriptFilePath = null; + try + { + tempScriptFilePath = Path.GetTempFileName(); + + File.WriteAllLines(tempScriptFilePath, updatedPSScriptFileContents); + File.Copy(tempScriptFilePath, resolvedFilePath, overwrite: true); + } + catch(Exception e) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException($"Could not update .ps1 file due to: {e.Message}"), + "FileIOErrorDuringUpdate", + ErrorCategory.InvalidArgument, + this)); + } + finally + { + if (tempScriptFilePath != null) + { + File.Delete(tempScriptFilePath); + } + } + + if (signatureRemoved) + { + WriteWarning("Re-sign this script, as the original signature was removed during update."); + } + } + + #endregion + } +} diff --git a/src/code/Utils.cs b/src/code/Utils.cs index f19861847..977d0be8a 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -16,6 +16,7 @@ using System.Runtime.InteropServices; using System.Security; using System.Security.Cryptography.X509Certificates; +using Microsoft.PowerShell.Commands; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -97,6 +98,17 @@ public static string QuoteName(string name) return "'" + CodeGeneration.EscapeSingleQuotedStringContent(name) + "'"; } + public static string[] GetStringArrayFromString(string[] delimeter, string stringToConvertToArray) + { + // This will be a string where entries are separated by space. + if (String.IsNullOrEmpty(stringToConvertToArray)) + { + return Utils.EmptyStrArray; + } + + return stringToConvertToArray.Split(delimeter, StringSplitOptions.RemoveEmptyEntries); + } + /// /// Converts an ArrayList of object types to a string array. /// @@ -914,6 +926,185 @@ public static Hashtable ConvertJsonToHashtable( return (results.Count == 1 && results[0] != null) ? (Hashtable)results[0].BaseObject : null; } + public static bool TryCreateModuleSpecification( + Hashtable[] moduleSpecHashtables, + out ModuleSpecification[] validatedModuleSpecs, + out ErrorRecord[] errors) + { + bool moduleSpecCreatedSuccessfully = true; + List errorList = new List(); + validatedModuleSpecs = Array.Empty(); + List moduleSpecsList = new List(); + + foreach(Hashtable moduleSpec in moduleSpecHashtables) + { + // ModuleSpecification(string) constructor for creating a ModuleSpecification when only ModuleName is provided. + if (!moduleSpec.ContainsKey("ModuleName") || String.IsNullOrEmpty((string) moduleSpec["ModuleName"])) + { + var exMessage = $"RequiredModules Hashtable entry {moduleSpec.ToString()} is missing a key 'ModuleName' and associated value, which is required for each module specification entry"; + var ex = new ArgumentException(exMessage); + var NameMissingModuleSpecError = new ErrorRecord(ex, "NameMissingInModuleSpecification", ErrorCategory.InvalidArgument, null); + errorList.Add(NameMissingModuleSpecError); + moduleSpecCreatedSuccessfully = false; + continue; + } + + // At this point it must contain ModuleName key. + string moduleSpecName = (string) moduleSpec["ModuleName"]; + ModuleSpecification currentModuleSpec = null; + if (!moduleSpec.ContainsKey("MaximumVersion") && !moduleSpec.ContainsKey("ModuleVersion") && !moduleSpec.ContainsKey("RequiredVersion")) + { + // Pass to ModuleSpecification(string) constructor. + // This constructor method would only throw for a null/empty string, which we've already validated against above. + currentModuleSpec = new ModuleSpecification(moduleSpecName); + + if (currentModuleSpec != null) + { + moduleSpecsList.Add(currentModuleSpec); + } + else + { + var exMessage = $"ModuleSpecification object was not able to be created for {moduleSpecName}"; + var ex = new ArgumentException(exMessage); + var ModuleSpecNotCreatedError = new ErrorRecord(ex, "ModuleSpecificationNotCreated", ErrorCategory.InvalidArgument, null); + errorList.Add(ModuleSpecNotCreatedError); + moduleSpecCreatedSuccessfully = false; + continue; + } + } + else + { + // ModuleSpecification(Hashtable) constructor for when ModuleName + {Required,Maximum,Module}Version value is also provided. + string moduleSpecMaxVersion = moduleSpec.ContainsKey("MaximumVersion") ? (string) moduleSpec["MaximumVersion"] : String.Empty; + string moduleSpecModuleVersion = moduleSpec.ContainsKey("ModuleVersion") ? (string) moduleSpec["ModuleVersion"] : String.Empty; + string moduleSpecRequiredVersion = moduleSpec.ContainsKey("RequiredVersion") ? (string) moduleSpec["RequiredVersion"] : String.Empty; + Guid moduleSpecGuid = moduleSpec.ContainsKey("Guid") ? (Guid) moduleSpec["Guid"] : Guid.Empty; + + if (String.IsNullOrEmpty(moduleSpecMaxVersion) && String.IsNullOrEmpty(moduleSpecModuleVersion) && String.IsNullOrEmpty(moduleSpecRequiredVersion)) + { + var exMessage = $"ModuleSpecification hashtable requires one of the following keys: MaximumVersion, ModuleVersion, RequiredVersion and failed to be created for {moduleSpecName}"; + var ex = new ArgumentException(exMessage); + var MissingModuleSpecificationMemberError = new ErrorRecord(ex, "MissingModuleSpecificationMember", ErrorCategory.InvalidArgument, null); + errorList.Add(MissingModuleSpecificationMemberError); + moduleSpecCreatedSuccessfully = false; + continue; + } + + Hashtable moduleSpecHash = new Hashtable(); + + moduleSpecHash.Add("ModuleName", moduleSpecName); + if (moduleSpecGuid != Guid.Empty) + { + moduleSpecHash.Add("Guid", moduleSpecGuid); + } + + if (!String.IsNullOrEmpty(moduleSpecMaxVersion)) + { + moduleSpecHash.Add("MaximumVersion", moduleSpecMaxVersion); + } + + if (!String.IsNullOrEmpty(moduleSpecModuleVersion)) + { + moduleSpecHash.Add("ModuleVersion", moduleSpecModuleVersion); + } + + if (!String.IsNullOrEmpty(moduleSpecRequiredVersion)) + { + moduleSpecHash.Add("RequiredVersion", moduleSpecRequiredVersion); + } + + try + { + currentModuleSpec = new ModuleSpecification(moduleSpecHash); + } + catch (Exception e) + { + var ex = new ArgumentException($"ModuleSpecification instance was not able to be created with hashtable constructor due to: {e.Message}"); + var ModuleSpecNotCreatedError = new ErrorRecord(ex, "ModuleSpecificationNotCreated", ErrorCategory.InvalidArgument, null); + errorList.Add(ModuleSpecNotCreatedError); + moduleSpecCreatedSuccessfully = false; + } + + if (currentModuleSpec != null) + { + moduleSpecsList.Add(currentModuleSpec); + } + } + } + + errors = errorList.ToArray(); + validatedModuleSpecs = moduleSpecsList.ToArray(); + return moduleSpecCreatedSuccessfully; + } + + /// + /// Parses metadata out of a comment block's lines (which are passed in) into a hashtable. + /// + public static Hashtable ParseCommentBlockContent(string[] commentLines) + { + /** + Comment lines can look like this: + + .KEY1 value + + .KEY2 value + + .KEY3 + value + + .KEY4 value + value continued + + */ + + Hashtable parsedHelpMetadata = new Hashtable(); + string keyName = ""; + string value = ""; + + for (int i = 1; i < commentLines.Count(); i++) + { + string line = commentLines[i]; + + // scenario where line is: .KEY VALUE + // this line contains a new metadata property. + if (line.Trim().StartsWith(".")) + { + // check if keyName was previously populated, if so add this key value pair to the metadata hashtable + if (!String.IsNullOrEmpty(keyName)) + { + parsedHelpMetadata.Add(keyName, value); + } + + string[] parts = line.Trim().TrimStart('.').Split(); + keyName = parts[0]; + value = parts.Count() > 1 ? String.Join(" ", parts.Skip(1)) : String.Empty; + } + else if (!String.IsNullOrEmpty(line)) + { + // scenario where line contains text that is a continuation of value from previously recorded key + // this line does not starting with .KEY, and is also not an empty line. + if (value.Equals(String.Empty)) + { + value += line; + } + else + { + value += Environment.NewLine + line; + } + } + } + + // this is the case where last key value had multi-line value. + // and we've captured it, but still need to add it to hashtable. + if (!String.IsNullOrEmpty(keyName) && !parsedHelpMetadata.ContainsKey(keyName)) + { + // only add this key value if it hasn't already been added + parsedHelpMetadata.Add(keyName, value); + } + + return parsedHelpMetadata; + } + #endregion #region Directory and File diff --git a/test/NewPSScriptFileInfo.Tests.ps1 b/test/NewPSScriptFileInfo.Tests.ps1 index 3ba34acf3..4b48ccd57 100644 --- a/test/NewPSScriptFileInfo.Tests.ps1 +++ b/test/NewPSScriptFileInfo.Tests.ps1 @@ -5,108 +5,107 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Test New-PSScriptFileInfo" { BeforeAll { - $script:TempPath = Get-TempPath + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDirPaths = @($tmpDir1Path) + Get-NewTestDirs($tmpDirPaths) } BeforeEach { - # Create temp script path - $script:TempScriptPath = Join-Path $script:TempPath "PSGet_$(Get-Random)" - $null = New-Item -Path $script:TempScriptPath -ItemType Directory -Force - - $script:PSScriptInfoName = "PSGetTestScript" - $script:testPSScriptInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath "$script:PSScriptInfoName.psd1" + $script:PSScriptInfoName = "test_script" + $script:testScriptFilePath = Join-Path -Path $tmpDir1Path -ChildPath "$script:PSScriptInfoName.ps1" } AfterEach { - RemoveItem "$script:TempScriptPath" + if (Test-Path -Path $script:testScriptFilePath) + { + Remove-Item $script:testScriptFilePath + } } - ### TODO: Add tests for -Force and -WhatIf if those parameters are applicable -<# It "Create .ps1 file with minimal required fields" { - $Description = "this is a test script" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Test-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath | Should -BeTrue + $description = "Test description" + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $description + Test-PSScriptFileInfo -FilePath $script:testScriptFilePath | Should -BeTrue } It "Create .ps1 file with relative path" { - $RelativeCurrentPath = Get-Location - $ScriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" - $Description = "this is a test script" - New-PSScriptFileInfo -FilePath $ScriptFilePath -Description $Description + $relativeCurrentPath = Get-Location + $scriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" + + $description = "Test description" + New-PSScriptFileInfo -FilePath $scriptFilePath -Description $description - Test-PSScriptFileInfo -FilePath $ScriptFilePath | Should -BeTrue - Remove-Item -Path $ScriptFilePath + Test-PSScriptFileInfo -FilePath $scriptFilePath | Should -BeTrue + Remove-Item -Path $scriptFilePath } It "Create new .ps1 given Version parameter" { - $Version = "2.0.0.0" - $Description = "Test description" + $version = "2.0.0.0" + $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version $version -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Version) | Should -BeTrue - $results.Contains(".VERSION $Version") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($version) | Should -BeTrue + $results.Contains(".VERSION $version") | Should -BeTrue } It "Create new .ps1 given Guid parameter" { - $Guid = [guid]::NewGuid() - $Description = "Test description" + $guid = [guid]::NewGuid() + $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Guid $Guid -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Guid $guid -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Guid) | Should -BeTrue - $results.Contains(".GUID $Guid") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($guid) | Should -BeTrue + $results.Contains(".GUID $guid") | Should -BeTrue } It "Create new .ps1 given Author parameter" { - $Author = "Test Author" - $Description = "Test description" + $author = "Test Author" + $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Author $Author -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Author $author -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Author) | Should -BeTrue - $results.Contains(".AUTHOR $Author") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($author) | Should -BeTrue + $results.Contains(".AUTHOR $author") | Should -BeTrue } It "Create new .ps1 given Description parameter" { - $Description = "PowerShellGet test description" - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($Description) | Should -BeTrue - $results -like ".DESCRIPTION*$Description" | Should -BeTrue + $description = "PowerShellGet test description" + + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $description + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($description) | Should -BeTrue + $results -like "*.DESCRIPTION$script:newline*$description*" | Should -BeTrue } It "Create new .ps1 given CompanyName parameter" { - $CompanyName = "Microsoft" - $Description = "Test description" + $companyName = "Microsoft" + $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -CompanyName $CompanyName -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -CompanyName $companyName -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($CompanyName) | Should -BeTrue - $results.Contains(".COMPANYNAME $Companyname") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($companyName) | Should -BeTrue + $results.Contains(".COMPANYNAME $companyname") | Should -BeTrue } It "Create new .ps1 given Copyright parameter" { - $Copyright = "(c) Test Corporation" - $Description = "Test description" + $copyright = "(c) Test Corporation" + $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Copyright $Copyright -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Copyright $copyright -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Copyright) | Should -BeTrue - $results.Contains(".COPYRIGHT $Copyright") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($copyright) | Should -BeTrue + $results.Contains(".COPYRIGHT $copyright") | Should -BeTrue } It "Create new .ps1 given RequiredModules parameter" { @@ -114,186 +113,129 @@ Describe "Test New-PSScriptFileInfo" { $requiredModuleVersion = '1.0.0.0' $RequiredModules = @(@{ModuleName = $requiredModuleName; ModuleVersion = $requiredModuleVersion }) - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredModules $RequiredModules -Description $Description + $description = "Test description" + + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredModules $RequiredModules -Description $Description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw $results.Contains($requiredModuleName) | Should -BeTrue $results.Contains($requiredModuleVersion) | Should -BeTrue - $results -like ".REQUIREDMODULES*$requiredModuleName*$requiredModuleVersion" | Should -BeTrue + $results -like "*#Requires*$requiredModuleName*$requiredModuleVersion*" | Should -BeTrue } It "Create new .ps1 given ReleaseNotes parameter" { - $Description = "Test Description" - $ReleaseNotes = "Release notes for script." + $description = "Test Description" + $releaseNotes = "Release notes for script." - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ReleaseNotes $ReleaseNotes -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ReleaseNotes $releaseNotes -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($ReleaseNotes) | Should -BeTrue - $results -like ".RELEASENOTES*$ReleaseNotes" | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($releaseNotes) | Should -BeTrue + $results -like "*.RELEASENOTES$script:newline*$ReleaseNotes*" | Should -BeTrue } It "Create new .ps1 given Tags parameter" { - $Description = "Test Description" - $Tag1 = "tag1" - $Tag2 = "tag2" + $description = "Test Description" + $tag1 = "tag1" + $tag2 = "tag2" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Tags $Tag1, $Tag2 -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Tags $tag1, $tag2 -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($Tag1) | Should -BeTrue - $results.Contains($Tag2) | Should -BeTrue - $results.Contains(".TAGS $Tag1 $Tag2") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($tag1) | Should -BeTrue + $results.Contains($tag2) | Should -BeTrue + $results.Contains(".TAGS $tag1 $tag2") | Should -BeTrue } It "Create new .ps1 given ProjectUri parameter" { - $Description = "Test Description" - $ProjectUri = "https://www.testprojecturi.com/" - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ProjectUri $ProjectUri -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($ProjectUri) | Should -BeTrue - $results.Contains(".PROJECTURI $ProjectUri") | Should -BeTrue + $description = "Test Description" + $projectUri = "https://www.testprojecturi.com/" + + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ProjectUri $projectUri -Description $description + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($projectUri) | Should -BeTrue + $results.Contains(".PROJECTURI $projectUri") | Should -BeTrue } It "Create new .ps1 given LicenseUri parameter" { - $Description = "Test Description" - $LicenseUri = "https://www.testlicenseuri.com/" + $description = "Test Description" + $licenseUri = "https://www.testlicenseuri.com/" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -LicenseUri $LicenseUri -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -LicenseUri $licenseUri -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($LicenseUri) | Should -BeTrue - $results.Contains(".LICENSEURI $LicenseUri") | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($licenseUri) | Should -BeTrue + $results.Contains(".LICENSEURI $licenseUri") | Should -BeTrue } It "Create new .ps1 given IconUri parameter" { - $Description = "Test Description" - $IconUri = "https://www.testiconuri.com/" - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -IconUri $IconUri -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($IconUri) | Should -BeTrue - $results.Contains(".ICONURI $IconUri") | Should -BeTrue - } + $description = "Test Description" + $iconUri = "https://www.testiconuri.com/" - It "Create new .ps1 given ExternalModuleDependencies parameter" { - $Description = "Test Description" - $ExternalModuleDep1 = "ExternalModuleDep1" - $ExternalModuleDep2 = "ExternalModuleDep2" - $ExternalModuleDep1FileName = "ExternalModuleDep1.psm1" - $ExternalModuleDep2FileName = "ExternalModuleDep2.psm1" - $ExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalModuleDep1FileName - $ExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalModuleDep2FileName - - $null = New-Item -Path $ExternalModuleDepPath1 -ItemType File -Force - $null = New-Item -Path $ExternalModuleDepPath2 -ItemType File -Force - - # NOTE: you may need to add the -NestedModules parameter here as well - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $ExternalModuleDep1, $ExternalModuleDep2 -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($ExternalModuleDep1) | Should -BeTrue - $results.Contains($ExternalModuleDep2) | Should -BeTrue - $results -like ".EXTERNALMODULEDEPENDENCIES*$ExternalModuleDep1*$ExternalModuleDep2" | Should -BeTrue - } + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -IconUri $iconUri -Description $description - It "Create new .ps1 given RequiredAssemblies parameter" { - $Description = "Test Description" - $RequiredAssembly1 = "RequiredAssembly1.dll" - $RequiredAssembly2 = "RequiredAssembly2.dll" - $RequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredAssembly1 - $RequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredAssembly2 + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($iconUri) | Should -BeTrue + $results.Contains(".ICONURI $iconUri") | Should -BeTrue + } - $null = New-Item -Path $RequiredAssemblyPath1 -ItemType File -Force - $null = New-Item -Path $RequiredAssemblyPath2 -ItemType File -Force + It "Create new .ps1 given ExternalModuleDependencies parameter" { + $description = "Test Description" + $externalModuleDep1 = "ExternalModuleDep1" + $externalModuleDep2 = "ExternalModuleDep2" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredAssemblies $RequiredAssembly1, $RequiredAssembly2 -Description $Description + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalModuleDependencies $externalModuleDep1, $externalModuleDep2 -Description $description - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($RequiredAssembly1) | Should -BeTrue - $results.Contains($RequiredAssembly2) | Should -BeTrue - $results -like ".REQUIREDASSEMBLIES*$RequiredAssembly1*$RequiredAssembly2" | Should -BeTrue - } - - It "Create new .ps1 given NestedModules parameter" { - $Description = "Test Description" - $NestedModule1 = "NestedModule1" - $NestedModule2 = "NestedModule2" - $NestModuleFileName1 = "NestedModule1.dll" - $NestModuleFileName2 = "NestedModule2.dll" - $NestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NestModuleFileName1 - $NestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NestModuleFileName2 - - $null = New-Item -Path $NestedModulePath1 -ItemType File -Force - $null = New-Item -Path $NestedModulePath2 -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -NestedModules $NestedModule1, $NestedModule2 -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NestedModule1) | Should -BeTrue - $results.Contains($NestedModule2) | Should -BeTrue - $results -like ".NESTEDMODULES*$NestedModule1*$NestedModule2" | Should -BeTrue + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($externalModuleDep1) | Should -BeTrue + $results.Contains($externalModuleDep2) | Should -BeTrue + $results -like "*.EXTERNALMODULEDEPENDENCIES*$externalModuleDep1*$externalModuleDep2*" | Should -BeTrue } It "Create new .ps1 given RequiredScripts parameter" { - $Description = "Test Description" - $RequiredScript1 = "NestedModule1.ps1" - $RequiredScript2 = "NestedModule2.ps1" - $RequiredScript1Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredScript1 - $RequiredScript2Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $RequiredScript2 - - $null = New-Item -Path $RequiredScript1Path -ItemType File -Force - $null = New-Item -Path $RequiredScript2Path -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredScripts $RequiredScript1, $RequiredScript2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($RequiredScript1) | Should -BeTrue - $results.Contains($RequiredScript2) | Should -BeTrue - $results -like ".REQUIREDSCRIPTS*$RequiredScript1*$RequiredScript2" | Should -BeTrue + $description = "Test Description" + $requiredScript1 = "RequiredScript1" + $requiredScript2 = "RequiredScript2" + + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredScripts $requiredScript1, $requiredScript2 -Description $description + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($requiredScript1) | Should -BeTrue + $results.Contains($requiredScript2) | Should -BeTrue + $results -like "*.REQUIREDSCRIPTS*$requiredScript1*$requiredScript2*" | Should -BeTrue } It "Create new .ps1 given ExternalScriptDependencies parameter" { - $Description = "Test Description" - $ExternalScriptDep1 = "ExternalScriptDep1.ps1" - $ExternalScriptDep2 = "ExternalScriptDep2.ps1" - $ExternalScriptDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalScriptDep1 - $ExternalScriptDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $ExternalScriptDep2 - - $null = New-Item -Path $ExternalScriptDepPath1 -ItemType File -Force - $null = New-Item -Path $ExternalScriptDepPath2 -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $ExternalModuleDep1, $ExternalModuleDep2 -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($ExternalModuleDep1) | Should -BeTrue - $results.Contains($ExternalModuleDep2) | Should -BeTrue - $results -like ".EXTERNALSCRIPTDEPENDENCIES*$ExternalScriptDep1*$ExternalScriptDep2" | Should -BeTrue + $description = "Test Description" + $externalScriptDep1 = "ExternalScriptDep1" + $externalScriptDep2 = "ExternalScriptDep2" + + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalScriptDependencies $externalScriptDep1, $externalScriptDep2 -Description $description + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($externalScriptDep1) | Should -BeTrue + $results.Contains($externalScriptDep2) | Should -BeTrue + $results -like "*.EXTERNALSCRIPTDEPENDENCIES*$externalScriptDep1*$externalScriptDep2*" | Should -BeTrue } It "Create new .ps1 given PrivateData parameter" { - $Description = "Test Description" - $PrivateData = @{"PrivateDataEntry1" = "PrivateDataValue1"} - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -PrivateData $PrivateData -Description $Description - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($PrivateData) | Should -BeTrue - $results -like ".PRIVATEDATA*$PrivateData" | Should -BeTrue + $description = "Test Description" + $privateData = @{"PrivateDataEntry1" = "PrivateDataValue1"} + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -PrivateData $privateData -Description $description + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($privateData) | Should -BeTrue + $results -like "*.PRIVATEDATA*$privateData*" | Should -BeTrue } -#> -} \ No newline at end of file +} diff --git a/test/TestPSScriptFileInfo.Tests.ps1 b/test/TestPSScriptFileInfo.Tests.ps1 new file mode 100644 index 000000000..30adae47b --- /dev/null +++ b/test/TestPSScriptFileInfo.Tests.ps1 @@ -0,0 +1,60 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Test-PSScriptFileInfo" { + BeforeAll { + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDirPaths = @($tmpDir1Path) + Get-NewTestDirs($tmpDirPaths) + + # Path to folder, within our test folder, where we store invalid module and script files used for testing + $script:testFilesFolderPath = Join-Path $psscriptroot -ChildPath "testFiles" + + # Path to specifically to that invalid test scripts folder + $script:testScriptsFolderPath = Join-Path $testFilesFolderPath -ChildPath "testScripts" + } + + It "determine script file with minimal required fields as valid" { + $scriptFilePath = Join-Path -Path $tmpDir1Path -ChildPath "testscript.ps1" + $scriptDescription = "this is a test script" + New-PSScriptFileInfo -FilePath $scriptFilePath -Description $scriptDescription + Test-PSScriptFileInfo $scriptFilePath | Should -Be $true + } + + It "not determine script file with Author field missing as valid" { + $scriptName = "InvalidScriptMissingAuthor.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $false + } + + It "not determine script file with Description field missing as valid" { + $scriptName = "InvalidScriptMissingDescription.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $false + } + + It "not determine script that is missing Description block altogether as valid" { + $scriptName = "InvalidScriptMissingDescriptionCommentBlock.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $false + } + + It "not determine script file Guid as valid" { + $scriptName = "InvalidScriptMissingGuid.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $false + } + + It "not determine script file missing Version as valid" { + $scriptName = "InvalidScriptMissingVersion.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $false + } +} diff --git a/test/TestPSScriptInfo.Tests.ps1 b/test/TestPSScriptInfo.Tests.ps1 deleted file mode 100644 index fa79f8bf9..000000000 --- a/test/TestPSScriptInfo.Tests.ps1 +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe "Test Test-PSScriptFileInfo" { - - BeforeAll { - $script:TempPath = Get-TempPath - } - BeforeEach { - # Create temp script path - $script:TempScriptPath = Join-Path $script:TempPath "PSGet_$(Get-Random)" - $null = New-Item -Path $script:TempScriptPath -ItemType Directory -Force - - $script:PSScriptInfoName = "PSGetTestScript" - $script:testPSScriptInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath "$script:PSScriptInfoName.psd1" - } - AfterEach { - RemoveItem "$script:TempScriptPath" - } - - ### TODO: Add tests for -Force and -WhatIf if those parameters are applicable - <# - It "Test .ps1 file with minimal required fields" { - $Description = "This is a test script" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Test-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath | Should -BeTrue - } - - It "Test .ps1 file with relative path" { - $RelativeCurrentPath = Get-Location - $ScriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" - $Description = "this is a test script" - New-PSScriptFileInfo -FilePath $ScriptFilePath -Description $Description - - Test-PSScriptFileInfo -FilePath $ScriptFilePath | Should -BeTrue - Remove-Item -Path $ScriptFilePath - } - #> -} diff --git a/test/UpdatePSScriptFileInfo.Tests.ps1 b/test/UpdatePSScriptFileInfo.Tests.ps1 new file mode 100644 index 000000000..6eac2d1d0 --- /dev/null +++ b/test/UpdatePSScriptFileInfo.Tests.ps1 @@ -0,0 +1,314 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force + +Describe "Test Update-PSScriptFileInfo" { + BeforeAll { + $tmpDir1Path = Join-Path -Path $TestDrive -ChildPath "tmpDir1" + $tmpDirPaths = @($tmpDir1Path) + Get-NewTestDirs($tmpDirPaths) + + # Path to folder, within our test folder, where we store invalid module and script files used for testing + $script:testFilesFolderPath = Join-Path $psscriptroot -ChildPath "testFiles" + + # Path to specifically to that invalid test scripts folder + $script:testScriptsFolderPath = Join-Path $testFilesFolderPath -ChildPath "testScripts" + + $script:newline = [System.Environment]::NewLine; + } + + BeforeEach { + $script:psScriptInfoName = "test_script" + $scriptDescription = "this is a test script" + $script:testScriptFilePath = Join-Path -Path $tmpDir1Path -ChildPath "$script:psScriptInfoName.ps1" + New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $scriptDescription + } + + AfterEach { + if (Test-Path -Path $script:testScriptFilePath) + { + Remove-Item $script:testScriptFilePath + } + } + + It "Update .ps1 file with relative path" { + $relativeCurrentPath = Get-Location + $scriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:psScriptInfoName.ps1" + $oldDescription = "Old description for test script" + $newDescription = "New description for test script" + New-PSScriptFileInfo -FilePath $scriptFilePath -Description $oldDescription + + Update-PSScriptFileInfo -FilePath $scriptFilePath -Description $newDescription + Test-PSScriptFileInfo -FilePath $scriptFilePath | Should -BeTrue + + Test-Path -Path $scriptFilePath | Should -BeTrue + $results = Get-Content -Path $scriptFilePath -Raw + $results.Contains($newDescription) | Should -BeTrue + $results -like "*.DESCRIPTION$script:newline*$newDescription*" | Should -BeTrue + + Remove-Item -Path $scriptFilePath -Force + } + + It "Update script should not overwrite old script data unless that property is specified" { + $description = "Test Description" + $version = "3.0.0" + $author = "John Doe" + $newAuthor = "Jane Doe" + $projectUri = "https://testscript.com/" + + $relativeCurrentPath = Get-Location + $scriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:psScriptInfoName.ps1" + + New-PSScriptFileInfo -FilePath $scriptFilePath -Description $description -Version $version -Author $author -ProjectUri $projectUri + Update-PSScriptFileInfo -FilePath $scriptFilePath -Author $newAuthor + + Test-PSScriptFileInfo -FilePath $scriptFilePath | Should -BeTrue + $results = Get-Content -Path $scriptFilePath -Raw + $results.Contains($newAuthor) | Should -BeTrue + $results.Contains(".AUTHOR $newAuthor") | Should -BeTrue + + # rest should be original data used when creating the script + $results.Contains($projectUri) | Should -BeTrue + $results.Contains(".PROJECTURI $projectUri") | Should -BeTrue + + $results.Contains($version) | Should -BeTrue + $results.Contains(".VERSION $version") | Should -BeTrue + + $results.Contains($description) | Should -BeTrue + $results -like "*.DESCRIPTION$script:newline*$description*" | Should -BeTrue + + Remove-Item -Path $scriptFilePath -Force + } + + It "update script file Author property" { + $author = "New Author" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Author $author + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($author) | Should -BeTrue + $results.Contains(".AUTHOR $author") | Should -BeTrue + } + + It "update script file Version property" { + $version = "2.0.0.0" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version $version + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($version) | Should -BeTrue + $results.Contains(".VERSION $version") | Should -BeTrue + } + + It "update script file Version property with prerelease version" { + $version = "3.0.0-alpha" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version $version + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($version) | Should -BeTrue + $results.Contains(".VERSION $version") | Should -BeTrue + } + + It "not update script file with invalid version" { + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version "4.0.0.0.0" -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "VersionParseIntoNuGetVersion,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" + } + + It "update script file Description property" { + $description = "this is an updated test script" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $description + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($description) | Should -BeTrue + $results -like "*.DESCRIPTION$script:newline*$description*" | Should -BeTrue + } + + It "update script file Guid property" { + $guid = [Guid]::NewGuid(); + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Guid $guid + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($guid) | Should -BeTrue + $results.Contains(".GUID $guid") | Should -BeTrue + } + + It "update script file CompanyName property" { + $companyName = "New Corporation" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -CompanyName $companyName + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($companyName) | Should -BeTrue + $results.Contains(".COMPANYNAME $companyName") | Should -BeTrue + } + + It "update script file Copyright property" { + $copyright = "(c) 2022 New Corporation. All rights reserved" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Copyright $copyright + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($copyright) | Should -BeTrue + $results.Contains(".COPYRIGHT $copyright") | Should -BeTrue + } + + It "update script file ExternalModuleDependencies property" { + $externalModuleDep1 = "ExternalModuleDep1" + $externalModuleDep2 = "ExternalModuleDep2" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalModuleDependencies $externalModuleDep1,$externalModuleDep2 + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($externalModuleDep1) | Should -BeTrue + $results.Contains($externalModuleDep2) | Should -BeTrue + $results -like "*.EXTERNALMODULEDEPENDENCIES*$externalModuleDep1*$externalModuleDep2*" | Should -BeTrue + } + + It "update script file ExternalScriptDependencies property" { + $externalScriptDep1 = "ExternalScriptDep1" + $externalScriptDep2 = "ExternalScriptDep2" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalScriptDependencies $externalScriptDep1,$externalScriptDep2 + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($externalScriptDep1) | Should -BeTrue + $results.Contains($externalScriptDep2) | Should -BeTrue + $results -like "*.EXTERNALMODULEDEPENDENCIES*$externalScriptDep1*$externalScriptDep2*" | Should -BeTrue + } + + It "update script file IconUri property" { + $iconUri = "https://testscript.com/icon" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -IconUri $iconUri + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($iconUri) | Should -BeTrue + $results.Contains(".ICONURI $iconUri") | Should -BeTrue + } + + It "update script file LicenseUri property" { + $licenseUri = "https://testscript.com/license" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -LicenseUri $licenseUri + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($licenseUri) | Should -BeTrue + $results.Contains(".LICENSEURI $licenseUri") | Should -BeTrue + } + + It "update script file ProjectUri property" { + $projectUri = "https://testscript.com/" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ProjectUri $projectUri + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($projectUri) | Should -BeTrue + $results.Contains(".PROJECTURI $projectUri") | Should -BeTrue + } + + It "update script file PrivateData property" { + $privateData = "this is some private data" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -PrivateData $privateData + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($privateData) | Should -BeTrue + $results -like "*.PRIVATEDATA*$privateData*" | Should -BeTrue + } + + It "update script file ReleaseNotes property" { + $releaseNotes = "Release notes for script." + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ReleaseNotes $releaseNotes + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($releaseNotes) | Should -BeTrue + $results -like "*.RELEASENOTES$script:newline*$releaseNotes*" | Should -BeTrue + } + + It "update script file RequiredModules property" { + $hashtable1 = @{ModuleName = "RequiredModule1"} + $hashtable2 = @{ModuleName = "RequiredModule2"; ModuleVersion = "1.0.0.0"} + $hashtable3 = @{ModuleName = "RequiredModule3"; RequiredVersion = "2.5.0.0"} + $hashtable4 = @{ModuleName = "RequiredModule4"; ModuleVersion = "1.1.0.0"; MaximumVersion = "2.0.0.0"} + $requiredModules = $hashtable1, $hashtable2, $hashtable3, $hashtable4 + + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredModules $requiredModules + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains("#Requires -Module RequiredModule1") | Should -BeTrue + $results -like "*#Requires*ModuleName*Version*" | Should -BeTrue + } + + It "update script file RequiredScripts property" { + $requiredScript1 = "RequiredScript1" + $requiredScript2 = "RequiredScript2" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredScripts $requiredScript1, $requiredScript2 + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($requiredScript1) | Should -BeTrue + $results.Contains($requiredScript2) | Should -BeTrue + $results -like "*.REQUIREDSCRIPTS*$requiredScript1*$requiredScript2*" | Should -BeTrue + } + + It "update script file Tags property" { + $tag1 = "tag1" + $tag2 = "tag2" + Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Tags $tag1, $tag2 + Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true + + Test-Path -Path $script:testScriptFilePath | Should -BeTrue + $results = Get-Content -Path $script:testScriptFilePath -Raw + $results.Contains($tag1) | Should -BeTrue + $results.Contains($tag2) | Should -BeTrue + $results.Contains(".TAGS $tag1 $tag2") | Should -BeTrue + } + + It "throw error when attempting to update a signed script without -RemoveSignature parameter" { + # Note: user should sign the script again once it's been updated + + $scriptName = "ScriptWithSignature.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + # use a copy of the signed script file so we can re-use for other tests + $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive + $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName + + { Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" } | Should -Throw -ErrorId "ScriptToBeUpdatedContainsSignature,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" + } + + It "update signed script when using RemoveSignature parameter" { + $scriptName = "ScriptWithSignature.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + # use a copy of the signed script file so we can re-use for other tests + $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive + $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName + + Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" -RemoveSignature + Test-PSScriptFileInfo -FilePath $tmpScriptFilePath | Should -Be $true + } +} diff --git a/test/UpdatePSScriptInfo.Tests.ps1 b/test/UpdatePSScriptInfo.Tests.ps1 deleted file mode 100644 index eb1450eaf..000000000 --- a/test/UpdatePSScriptInfo.Tests.ps1 +++ /dev/null @@ -1,415 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe "Test Update-PSScriptFileInfo" { - - BeforeAll { - $script:TempPath = Get-TempPath - } - BeforeEach { - # Create temp script path - $script:TempScriptPath = Join-Path $script:TempPath "PSGet_$(Get-Random)" - $null = New-Item -Path $script:TempScriptPath -ItemType Directory -Force - - $script:PSScriptInfoName = "PSGetTestScript" - $script:testPSScriptInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath "$script:PSScriptInfoName.psd1" - } - AfterEach { - RemoveItem "$script:TempScriptPath" - } - - ### TODO: Add tests for -Force and -WhatIf if those parameters are applicable -<# - It "Update .ps1 file with relative path" { - $RelativeCurrentPath = Get-Location - $ScriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" - $OldDescription = "Old description for test script" - $NewDescription = "Old description for test script" - New-PSScriptFileInfo -FilePath $ScriptFilePath -Description $OldDescription - - Update-PSScriptFileInfo -FilePath $ScriptFilePath -Description $NewDescription - - Test-PSScriptFileInfo -FilePath $ScriptFilePath | Should -BeTrue - Remove-Item -Path $ScriptFilePath - } - - It "Update .ps1 given Version parameter" { - $Version = "2.0.0.0" - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Version) | Should -BeTrue - $results.Contains(".VERSION $Version") | Should -BeTrue - } - - It "Update .ps1 given prerelease version" { - $Version = "2.0.0.0-alpha" - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Version) | Should -BeTrue - $results.Contains(".VERSION $Version") | Should -BeTrue - } - - It "Should not update .ps1 with invalid version" { - $Version = "4.0.0.0.0" - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Version $Version -ErrorVariable err -ErrorAction SilentlyContinue - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeFalse - $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "VersionParseIntoNuGetVersion,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" - } - - It "Update .ps1 given Guid parameter" { - $Guid = [guid]::NewGuid() - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Guid $Guid - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Guid) | Should -BeTrue - $results.Contains(".GUID $Guid") | Should -BeTrue - } - - It "Update .ps1 given Author parameter" { - $Author = "New Author" - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Author $Author - - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($Author) | Should -BeTrue - $results.Contains(".AUTHOR $Author") | Should -BeTrue - } - - It "Update .ps1 given Description parameter" { - $OldDescription = "Old description for test script." - $NewDescription = "New description for test script." - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $OldDescription - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Description $NewDescription - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewDescription) | Should -BeTrue - $results -like ".DESCRIPTION*$NewDescription" | Should -BeTrue - } - - It "Update .ps1 given CompanyName parameter" { - $OldCompanyName = "Old company name" - $NewCompanyName = "New company name" - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -CompanyName $OldCompanyName -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -CompanyName $NewCompanyName - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($NewCompanyName) | Should -BeTrue - $results.Contains(".COMPANYNAME $NewCompanyName") | Should -BeTrue - } - - It "Update .ps1 given Copyright parameter" { - $OldCopyright = "(c) Old Test Corporation" - $NewCopyright = "(c) New Test Corporation" - $Description = "Test description" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Copyright $OldCopyright -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Copyright $NewCopyright - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testPSScriptInfoPath -Raw - $results.Contains($NewCopyright) | Should -BeTrue - $results.Contains(".COPYRIGHT $NewCopyright") | Should -BeTrue - } - - It "Update .ps1 given RequiredModules parameter" { - $RequiredModuleName = 'PackageManagement' - $OldrequiredModuleVersion = '1.0.0.0' - $OldRequiredModules = @(@{ModuleName = $RequiredModuleName; ModuleVersion = $OldrequiredModuleVersion }) - $NewrequiredModuleVersion = '2.0.0.0' - $NewRequiredModules = @(@{ModuleName = $RequiredModuleName; ModuleVersion = $NewrequiredModuleVersion }) - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredModules $OldRequiredModules -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredModules $NewRequiredModules - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($RequiredModuleName) | Should -BeTrue - $results.Contains($NewrequiredModuleVersion) | Should -BeTrue - $results -like ".REQUIREDMODULES*$RequiredModuleName*$NewrequiredModuleVersion" | Should -BeTrue - } - - It "Update .ps1 given ReleaseNotes parameter" { - $Description = "Test Description" - $OldReleaseNotes = "Old release notes for script." - $NewReleaseNotes = "New release notes for script." - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ReleaseNotes $OldReleaseNotes -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ReleaseNotes $NewReleaseNotes - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewReleaseNotes) | Should -BeTrue - $results -like ".RELEASENOTES*$NewReleaseNotes" | Should -BeTrue - } - - It "Update .ps1 given Tags parameter" { - $Description = "Test Description" - $OldTag1 = "Tag1" - $OldTag2 = "Tag2" - $NewTag1 = "NewTag1" - $NewTag2 = "NewTag2" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Tags $OldTag1, $OldTag2 -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -Tags $NewTag1, $NewTag2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewTag1) | Should -BeTrue - $results.Contains($NewTag2) | Should -BeTrue - $results.Contains(".TAGS $NewTag1 $NewTag2") | Should -BeTrue - } - - It "Update .ps1 given ProjectUri parameter" { - $Description = "Test Description" - $OldProjectUri = "https://www.oldtestprojecturi.com/" - $NewProjectUri = "https://www.newtestprojecturi.com/" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ProjectUri $OldProjectUri -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ProjectUri $NewProjectUri - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewProjectUri) | Should -BeTrue - $results.Contains(".PROJECTURI $NewProjectUri") | Should -BeTrue - } - - It "Update .ps1 given LicenseUri parameter" { - $Description = "Test Description" - $OldLicenseUri = "https://www.oldtestlicenseuri.com/" - $NewLicenseUri = "https://www.newtestlicenseuri.com/" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -LicenseUri $OldLicenseUri -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -LicenseUri $NewLicenseUri - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewLicenseUri) | Should -BeTrue - $results.Contains(".LICENSEURI $NewLicenseUri") | Should -BeTrue - } - - It "Update .ps1 given IconUri parameter" { - $Description = "Test Description" - $OldIconUri = "https://www.oldtesticonuri.com/" - $NewIconUri = "https://www.newtesticonuri.com/" - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -IconUri $OldIconUri -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -IconUri $NewIconUri - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewIconUri) | Should -BeTrue - $results.Contains(".ICONURI $NewIconUri") | Should -BeTrue - } - - It "Update .ps1 given ExternalModuleDependencies parameter" { - $Description = "Test Description" - $OldExternalModuleDep1 = "OldExternalModuleDep1" - $OldExternalModuleDep2 = "OldExternalModuleDep2" - $OldExternalModuleDep1FileName = "OldExternalModuleDep1.psm1" - $OldExternalModuleDep2FileName = "OldExternalModuleDep2.psm1" - $OldExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalModuleDep1FileName - $OldExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalModuleDep2FileName - $null = New-Item -Path $OldExternalModuleDepPath1 -ItemType File -Force - $null = New-Item -Path $OldExternalModuleDepPath2 -ItemType File -Force - - $NewExternalModuleDep1 = "NewExternalModuleDep1" - $NewExternalModuleDep2 = "NewExternalModuleDep2" - $NewExternalModuleDep1FileName = "NewExternalModuleDep1.psm1" - $NewExternalModuleDep2FileName = "NewExternalModuleDep2.psm1" - $NewExternalModuleDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalModuleDep1FileName - $NewExternalModuleDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalModuleDep2FileName - $null = New-Item -Path $NewExternalModuleDepPath1 -ItemType File -Force - $null = New-Item -Path $NewExternalModuleDepPath2 -ItemType File -Force - - # NOTE: you may need to add the -NestedModules parameter here as well - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $OldExternalModuleDep1, $OldExternalModuleDep2 -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $NewExternalModuleDep1, $NewExternalModuleDep2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewExternalModuleDep1) | Should -BeTrue - $results.Contains($NewExternalModuleDep2) | Should -BeTrue - $results -like ".EXTERNALMODULEDEPENDENCIES*$NewExternalModuleDep1*$NewExternalModuleDep2" | Should -BeTrue - } - - It "Update .ps1 given RequiredAssemblies parameter" { - $Description = "Test Description" - $OldRequiredAssembly1 = "OldRequiredAssembly1.dll" - $OldRequiredAssembly2 = "OldRequiredAssembly2.dll" - $OldRequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredAssembly1 - $OldRequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredAssembly2 - $null = New-Item -Path $OldRequiredAssemblyPath1 -ItemType File -Force - $null = New-Item -Path $OldRequiredAssemblyPath2 -ItemType File -Force - - $NewRequiredAssembly1 = "NewRequiredAssembly1.dll" - $NewRequiredAssembly2 = "NewRequiredAssembly2.dll" - $NewRequiredAssemblyPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredAssembly1 - $NewRequiredAssemblyPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredAssembly2 - $null = New-Item -Path $NewRequiredAssemblyPath1 -ItemType File -Force - $null = New-Item -Path $NewRequiredAssemblyPath2 -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredAssemblies $OldRequiredAssembly1, $OldRequiredAssembly2 -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredAssemblies $NewRequiredAssembly1, $NewRequiredAssembly2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewRequiredAssembly1) | Should -BeTrue - $results.Contains($NewRequiredAssembly2) | Should -BeTrue - $results -like ".REQUIREDASSEMBLIES*$NewRequiredAssembly1*$NewRequiredAssembly2" | Should -BeTrue - } - - It "Update .ps1 given NestedModules parameter" { - $Description = "Test Description" - $OldNestedModule1 = "OldNestedModule1" - $OldNestedModule2 = "OldNestedModule2" - $OldNestModuleFileName1 = "OldNestedModule1.dll" - $OldNestModuleFileName2 = "OldNestedModule2.dll" - $OldNestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldNestModuleFileName1 - $OldNestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldNestModuleFileName2 - $null = New-Item -Path $OldNestedModulePath1 -ItemType File -Force - $null = New-Item -Path $OldNestedModulePath2 -ItemType File -Force - - $NewNestedModule1 = "NewNestedModule1" - $NewNestedModule2 = "NewNestedModule2" - $NewNestModuleFileName1 = "NewNestedModule1.dll" - $NewNestModuleFileName2 = "NewNestedModule2.dll" - $NewNestedModulePath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewNestModuleFileName1 - $NewNestedModulePath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewNestModuleFileName2 - $null = New-Item -Path $NewNestedModulePath1 -ItemType File -Force - $null = New-Item -Path $NewNestedModulePath2 -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -NestedModules $OldNestedModule1, $OldNestedModule2 -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -NestedModules $NewNestedModule1, $NewNestedModule2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewNestedModule1) | Should -BeTrue - $results.Contains($NewNestedModule2) | Should -BeTrue - $results -like ".NESTEDMODULES*$NewNestedModule1*$NewNestedModule2" | Should -BeTrue - } - - It "Update .ps1 given RequiredScripts parameter" { - $Description = "Test Description" - $OldRequiredScript1 = "OldNestedModule1.ps1" - $OldRequiredScript2 = "OldNestedModule2.ps1" - $OldRequiredScript1Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredScript1 - $OldRequiredScript2Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldRequiredScript2 - $null = New-Item -Path $OldRequiredScript1Path -ItemType File -Force - $null = New-Item -Path $OldRequiredScript2Path -ItemType File -Force - - $NewRequiredScript1 = "NewNestedModule1.ps1" - $NewRequiredScript2 = "NewNestedModule2.ps1" - $NewRequiredScript1Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredScript1 - $NewRequiredScript2Path = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewRequiredScript2 - $null = New-Item -Path $NewRequiredScript1Path -ItemType File -Force - $null = New-Item -Path $NewRequiredScript2Path -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredScripts $OldRequiredScript1, $OldRequiredScript2 -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -RequiredScripts $NewRequiredScript1, $NewRequiredScript2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewRequiredScript1) | Should -BeTrue - $results.Contains($NewRequiredScript2) | Should -BeTrue - $results -like ".REQUIREDSCRIPTS*$NewRequiredScript1*$NewRequiredScript2" | Should -BeTrue - } - - It "Update .ps1 given ExternalScriptDependencies parameter" { - $Description = "Test Description" - $OldExternalScriptDep1 = "OldExternalScriptDep1.ps1" - $OldExternalScriptDep2 = "OldExternalScriptDep2.ps1" - $OldExternalScriptDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalScriptDep1 - $OldExternalScriptDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $OldExternalScriptDep2 - $null = New-Item -Path $OldExternalScriptDepPath1 -ItemType File -Force - $null = New-Item -Path $OldExternalScriptDepPath2 -ItemType File -Force - - $NewExternalScriptDep1 = "NewExternalScriptDep1.ps1" - $NewExternalScriptDep2 = "NewExternalScriptDep2.ps1" - $NewExternalScriptDepPath1 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalScriptDep1 - $NewExternalScriptDepPath2 = Microsoft.PowerShell.Management\Join-Path -Path $script:TempScriptPath -ChildPath $NewExternalScriptDep2 - $null = New-Item -Path $NewExternalScriptDepPath1 -ItemType File -Force - $null = New-Item -Path $NewExternalScriptDepPath2 -ItemType File -Force - - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $OldExternalModuleDep1, $OldExternalModuleDep2 -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -ExternalModuleDependencies $NewExternalModuleDep1, $NewExternalModuleDep2 - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewExternalModuleDep1) | Should -BeTrue - $results.Contains($NewExternalModuleDep2) | Should -BeTrue - $results -like ".EXTERNALSCRIPTDEPENDENCIES*$NewExternalModuleDep1*$NewExternalModuleDep2" | Should -BeTrue - } - - It "Update .ps1 given PrivateData parameter" { - $Description = "Test Description" - $OldPrivateData = @{"OldPrivateDataEntry1" = "OldPrivateDataValue1"} - $NewPrivateData = @{"NewPrivateDataEntry1" = "NewPrivateDataValue1"} - New-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -PrivateData $OldPrivateData -Description $Description - - Update-PSScriptFileInfo -FilePath $script:testPSScriptInfoPath -PrivateData $NewPrivateData - - Test-Path -FilePath $script:testPSScriptInfoPath | Should -BeTrue - $results = Get-Content -Path $script:testManifestPath -Raw - $results.Contains($NewPrivateData) | Should -BeTrue - $results -like ".PRIVATEDATA*$NewPrivateData" | Should -BeTrue - } - - It "Update signed script when using RemoveSignature parameter" { - $scriptName = "ScriptWithSignature.ps1" - $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName - - # use a copy of the signed script file so we can re-use for other tests - $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive - $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName - - Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" -RemoveSignature - Test-PSScriptFileInfo -FilePath $tmpScriptFilePath | Should -Be $true - } - - It "Throw error when attempting to update a signed script without -RemoveSignature parameter" { - $scriptName = "ScriptWithSignature.ps1" - $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName - - # use a copy of the signed script file so we can re-use for other tests - $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive - $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName - - { Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" } | Should -Throw -ErrorId "ScriptToBeUpdatedContainsSignature,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" - } -#> -} \ No newline at end of file diff --git a/test/testFiles/testScripts/ScriptWithSignature.ps1 b/test/testFiles/testScripts/ScriptWithSignature.ps1 new file mode 100644 index 000000000..9bd193af7 --- /dev/null +++ b/test/testFiles/testScripts/ScriptWithSignature.ps1 @@ -0,0 +1,75 @@ + +<#PSScriptInfo + +.VERSION 1.0 + +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd + +.AUTHOR annavied + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + this is a test for a script that will be published remotely + +#> +Param() + + + +# SIG # Begin signature block +# MIIFbQYJKoZIhvcNAQcCoIIFXjCCBVoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB +# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR +# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUhY04RvNe0Q8hliL7qS3/X9kr +# QVugggMIMIIDBDCCAeygAwIBAgIQN+zCRZRKiphJ5gGoRKvpeTANBgkqhkiG9w0B +# AQsFADAaMRgwFgYDVQQDDA9Db2RlU2lnbmluZ0NlcnQwHhcNMjIwNjIyMTgyODUx +# WhcNMjQwNjIyMTgzODUwWjAaMRgwFgYDVQQDDA9Db2RlU2lnbmluZ0NlcnQwggEi +# MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf7gQAR4AVpVc4/4OlffaEQ6uE +# klG01+ga7sZbV7z9UkJFIDbntapCoXV85w/bNbmWSI+IUDisVBS7BIoicKagHskE +# YhRJv6WL/zxD2lWP21MRkEJBEMicbrj38F2R/khGDq/T5/a1XH+7QVAsf1kOG/oU +# d0CUDqgsR5+JdpaMt/QRM/jFLEUdvs+7zCvduciEEQRFFUbYYqy9RfmxMpPxZ6CM +# RjLVr5k4tirbg1YyBK6l7xPvT3BUejGvEYPOdAskPXMVbMO37DyEszudqOz9eEvp +# yHCKOgePLeq+9DbOQ+fAy30c79YNU5JfvgaDY+3c99WQXSeQuLYNDUeDDPGxAgMB +# AAGjRjBEMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNV +# HQ4EFgQUrmtlJTMGV5h8ksEMzPTPYk04g3IwDQYJKoZIhvcNAQELBQADggEBAAR3 +# sIiiVgSxUiPzGS/Ivwgjvqfsb6HXioE9VIJxQPwXc63LqC01TGJpeGayjr5zQ4p5 +# vt9q8WsiZvoUMofWzabz4BdprGWVDrO8hwksIixF8ojbfLuAra1cZ4qkDZtJH2Sn +# 0dUhvXabZqLuVghMiyqcSvs2hN8OiVI+tLzW8VQKzbFdj77c+lHxKBTkcKVpLiSI +# V2V8P4zRxyYE+CMlpTr58ErOGVxP1zITou7fwCAXdWEKWo5nlU22VNF6oGE9tghm +# S3M5PQT8lFCjZOPPKx+0oLDxwjluHENXZzH+61ugrszzRjK1rG3D3emrRYh/4BcG +# Wy7J1H41povt21JlzEExggHPMIIBywIBATAuMBoxGDAWBgNVBAMMD0NvZGVTaWdu +# aW5nQ2VydAIQN+zCRZRKiphJ5gGoRKvpeTAJBgUrDgMCGgUAoHgwGAYKKwYBBAGC +# NwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor +# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUbfriqhB/ +# EKzgoXnVu2UFtaTb040wDQYJKoZIhvcNAQEBBQAEggEAiQa/HUhDP1HyrPh7mC5H +# 6IwOdxL4p3EIkGeuUh3ZqWRNFLNz0ob24vqmKBtaKTfJqqrxTIBYeoBKB3Y8Wcx2 +# rEaH31WqQM2U7mFvM2cVv6dcrdWmLcMwi3LSEMxJf6VbWpbmWZK6zMRW2H76P5wQ +# cs6BUOwKZq/5eQcQLjJ3h+Mh5dsENZ7scB4U1yihD7Ggvrgxf54+J/TS8XuDsx2o +# g0czxIjMBwT5wGh8BqbC50izZ3D0WRFe7UNnhMk7zKG/bvIRBxah+JV25hdoGYaR +# 2tdmgr4EMPoB1ti8DOFmYAicckDWfX7/X4NzeM234LSMLtOxO2lVj5jhkmJJdjKh +# WA== +# SIG # End signature block \ No newline at end of file From bffff47d84aab49f5cfadbe6f5a5c85bf868b802 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 20 Jul 2022 16:04:03 -0400 Subject: [PATCH 173/276] Add help docs for New,Update,Test-PSScriptFileInfo cmdlets (#689) --- help/New-PSScriptFileInfo.md | 485 ++++++++++++++++++++++++++++++++ help/Test-PSScriptFileInfo.md | 179 ++++++++++++ help/Update-PSScriptFileInfo.md | 429 ++++++++++++++++++++++++++++ 3 files changed, 1093 insertions(+) create mode 100644 help/New-PSScriptFileInfo.md create mode 100644 help/Test-PSScriptFileInfo.md create mode 100644 help/Update-PSScriptFileInfo.md diff --git a/help/New-PSScriptFileInfo.md b/help/New-PSScriptFileInfo.md new file mode 100644 index 000000000..083893a2a --- /dev/null +++ b/help/New-PSScriptFileInfo.md @@ -0,0 +1,485 @@ +--- +external help file: PowerShellGet-help.xml +Module Name: PowerShellGet +online version: +schema: 2.0.0 +--- + +# New-PSScriptFileInfo + +## SYNOPSIS + +Creates a new .ps1 file containing metadata for the script, which is used when publishing a script package. + +## SYNTAX + +### __AllParameterSets + +``` +New-PSScriptFileInfo [-FilePath] -Description [-Author ] [-CompanyName ] [-Copyright ] [-ExternalModuleDependencies ] [-ExternalScriptDependencies ] [-Force] [-Guid ] [-IconUri ] [-LicenseUri ] [-PrivateData ] [-ProjectUri ] [-ReleaseNotes ] [-RequiredModules ] [-RequiredScripts ] [-Tags ] [-Version ] [] +``` + +## DESCRIPTION + +The New-PSScriptFileInfo cmdlet creates a .ps1 file containing metadata for the script. + +## EXAMPLES + +### Example 1: Creating a script with minimum required parameters + +``` +PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 1.0.0.0 + +.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 + +.AUTHOR johndoe + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> + +``` + +This example runs the cmdlet with the only required parameters, the 'FilePath' parameter sets the path the script is to be created and the 'Description' parameter contains the description for the script. The script is successfully created and if the contents of the file are viewed we can see the Description set as well as Author, Guid, and Version (with default values). + +### Example 2: Creating a script with RequiredModules, Author, Version and Description parameters + +``` +PS C:\> $requiredModules = @(@{ModuleName = "PackageManagement"; ModuleVersion = "1.0.0.0" }, @{ModuleName = "PSReadLine"}) +PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script2.ps1" -Description "this is a test script" -Version "2.0.0.0" -Author "janedoe" -RequiredModules $requiredModules +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 2.0.0.0 + +.GUID 7ec4832e-a4e1-562b-8a8c-241e535ad7d7 + +.AUTHOR janedoe + +.COMPANYNAME Jane Corporation + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +#Requires -Module PSReadLine +#Requires -Module @{ ModuleName = 'PackageManagement'; ModuleVersion = '1.0.0.0' } + +<# + +.DESCRIPTION +this is a test script + + +#> + +``` + +This example runs the cmdlet with the required 'FilePath' and 'Description' parameters, as well as 'Author', 'Version', and 'RequiredModules' parameters. The 'RequiredModules' parameter describes modules required by the script. It is necessary to provide the ModuleName key in the hashtable and if one wishes to specify verion they must also specify ModuleVersion, RequiredVersion, MaximumVersion, or MinimumVersion keys. The script is successfully created and if the contents of the file are viewed we can see the following values are set in the script file: Description, Author, Guid, and Version and RequiredModules. + + + +## PARAMETERS + +### -Author + +The author of the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -CompanyName + +The name of the company owning the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Copyright + +The copyright information for the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Description + +The description of the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ExternalModuleDependencies + +The list of external module dependencies taken by this script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ExternalScriptDependencies + +The list of external script dependencies taken by this script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -FilePath + +The path the .ps1 script info file will be created at. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True +Position: 0 +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Force + +If used and the .ps1 file specified at the path exists, it rewrites the file. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Guid + +The GUID for the script. + +```yaml +Type: Guid +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -IconUri + +The Uri for the icon associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -LicenseUri + +The Uri for the license associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -PrivateData + +The private data associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ProjectUri + +The Uri for the project associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ReleaseNotes + +The release notes for the script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -RequiredModules + +The list of modules required by the script. + +```yaml +Type: Hashtable[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -RequiredScripts + +The list of scripts required by the script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True (None) False (All) +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Tags + +The tags associated with the script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True (None) False (All) +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Version + +The version of the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True (None) False (All) +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### None + + + +## OUTPUTS + +### None + + + +## NOTES + + +## RELATED LINKS + +Fill Related Links Here + diff --git a/help/Test-PSScriptFileInfo.md b/help/Test-PSScriptFileInfo.md new file mode 100644 index 000000000..7335c7a42 --- /dev/null +++ b/help/Test-PSScriptFileInfo.md @@ -0,0 +1,179 @@ +--- +external help file: PowerShellGet-help.xml +Module Name: PowerShellGet +online version: +schema: 2.0.0 +--- + +# Test-PSScriptFileInfo + +## SYNOPSIS + +Tests a .ps1 file at the specified path to ensure it is valid. + +## SYNTAX + +### __AllParameterSets + +``` +Test-PSScriptFileInfo [-FilePath] [] +``` + +## DESCRIPTION + +The Test-PSScriptFileInfo cmdlet tests a .ps1 file at the specified path to ensure it is valid. + +## EXAMPLES + +### Example 1: Test a valid script + +``` +PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" +PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" +True +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 1.0.0.0 + +.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 + +.AUTHOR johndoe + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> + +``` + +Assume that the script file specified was created by the New-PSScriptFileInfo cmdlet prior to this example and is valid. This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is a valid script the cmdlet outputs "True". To see what this valid script looks like we can see the contents of the file. + +### Example 2: Test an invalid script (missing Author) + +``` +PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\invalid_test_script.ps1" +WARNING: The .ps1 script file passed in was not valid due to: PSScript file is missing the required Author property +False + +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 1.0.0.0 + +.GUID 7ec4832e-a4e1-562b-8a8c-241e535ad7d7 + +.AUTHOR + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> + +``` + +This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is not a valid script and is missing the required Author metadata property, the cmdlet writes an informative warning message and outputs "False". To see what this invalid script looks like we can see the contents of the file. + + +## PARAMETERS + +### -FilePath + +The path that the .ps1 script info file which is to be tested is located at. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True +Position: 0 +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### None + + + +## OUTPUTS + +### bool + + + +## NOTES + + +## RELATED LINKS + +Fill Related Links Here + diff --git a/help/Update-PSScriptFileInfo.md b/help/Update-PSScriptFileInfo.md new file mode 100644 index 000000000..740c0eaeb --- /dev/null +++ b/help/Update-PSScriptFileInfo.md @@ -0,0 +1,429 @@ +--- +external help file: PowerShellGet-help.xml +Module Name: PowerShellGet +online version: +schema: 2.0.0 +--- + +# Update-PSScriptFileInfo + +## SYNOPSIS + +Updates an existing .ps1 file with requested properties and ensures it's valid + +## SYNTAX + +### __AllParameterSets + +``` +Update-PSScriptFileInfo [-FilePath] [-Author ] [-CompanyName ] [-Copyright ] [-Description ] [-ExternalModuleDependencies ] [-ExternalScriptDependencies ] [-Guid ] [-IconUri ] [-LicenseUri ] [-PrivateData ] [-ProjectUri ] [-ReleaseNotes ] [-RemoveSignature] [-RequiredModules ] [-RequiredScripts ] [-Tags ] [-Version ] [] +``` + +## DESCRIPTION + +The Update-PSScriptFileInfo cmdlet updates an existing .ps1 file with requested properties and ensures it's valid. + +## EXAMPLES + +### Example 1: Update the version of a script + +``` +PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" +PS C:\> Update-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 2.0.0.0 + +.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 + +.AUTHOR johndoe + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> + +``` + +In this example a script is created by running the New-PSScriptFileInfo cmdlet with version specified as 1.0.0.0. To update the script's version to 2.0.0.0, the Update-PSScriptFileInfo cmdlet is run with 'Version' specified as "2.0.0.0". Given that the cmdlet completed running without errors and by looking at the contents of the updated file we see the version was updated to 2.0.0.0. + +## PARAMETERS + +### -Author + +The author of the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -CompanyName + +The name of the company owning the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Copyright + +The copyright information for the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Description + +The description of the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ExternalModuleDependencies + +The list of external module dependencies taken by this script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ExternalScriptDependencies + +The list of external script dependencies taken by this script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -FilePath + +The path the .ps1 script info file will be created at. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: True +Position: 0 +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Guid + +The GUID for the script. + +```yaml +Type: Guid +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -IconUri + +The Uri for the icon associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -LicenseUri + +The Uri for the license associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -PrivateData + +The private data associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ProjectUri + +The Uri for the project associated with the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -ReleaseNotes + +The release notes for the script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -RemoveSignature + +Remove signature from signed .ps1 (if present) thereby allowing update of script to happen. User should re-sign the updated script afterwards. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -RequiredModules + +The list of modules required by the script. + +```yaml +Type: Hashtable[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -RequiredScripts + +The list of scripts required by the script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Tags + +The tags associated with the script. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + +### -Version + +The version of the script. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: + +Required: False +Position: Named +Default value: +Accept pipeline input: False +Accept wildcard characters: False +DontShow: False +``` + + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### None + + + +## OUTPUTS + +### None + + + +## NOTES + + +## RELATED LINKS + +Fill Related Links Here + From c1dd5f30928c06e462ab5037cde74847731285b8 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:12:30 -0700 Subject: [PATCH 174/276] Update PowerShellGet.dll-Help.xml --- help/en-US/PowerShellGet.dll-Help.xml | 1045 +++++++++++++++++++++++++ 1 file changed, 1045 insertions(+) diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 6258499a0..6eb948e70 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -3422,6 +3422,1051 @@ PS C:\> Get-PSResourceRepository + + + Update-ModuleManifest + Update + ModuleManifest + + Updates a module manifest file. + + + + The Update-ModuleManifest cmdlet replaces the Update-ModuleManifest cmdlet from V2. It updates a module manifest based on the `-Path` parameter argument. It does not return an object. Other parameters allow specific properties of the manifest to be updated. + + + + Update-ModuleManifest + + Path + + Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + + String + + String + + + None + + + NestedModules + + Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + + Object[] + + Object[] + + + None + + + Guid + + Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + + System.Guid + + System.Guid + + + None + + + Author + + Specifies the module author. + + String + + String + + + None + + + CompanyName + + Specifies the company or vendor who created the module. + + String + + String + + + None + + + Copyright + + Specifies a copyright statement for the module. + + String + + String + + + None + + + RootModule + + Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. + If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). + To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + + System.String + + System.String + + + None + + + ModuleVersion + + Specifies the version of the module. + + System.Version + + System.Version + + + None + + + Description + + Specifies a description of the module. + + System.String + + System.String + + + None + + + ProcessorArchitecture + + Specifies the processor architecture that the module requires. + The acceptable values for this parameter are: + * Amd64 + * Arm + * IA64 + * MSIL + * None (unknown or unspecified) + * X86 + + System.Reflection.ProcessorArchitecture + + System.Reflection.ProcessorArchitecture + + + None + + + CompatiblePSEditions + + Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + + + Desktop + Core + + System.String[] + + System.String[] + + + None + + + PowerShellVersion + + Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + + System.Version + + System.Version + + + None + + + ClrVersion + + Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + DotNetFrameworkVersion + + Specifies the minimum version of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + PowerShellHostName + + Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + To find the name of a host program, in the program, type $Host.Name. + + System.String + + System.String + + + None + + + PowerShellHostVersion + + Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + + System.Version + + System.Version + + + None + + + RequiredModules + + Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + + System.Object[] + + System.Object[] + + + None + + + TypesToProcess + + Specifies the type files (.ps1xml) that run when the module is imported. + When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + FormatsToProcess + + Specifies the formatting files (.ps1xml) that run when the module is imported. + When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + ScriptsToProcess + + Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + To specify scripts that run in the module's session state, use the NestedModules key. + + System.String[] + + System.String[] + + + None + + + RequiredAssemblies + + Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. + Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + + System.String[] + + System.String[] + + + None + + + FileList + + Specifies all items that are included in the module. + + System.String[] + + System.String[] + + + None + + + ModuleList + + Specifies an array of modules that are included in the module. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. + + System.String[] + + System.String[] + + + None + + + FunctionsToExport + + Specifies the functions that the module exports. Wildcards are permitted. + Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + + System.String[] + + System.String[] + + + None + + + AliasesToExport + + Specifies the aliases that the module exports. Wildcards are permitted. + Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + + System.String[] + + System.String[] + + + None + + + VariablesToExport + + Specifies the variables that the module exports. Wildcards are permitted. + Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + + System.String[] + + System.String[] + + + None + + + CmdletsToExport + + Specifies the cmdlets that the module exports. Wildcards are permitted. + Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + + System.String[] + + System.String[] + + + None + + + DscResourcesToExport + + Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + + System.String[] + + System.String[] + + + None + + + PrivateData + + Specifies data that is passed to the module when it's imported. + + Hashtable + + Hashtable + + + None + + + Tags + + Specifies an array of tags. + + System.String[] + + System.String[] + + + None + + + ProjectUri + + Specifies the URL of a web page about this project. + + Uri + + Uri + + + None + + + LicenseUri + + Specifies the URL of licensing terms for the module. + + Uri + + Uri + + + None + + + IconUri + + Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + + Uri + + Uri + + + None + + + ReleaseNotes + + Specifies a string array that contains release notes or comments that you want available for this version of the script. + + System.String[] + + System.String[] + + + None + + + Prerelease + + Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + + System.String + + System.String + + + None + + + HelpInfoUri + + Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. + The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. + For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + + Uri + + Uri + + + None + + + DefaultCommandPrefix + + Specifies the default command prefix. + + System.String + + System.String + + + None + + + ExternalModuleDependencies + + Specifies an array of external module dependencies. + + System.String[] + + System.String[] + + + None + + + RequireLicenseAcceptance + + Specifies that a license acceptance is required for the module. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + Path + + Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + + String + + String + + + None + + + NestedModules + + Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + + Object[] + + Object[] + + + None + + + Guid + + Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + + System.Guid + + System.Guid + + + None + + + Author + + Specifies the module author. + + String + + String + + + None + + + CompanyName + + Specifies the company or vendor who created the module. + + String + + String + + + None + + + Copyright + + Specifies a copyright statement for the module. + + String + + String + + + None + + + RootModule + + Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. + If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). + To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + + System.String + + System.String + + + None + + + ModuleVersion + + Specifies the version of the module. + + System.Version + + System.Version + + + None + + + Description + + Specifies a description of the module. + + System.String + + System.String + + + None + + + ProcessorArchitecture + + Specifies the processor architecture that the module requires. + The acceptable values for this parameter are: + * Amd64 + * Arm + * IA64 + * MSIL + * None (unknown or unspecified) + * X86 + + System.Reflection.ProcessorArchitecture + + System.Reflection.ProcessorArchitecture + + + None + + + CompatiblePSEditions + + Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + + System.String[] + + System.String[] + + + None + + + PowerShellVersion + + Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + + System.Version + + System.Version + + + None + + + ClrVersion + + Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + DotNetFrameworkVersion + + Specifies the minimum version of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + PowerShellHostName + + Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + To find the name of a host program, in the program, type $Host.Name. + + System.String + + System.String + + + None + + + PowerShellHostVersion + + Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + + System.Version + + System.Version + + + None + + + RequiredModules + + Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + + System.Object[] + + System.Object[] + + + None + + + TypesToProcess + + Specifies the type files (.ps1xml) that run when the module is imported. + When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + FormatsToProcess + + Specifies the formatting files (.ps1xml) that run when the module is imported. + When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + ScriptsToProcess + + Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + To specify scripts that run in the module's session state, use the NestedModules key. + + System.String[] + + System.String[] + + + None + + + RequiredAssemblies + + Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. + Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + + System.String[] + + System.String[] + + + None + + + FileList + + Specifies all items that are included in the module. + + System.String[] + + System.String[] + + + None + + + ModuleList + + Specifies an array of modules that are included in the module. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. + + System.String[] + + System.String[] + + + None + + + FunctionsToExport + + Specifies the functions that the module exports. Wildcards are permitted. + Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + + System.String[] + + System.String[] + + + None + + + AliasesToExport + + Specifies the aliases that the module exports. Wildcards are permitted. + Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + + System.String[] + + System.String[] + + + None + + + VariablesToExport + + Specifies the variables that the module exports. Wildcards are permitted. + Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + + System.String[] + + System.String[] + + + None + + + CmdletsToExport + + Specifies the cmdlets that the module exports. Wildcards are permitted. + Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + + System.String[] + + System.String[] + + + None + + + DscResourcesToExport + + Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + + System.String[] + + System.String[] + + + None + + + PrivateData + + Specifies data that is passed to the module when it's imported. + + Hashtable + + Hashtable + + + None + + + Tags + + Specifies an array of tags. + + System.String[] + + System.String[] + + + None + + + ProjectUri + + Specifies the URL of a web page about this project. + + Uri + + Uri + + + None + + + LicenseUri + + Specifies the URL of licensing terms for the module. + + Uri + + Uri + + + None + + + IconUri + + Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + + Uri + + Uri + + + None + + + ReleaseNotes + + Specifies a string array that contains release notes or comments that you want available for this version of the script. + + System.String[] + + System.String[] + + + None + + + Prerelease + + Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + + System.String + + System.String + + + None + + + HelpInfoUri + + Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. + The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. + For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + + Uri + + Uri + + + None + + + DefaultCommandPrefix + + Specifies the default command prefix. + + System.String + + System.String + + + None + + + ExternalModuleDependencies + + Specifies an array of external module dependencies. + + System.String[] + + System.String[] + + + None + + + RequireLicenseAcceptance + + Specifies that a license acceptance is required for the module. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + System.String[] + + + + + + + + + + ## RELATED LINKS + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" + + In this example the author property in the module manifest will be updated to "New Author". + + + + -------------------------- Example 2 -------------------------- + PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" + + In this example the prerelease property will be updated to "beta2" + + + + -------------------------- Example 3 -------------------------- + PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." + + In this example the tags and description will be updated to the passed in values. + + + + + Update-PSResource From 74c8f0260054a018c769df3436b8c966bc445a64 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:13:50 -0700 Subject: [PATCH 175/276] Update PowerShellGet.dll-Help.xml --- help/en-US/PowerShellGet.dll-Help.xml | 5139 ++++--------------------- 1 file changed, 765 insertions(+), 4374 deletions(-) diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 6eb948e70..a26f1a072 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -2,295 +2,458 @@ - Find-PSResource - Find - PSResource + New-PSScriptFileInfo + New + PSScriptFileInfo - Searches for packages from a repository (local or remote), based on `-Name` and other package properties. + Creates a new .ps1 file containing metadata for the script, which is used when publishing a script package. - The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. + The New-PSScriptFileInfo cmdlet creates a .ps1 file containing metadata for the script. - Find-PSResource - - Name + New-PSScriptFileInfo + + FilePath - Name of a resource or resources to find. Accepts wild card character '*'. + The path the .ps1 script info file will be created at. - System.String[] + String - System.String[] + String None - Credential + Author - Optional credentials to be used when accessing a repository. + The author of the script. - System.Management.Automation.PSCredential + System.String - System.Management.Automation.PSCredential + System.String None - IncludeDependencies + CompanyName - When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + The name of the company owning the script. + String - System.Management.Automation.SwitchParameter + String - False + None - ModuleName + Copyright - Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + The copyright information for the script. - System.String + String - System.String + String + + + None + + + Description + + The description of the script. + + String + + String + + + None + + + ExternalModuleDependencies + + The list of external module dependencies taken by this script. + + String[] + + String[] + + + None + + + ExternalScriptDependencies + + The list of external script dependencies taken by this script. + + String[] + + String[] None - Prerelease + Force - When specified, includes prerelease versions in search results returned. + If used and the .ps1 file specified at the path exists, it rewrites the file. - System.Management.Automation.SwitchParameter + SwitchParameter False - - Repository + + Guid - 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. + The GUID for the script. - System.String[] + Guid - System.String[] + Guid None - Tag + IconUri - Filters search results for resources that include one or more of the specified tags. + The Uri for the icon associated with the script. - System.String[] + String - System.String[] + String None - Type + LicenseUri - Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + The Uri for the license associated with the script. - - Module - Script - DscResource - Command - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + String - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + String None - - Version + + PrivateData - Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + The private data associated with the script. - System.String + String - System.String + String None - - Confirm + + ProjectUri - Prompts you for confirmation before running the cmdlet. + The Uri for the project associated with the script. + String - System.Management.Automation.SwitchParameter + String - False + None - - WhatIf + + ReleaseNotes - Shows what would happen if the cmdlet runs. The cmdlet is not run. + The release notes for the script. + String[] - System.Management.Automation.SwitchParameter + String[] - False + None + + + RequiredModules + + The list of modules required by the script. + + Hashtable[] + + Hashtable[] + + + None + + + RequiredScripts + + The list of scripts required by the script. + + String[] + + String[] + + + None + + + Tags + + The tags associated with the script. + + String[] + + String[] + + + None + + + Version + + The version of the script. + + String + + String + + + None - Credential + Author - Optional credentials to be used when accessing a repository. + The author of the script. - System.Management.Automation.PSCredential + System.String - System.Management.Automation.PSCredential + System.String None - IncludeDependencies + CompanyName - When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + The name of the company owning the script. - System.Management.Automation.SwitchParameter + String - System.Management.Automation.SwitchParameter + String - False + None - ModuleName + Copyright - Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + The copyright information for the script. - System.String + String - System.String + String + + + None + + + Description + + The description of the script. + + String + + String + + + None + + + ExternalModuleDependencies + + The list of external module dependencies taken by this script. + + String[] + + String[] + + + None + + + ExternalScriptDependencies + + The list of external script dependencies taken by this script. + + String[] + + String[] None - - Name + + FilePath - Name of a resource or resources to find. Accepts wild card character '*'. + The path the .ps1 script info file will be created at. - System.String[] + String - System.String[] + String None - Prerelease + Force - When specified, includes prerelease versions in search results returned. + If used and the .ps1 file specified at the path exists, it rewrites the file. - System.Management.Automation.SwitchParameter + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - - Repository + + Guid - 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. + The GUID for the script. - System.String[] + Guid - System.String[] + Guid None - Tag + IconUri - Filters search results for resources that include one or more of the specified tags. + The Uri for the icon associated with the script. - System.String[] + String - System.String[] + String None - Type + LicenseUri - Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + The Uri for the license associated with the script. - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + String - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + String None - - Version + + PrivateData - Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + The private data associated with the script. - System.String + String - System.String + String None - - Confirm + + ProjectUri - Prompts you for confirmation before running the cmdlet. + The Uri for the project associated with the script. - System.Management.Automation.SwitchParameter + String - System.Management.Automation.SwitchParameter + String - False + None - - WhatIf + + ReleaseNotes - Shows what would happen if the cmdlet runs. The cmdlet is not run. + The release notes for the script. - System.Management.Automation.SwitchParameter + String[] - System.Management.Automation.SwitchParameter + String[] - False + None + + + RequiredModules + + The list of modules required by the script. + + Hashtable[] + + Hashtable[] + + + None + + + RequiredScripts + + The list of scripts required by the script. + + String[] + + String[] + + + None + + + Tags + + The tags associated with the script. + + String[] + + String[] + + + None + + + Version + + The version of the script. + + String + + String + + + None - System.String[] + None @@ -300,7 +463,7 @@ - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + None @@ -314,273 +477,105 @@ - -------------------------- Example 1 -------------------------- - PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... - - This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". - - - - -------------------------- Example 2 -------------------------- - PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... - - This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". - - - - -------------------------- Example 3 -------------------------- - PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... - Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... - - This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". - - - - -------------------------- Example 4 -------------------------- - PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery - Get-TargetResource 1.0.0.4 WindowsDefender PSGallery - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery - Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery - Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery - Get-TargetResource 1.2.0.0 cRegFile PSGallery - Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery - Get-TargetResource 1.0.0.0 cVNIC PSGallery - Get-TargetResource 1.1.17.0 supVsts PSGallery - - This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. - - - - -------------------------- Example 5 -------------------------- - PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery - - This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. - - - - -------------------------- Example 6 -------------------------- - PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery - - This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. - - - - -------------------------- Example 7 -------------------------- - PS C:\> Find-PSResource -Name * - - This will search all PSResources from registered PSResourceRepositories. - - - - - - <add> - - - - - - - Get-PSResource - Get - PSResource - - Returns resources (modules and scripts) installed on the machine via PowerShellGet. - - - - The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. - - - - Get-PSResource - - Name - - Name of a resource or resources to find. Accepts wild card characters or a null value. - - System.String[] - - System.String[] - - - None - - - Path - - Specifies the path to search in. - - System.String - - System.String - - - None - - - Version - - Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - - - Scope - - Specifies the scope of the resource. - - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - - - - Name - - Name of a resource or resources to find. Accepts wild card characters or a null value. - - System.String[] - - System.String[] - - - None - - - Path - - Specifies the path to search in. - - System.String - - System.String - - - None - - - Version - - Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - - - Scope - - Specifies the scope of the resource. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResource Az - - This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResource Az -version "1.0.0" - - This will return version 1.0.0 of the Az module. - - - - -------------------------- Example 3 -------------------------- - PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" - - This will return all versions of the Az module within the specified range. - - - - -------------------------- Example 4 -------------------------- - PS C:\> Get-PSResource Az -version "4.0.1-preview" - - Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. - - - - -------------------------- Example 5 -------------------------- - PS C:\> Get-PSResource Az -version "4.0.1" - - Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. - - - - -------------------------- Example 6 -------------------------- - PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] - - Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. - - - - -------------------------- Example 6 -------------------------- - PS C:\> Get-PSResource Az -Path . + Example 1: Creating a script with minimum required parameters + PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 1.0.0.0 + +.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 + +.AUTHOR johndoe + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> - This will return all versions of the Az module that have been installed in the current directory. + This example runs the cmdlet with the only required parameters, the 'FilePath' parameter sets the path the script is to be created and the 'Description' parameter contains the description for the script. The script is successfully created and if the contents of the file are viewed we can see the Description set as well as Author, Guid, and Version (with default values). - -------------------------- Example 7 -------------------------- - PS C:\> Get-PSResource + Example 2: Creating a script with RequiredModules, Author, Version and Description parameters + PS C:\> $requiredModules = @(@{ModuleName = "PackageManagement"; ModuleVersion = "1.0.0.0" }, @{ModuleName = "PSReadLine"}) +PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script2.ps1" -Description "this is a test script" -Version "2.0.0.0" -Author "janedoe" -RequiredModules $requiredModules +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 2.0.0.0 + +.GUID 7ec4832e-a4e1-562b-8a8c-241e535ad7d7 + +.AUTHOR janedoe + +.COMPANYNAME Jane Corporation + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +#Requires -Module PSReadLine +#Requires -Module @{ ModuleName = 'PackageManagement'; ModuleVersion = '1.0.0.0' } + +<# + +.DESCRIPTION +this is a test script + + +#> - This will return all versions and scripts installed on the machine. + This example runs the cmdlet with the required 'FilePath' and 'Description' parameters, as well as 'Author', 'Version', and 'RequiredModules' parameters. The 'RequiredModules' parameter describes modules required by the script. It is necessary to provide the ModuleName key in the hashtable and if one wishes to specify verion they must also specify ModuleVersion, RequiredVersion, MaximumVersion, or MinimumVersion keys. The script is successfully created and if the contents of the file are viewed we can see the following values are set in the script file: Description, Author, Guid, and Version and RequiredModules. @@ -588,27 +583,27 @@ - Get-PSResourceRepository - Get - PSResourceRepository + Test-PSScriptFileInfo + Test + PSScriptFileInfo - Finds and returns registered repository information. + Tests a .ps1 file at the specified path to ensure it is valid. - The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. + The Test-PSScriptFileInfo cmdlet tests a .ps1 file at the specified path to ensure it is valid. - Get-PSResourceRepository - - Name + Test-PSScriptFileInfo + + FilePath - This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + The path that the .ps1 script info file which is to be tested is located at. - String[] + String - String[] + String None @@ -616,14 +611,14 @@ - - Name + + FilePath - This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + The path that the .ps1 script info file which is to be tested is located at. - String[] + String - String[] + String None @@ -632,3836 +627,121 @@ - System.String[] + None - - - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo - - - - - - + - If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. + - -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - - This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResourceRepository -Name "*Gallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - - This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. - - - - -------------------------- Example 3 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - - This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. - - - - -------------------------- Example 4 -------------------------- - PS C:\> Get-PSResourceRepository -Name "*" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir True 50 - - This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. - - - - - - - - Install-PSResource - Install - PSResource - - Installs resources (modules and scripts) from a registered repository onto the machine. - - - - The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. - - - - Install-PSResource - - Name - - Name of a resource or resources to install. Does not accept wildcard characters or a null value. - - System.String[] - - System.String[] - - - None - - - Version - - Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - - - Prerelease - - When specified, includes prerelease versions in search results returned. - - - System.Management.Automation.SwitchParameter - - - False - - - Repository - - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. - - System.String[] - - System.String[] - - - None - - - Credential - - Optional credentials to be used when accessing a repository. - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - Scope - - Specifies the scope under which a user has access. - - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - TrustRepository - - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. - - - System.Management.Automation.SwitchParameter - - - False - - - Reinstall - - Writes over any previously installed resource version that already exists on the machine. - - - System.Management.Automation.SwitchParameter - - - False - - - Quiet - - Supresses installation progress bar. - - - System.Management.Automation.SwitchParameter - - - False - - - AcceptLicense - - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. - - - System.Management.Automation.SwitchParameter - - - False - - - NoClobber - - Prevents installing a package that contains cmdlets that already exist on the machine. - - - System.Management.Automation.SwitchParameter - - - False - - - SkipDependencyCheck - - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. - - - System.Management.Automation.SwitchParameter - - - False - - - AuthenticodeCheck - - Does a check to to validate signed files and catalog files on Windows. - - - System.Management.Automation.SwitchParameter - - - False - - - PassThru - - Passes the resource installed to the console. - - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - Install-PSResource - - RequiredResource - - A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. - The hashtable will take a format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - A json string will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } - - RequiredResource - - RequiredResource - - - None - - - Credential - - Optional credentials to be used when accessing a repository. - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - Scope - - Specifies the scope under which a user has access. - - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - TrustRepository - - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. - - - System.Management.Automation.SwitchParameter - - - False - - - Reinstall - - Writes over any previously installed resource version that already exists on the machine. - - - System.Management.Automation.SwitchParameter - - - False - - - Quiet - - Supresses installation progress bar. - - - System.Management.Automation.SwitchParameter - - - False - - - AcceptLicense - - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. - - - System.Management.Automation.SwitchParameter - - - False - - - NoClobber - - Prevents installing a package that contains cmdlets that already exist on the machine. - - - System.Management.Automation.SwitchParameter - - - False - - - SkipDependencyCheck - - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. - - - System.Management.Automation.SwitchParameter - - - False - - - AuthenticodeCheck - - Does a check to to validate signed files and catalog files on Windows. - - - System.Management.Automation.SwitchParameter - - - False - - - PassThru - - Passes the resource installed to the console. - - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - Install-PSResource - - RequiredResourceFile - - Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. - The psd1 will take a hashtable format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - json files will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } - - System.String[] - - System.String[] - - - None - - - Credential - - Optional credentials to be used when accessing a repository. - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - Scope - - Specifies the scope under which a user has access. - - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - TrustRepository - - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. - - - System.Management.Automation.SwitchParameter - - - False - - - Reinstall - - Writes over any previously installed resource version that already exists on the machine. - - - System.Management.Automation.SwitchParameter - - - False - - - Quiet - - Supresses installation progress bar. - - - System.Management.Automation.SwitchParameter - - - False - - - AcceptLicense - - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. - - - System.Management.Automation.SwitchParameter - - - False - - - NoClobber - - Prevents installing a package that contains cmdlets that already exist on the machine. - - - System.Management.Automation.SwitchParameter - - - False - - - SkipDependencyCheck - - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. - - - System.Management.Automation.SwitchParameter - - - False - - - AuthenticodeCheck - - Does a check to to validate signed files and catalog files on Windows. - - - System.Management.Automation.SwitchParameter - - - False - - - PassThru - - Passes the resource installed to the console. - - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - - - Name - - Name of a resource or resources to install. Does not accept wildcard characters or a null value. - - System.String[] - - System.String[] - - - None - - - Version - - Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - - - Prerelease - - When specified, includes prerelease versions in search results returned. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Repository - - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. - - System.String[] - - System.String[] - - - None - - - RequiredResource - - A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. - The hashtable will take a format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - A json string will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } - - RequiredResource - - RequiredResource - - - None - - - RequiredResourceFile - - Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. - The psd1 will take a hashtable format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - json files will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } - - System.String[] - - System.String[] - - - None - - - Credential - - Optional credentials to be used when accessing a repository. - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - Scope - - Specifies the scope under which a user has access. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - TrustRepository - - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Reinstall - - Writes over any previously installed resource version that already exists on the machine. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Quiet - - Supresses installation progress bar. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - AcceptLicense - - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - NoClobber - - Prevents installing a package that contains cmdlets that already exist on the machine. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - SkipDependencyCheck - - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - AuthenticodeCheck - - Does a check to to validate signed files and catalog files on Windows. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - PassThru - - Passes the resource installed to the console. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Install-PSResource Az - - Installs the Az module. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" - - Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. - - - - -------------------------- Example 3 -------------------------- - PS C:\> Install-PSResource Az -Repository PSGallery - - Installs the latest stable Az module from the PowerShellGallery. - - - - -------------------------- Example 3 -------------------------- - PS C:\> Install-PSResource Az -Reinstall - - Installs the Az module and will write over any previously installed version if it is already installed. - - - - -------------------------- Example 4 -------------------------- - PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 - - Installs the PSResources specified in the psd1 file. - - - - - - Online Version: - - - - - - - Publish-PSResource - Publish - PSResource - - Publishes a specified module from the local computer to PSResource repository. - - - - The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. - - - - Publish-PSResource - - Path - - When specified, includes prerelease versions in search. - - System.String - - System.String - - - None - - - APIKey - - Specifies the API key that you want to use to publish a resource to the online gallery. - - System.String - - System.String - - - None - - - Repository - - Specifies the repository to publish to. - - System.String - - System.String - - - None - - - DestinationPath - - Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. - - System.String - - System.String - - - None - - - Credential - - Specifies a user account that has rights to a specific repository (used for finding dependencies). - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - SkipDependenciesCheck - - Bypasses the default check that all dependencies are present on the repository which the resource is being published to. - - - System.Management.Automation.SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - - - APIKey - - Specifies the API key that you want to use to publish a resource to the online gallery. - - System.String - - System.String - - - None - - - Repository - - Specifies the repository to publish to. - - System.String - - System.String - - - None - - - Path - - When specified, includes prerelease versions in search. - - System.String - - System.String - - - None - - - DestinationPath - - Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. - - System.String - - System.String - - - None - - - Credential - - Specifies a user account that has rights to a specific repository (used for finding dependencies). - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - SkipDependenciesCheck - - Bypasses the default check that all dependencies are present on the repository which the resource is being published to. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Publish-PSResource -Path c:\Test-Module - - This will publish the module 'Test-Module' to the highest priority repository - - - - -------------------------- Example 2 -------------------------- - PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' - - This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. - - - - - - Online Version: - - - - - - - Register-PSResourceRepository - Register - PSResourceRepository - - Registers a repository for PowerShell resources. - - - - The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. - - - - Register-PSResourceRepository - - Name - - Name of the repository to be registered. Cannot be "PSGallery". - - String - - String - - - None - - - Uri - - Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. - - String - - String - - - None - - - Priority - - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. - - Int32 - - Int32 - - - 50 - - - Trusted - - Specifies whether the repository should be trusted. - - - SwitchParameter - - - False - - - CredentialInfo - - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` - - PSCredentialInfo - - PSCredentialInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - SwitchParameter - - - False - - - PassThru - - When specified, displays the succcessfully registered repository and its information. - - - SwitchParameter - - - False - - - - Register-PSResourceRepository - - Priority - - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. - - Int32 - - Int32 - - - 50 - - - PSGallery - - When specified, registers PSGallery repository. - - - SwitchParameter - - - False - - - Trusted - - Specifies whether the repository should be trusted. - - - SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - SwitchParameter - - - False - - - PassThru - - When specified, displays the succcessfully registered repository and its information. - - - SwitchParameter - - - False - - - - Register-PSResourceRepository - - Repository - - Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. - - Hashtable[] - - Hashtable[] - - - None - - - Trusted - - Specifies whether the repository should be trusted. - - - SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - SwitchParameter - - - False - - - PassThru - - When specified, displays the succcessfully registered repository and its information. - - - SwitchParameter - - - False - - - - - - Name - - Name of the repository to be registered. Cannot be "PSGallery". - - String - - String - - - None - - - Priority - - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. - - Int32 - - Int32 - - - 50 - - - PSGallery - - When specified, registers PSGallery repository. - - SwitchParameter - - SwitchParameter - - - False - - - Repository - - Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. - - Hashtable[] - - Hashtable[] - - - None - - - Trusted - - Specifies whether the repository should be trusted. - - SwitchParameter - - SwitchParameter - - - False - - - Uri - - Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. - - String - - String - - - None - - - CredentialInfo - - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` - - PSCredentialInfo - - PSCredentialInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - SwitchParameter - - SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - SwitchParameter - - SwitchParameter - - - False - - - PassThru - - When specified, displays the succcessfully registered repository and its information. - - SwitchParameter - - SwitchParameter - - - False - - - - - - System.String - - - - - - - - - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) - - - - - - - - - Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. - Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). - Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 - - This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Register-PSResourceRepository -PSGallery -PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - - This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. - - - - -------------------------- Example 3 -------------------------- - PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} -PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir False 50 - - This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. - - - - - - - - Save-PSResource - Save - PSResource - - Saves resources (modules and scripts) from a registered repository onto the machine. - - - - The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. - - - - Save-PSResource - - Name - - Name of a resource or resources to save. Does not accept wildcard characters or a null value. - - System.String[] - - System.String[] - - - None - - - Version - - Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - - - Prerelease - - Specifies to include prerelease versions. - - - System.Management.Automation.SwitchParameter - - - False - - - Repository - - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. - - System.String[] - - System.String[] - - - None - - - Credential - - Optional credentials to be used when accessing a repository. - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - AsNupkg - - Saves the resource as a zipped .nupkg file. - - - System.Management.Automation.SwitchParameter - - - False - - - IncludeXML - - Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). - - - System.Management.Automation.SwitchParameter - - - False - - - Path - - Specifies the path to save the resource to. - - System.String - - System.String - - - None - - - TrustRepository - - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. - - - System.Management.Automation.SwitchParameter - - - False - - - AuthenticodeCheck - - Does a check to to validate signed files and catalog files on Windows. - - - System.Management.Automation.SwitchParameter - - - False - - - PassThru - - Passes the resource saved to the console. - - - System.Management.Automation.SwitchParameter - - - False - - - SkipDependencyCheck - - Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. - - - System.Management.Automation.SwitchParameter - - - False - - - Quiet - - Supresses progress information. - - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - - - Name - - Name of a resource or resources to save. Does not accept wildcard characters or a null value. - - System.String[] - - System.String[] - - - None - - - Version - - Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - - - Prerelease - - Specifies to include prerelease versions. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Repository - - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. - - System.String[] - - System.String[] - - - None - - - Credential - - Optional credentials to be used when accessing a repository. - - System.Management.Automation.PSCredential - - System.Management.Automation.PSCredential - - - None - - - AsNupkg - - Saves the resource as a zipped .nupkg file. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - IncludeXML - - Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Path - - Specifies the path to save the resource to. - - System.String - - System.String - - - None - - - TrustRepository - - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - AuthenticodeCheck - - Does a check to to validate signed files and catalog files on Windows. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - PassThru - - Passes the resource saved to the console. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - SkipDependencyCheck - - Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Quiet - - Supresses progress information. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Save-PSResource -Name Az - - Saves the Az module - - - - -------------------------- Example 2 -------------------------- - PS C:\> Save-PSResource -Name Az -Repository PSGallery - - Saves the Az module found in the PowerShellGallery - - - - -------------------------- Example 3 -------------------------- - PS C:\> Save-PSResource Az -AsNupkg - - Saves the Az module as a .nupkg file - - - - -------------------------- Example 4 -------------------------- - PS C:\> Save-PSResource Az -IncludeXML - - Saves the Az module and includes the PowerShellGet XML metadata - - - - - - Online Version: - - - - - - - Set-PSResourceRepository - Set - PSResourceRepository - - Sets information for a registered repository. - - - - The Set-PSResourceRepository cmdlet sets information for a registered repository. - - - - Set-PSResourceRepository - - Name - - Specifies the name of the repository to be set. - - System.String - - System.String - - - None - - - Priority - - Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). - - System.Int32 - - System.Int32 - - - None - - - Trusted - - Specifies whether the repository should be trusted. - - - System.Management.Automation.SwitchParameter - - - False - - - Uri - - Specifies the location of the repository to be set. - - String - - String - - - None - - - CredentialInfo - - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` - - PSCredentialInfo - - PSCredentialInfo - - - None - - - PassThru - - When specified, displays the succcessfully registered repository and its information - - - System.Management.Automation.SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - - - Name - - Specifies the name of the repository to be set. - - System.String - - System.String - - - None - - - Priority - - Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). - - System.Int32 - - System.Int32 - - - None - - - Trusted - - Specifies whether the repository should be trusted. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Uri - - Specifies the location of the repository to be set. - - String - - String - - - None - - - CredentialInfo - - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` - - PSCredentialInfo - - PSCredentialInfo - - - None - - - PassThru - - When specified, displays the succcessfully registered repository and its information - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - - - - System.String - - - - - - - - System.Collections.Hashtable[] - - - - - - - - - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) - - - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery file:///c:/code/testdir False 50 - - This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 True 25 - - This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. - - - - -------------------------- Example 3 -------------------------- - PS C:\> Get-PSResourceRepository -Name "*" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 - -PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} - -PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 True 50 - PoshTestGallery file:///c:/code/testdir False 50 - - This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. - - - - - - - - Uninstall-PSResource - Uninstall - PSResource - - Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. - - - - The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. - - - - Uninstall-PSResource - - Name - - Name of a resource or resources that has been installed. Accepts wild card characters. - - System.String[] - - System.String[] - - - None - - - Version - - Specifies the version of the resource to be uninstalled. - - System.String - - System.String - - - None - - - Scope - - Specifies the scope of the resource to uninstall. - - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - SkipDependencyCheck - - Skips check to see if other resources are dependent on the resource being uninstalled. - - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - System.Management.Automation.SwitchParameter - - - False - - - - - - Name - - Name of a resource or resources that has been installed. Accepts wild card characters. - - System.String[] - - System.String[] - - - None - - - Version - - Specifies the version of the resource to be uninstalled. - - System.String - - System.String - - - None - - - Scope - - Specifies the scope of the resource to uninstall. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - - - None - - - SkipDependencyCheck - - Skips check to see if other resources are dependent on the resource being uninstalled. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Uninstall-PSResource Az - - Uninstalls the latest version of the Az module. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "1.0.0" - - Uninstalls version 1.0.0 of the Az module. - - - - -------------------------- Example 3 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" - - Uninstalls all versions within the specified version range. - - - - -------------------------- Example 4 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" - - Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. - - - - -------------------------- Example 4 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease - - Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. - - - - - - - - Unregister-PSResourceRepository - Unregister - PSResourceRepository - - Un-registers a repository from the repository store. - - - - The Unregister-PSResourceRepository cmdlet unregisters a repository. - - - - Unregister-PSResourceRepository - - Name - - This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. - - String[] - - String[] - - - None - - - PassThru - - Passes the resource installed to the console. - - - SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - - SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - - SwitchParameter - - - False - - - - - - Name - - This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. - - String[] - - String[] - - - None - - - PassThru - - Passes the resource installed to the console. - - SwitchParameter - - SwitchParameter - - - False - - - Confirm - - Prompts you for confirmation before running the cmdlet. - - SwitchParameter - - SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - SwitchParameter - - SwitchParameter - - - False - - - - - - System.String[] - - - - - - - - - - - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" -PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" -PS C:\> - - In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. - - - - -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir True 50 - -PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - - In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. - - - - - - - - Update-ModuleManifest - Update - ModuleManifest - - Updates a module manifest file. - - - - The Update-ModuleManifest cmdlet replaces the Update-ModuleManifest cmdlet from V2. It updates a module manifest based on the `-Path` parameter argument. It does not return an object. Other parameters allow specific properties of the manifest to be updated. - - - - Update-ModuleManifest - - Path - - Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. - - String - - String - - - None - - - NestedModules - - Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. - - Object[] - - Object[] - - - None - - - Guid - - Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. - - System.Guid - - System.Guid - - - None - - - Author - - Specifies the module author. - - String - - String - - - None - - - CompanyName - - Specifies the company or vendor who created the module. - - String - - String - - - None - - - Copyright - - Specifies a copyright statement for the module. - - String - - String - - - None - - - RootModule - - Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. - If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). - To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. - - System.String - - System.String - - - None - - - ModuleVersion - - Specifies the version of the module. - - System.Version - - System.Version - - - None - - - Description - - Specifies a description of the module. - - System.String - - System.String - - - None - - - ProcessorArchitecture - - Specifies the processor architecture that the module requires. - The acceptable values for this parameter are: - * Amd64 - * Arm - * IA64 - * MSIL - * None (unknown or unspecified) - * X86 - - System.Reflection.ProcessorArchitecture - - System.Reflection.ProcessorArchitecture - - - None - - - CompatiblePSEditions - - Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support - - - Desktop - Core - - System.String[] - - System.String[] - - - None - - - PowerShellVersion - - Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. - - System.Version - - System.Version - - - None - - - ClrVersion - - Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. - - System.Version - - System.Version - - - None - - - DotNetFrameworkVersion - - Specifies the minimum version of the Microsoft .NET Framework that the module requires. - - System.Version - - System.Version - - - None - - - PowerShellHostName - - Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. - To find the name of a host program, in the program, type $Host.Name. - - System.String - - System.String - - - None - - - PowerShellHostVersion - - Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. - - System.Version - - System.Version - - - None - - - RequiredModules - - Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. - - System.Object[] - - System.Object[] - - - None - - - TypesToProcess - - Specifies the type files (.ps1xml) that run when the module is imported. - When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. - - System.String[] - - System.String[] - - - None - - - FormatsToProcess - - Specifies the formatting files (.ps1xml) that run when the module is imported. - When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. - - System.String[] - - System.String[] - - - None - - - ScriptsToProcess - - Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. - To specify scripts that run in the module's session state, use the NestedModules key. - - System.String[] - - System.String[] - - - None - - - RequiredAssemblies - - Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. - Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. - - System.String[] - - System.String[] - - - None - - - FileList - - Specifies all items that are included in the module. - - System.String[] - - System.String[] - - - None - - - ModuleList - - Specifies an array of modules that are included in the module. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. - This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. - - System.String[] - - System.String[] - - - None - - - FunctionsToExport - - Specifies the functions that the module exports. Wildcards are permitted. - Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. - - System.String[] - - System.String[] - - - None - - - AliasesToExport - - Specifies the aliases that the module exports. Wildcards are permitted. - Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. - - System.String[] - - System.String[] - - - None - - - VariablesToExport - - Specifies the variables that the module exports. Wildcards are permitted. - Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. - - System.String[] - - System.String[] - - - None - - - CmdletsToExport - - Specifies the cmdlets that the module exports. Wildcards are permitted. - Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. - - System.String[] - - System.String[] - - - None - - - DscResourcesToExport - - Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. - - System.String[] - - System.String[] - - - None - - - PrivateData - - Specifies data that is passed to the module when it's imported. - - Hashtable - - Hashtable - - - None - - - Tags - - Specifies an array of tags. - - System.String[] - - System.String[] - - - None - - - ProjectUri - - Specifies the URL of a web page about this project. - - Uri - - Uri - - - None - - - LicenseUri - - Specifies the URL of licensing terms for the module. - - Uri - - Uri - - - None - - - IconUri - - Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. - - Uri - - Uri - - - None - - - ReleaseNotes - - Specifies a string array that contains release notes or comments that you want available for this version of the script. - - System.String[] - - System.String[] - - - None - - - Prerelease - - Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". - - System.String - - System.String - - - None - - - HelpInfoUri - - Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. - The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. - For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. - - Uri - - Uri - - - None - - - DefaultCommandPrefix - - Specifies the default command prefix. - - System.String - - System.String - - - None - - - ExternalModuleDependencies - - Specifies an array of external module dependencies. - - System.String[] - - System.String[] - - - None - - - RequireLicenseAcceptance - - Specifies that a license acceptance is required for the module. - - - System.Management.Automation.SwitchParameter - - - False - - - - - - Path - - Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. - - String - - String - - - None - - - NestedModules - - Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. - - Object[] - - Object[] - - - None - - - Guid - - Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. - - System.Guid - - System.Guid - - - None - - - Author - - Specifies the module author. - - String - - String - - - None - - - CompanyName - - Specifies the company or vendor who created the module. - - String - - String - - - None - - - Copyright - - Specifies a copyright statement for the module. - - String - - String - - - None - - - RootModule - - Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. - If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). - To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. - - System.String - - System.String - - - None - - - ModuleVersion - - Specifies the version of the module. - - System.Version - - System.Version - - - None - - - Description - - Specifies a description of the module. - - System.String - - System.String - - - None - - - ProcessorArchitecture - - Specifies the processor architecture that the module requires. - The acceptable values for this parameter are: - * Amd64 - * Arm - * IA64 - * MSIL - * None (unknown or unspecified) - * X86 - - System.Reflection.ProcessorArchitecture - - System.Reflection.ProcessorArchitecture - - - None - - - CompatiblePSEditions - - Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support - - System.String[] - - System.String[] - - - None - - - PowerShellVersion - - Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. - - System.Version - - System.Version - - - None - - - ClrVersion - - Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. - - System.Version - - System.Version - - - None - - - DotNetFrameworkVersion - - Specifies the minimum version of the Microsoft .NET Framework that the module requires. - - System.Version - - System.Version - - - None - - - PowerShellHostName - - Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. - To find the name of a host program, in the program, type $Host.Name. - - System.String - - System.String - - - None - - - PowerShellHostVersion - - Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. - - System.Version - - System.Version - - - None - - - RequiredModules - - Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. - - System.Object[] - - System.Object[] - - - None - - - TypesToProcess - - Specifies the type files (.ps1xml) that run when the module is imported. - When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. - - System.String[] - - System.String[] - - - None - - - FormatsToProcess - - Specifies the formatting files (.ps1xml) that run when the module is imported. - When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. - - System.String[] - - System.String[] - - - None - - - ScriptsToProcess - - Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. - To specify scripts that run in the module's session state, use the NestedModules key. - - System.String[] - - System.String[] - - - None - - - RequiredAssemblies - - Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. - Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. - - System.String[] - - System.String[] - - - None - - - FileList - - Specifies all items that are included in the module. - - System.String[] - - System.String[] - - - None - - - ModuleList - - Specifies an array of modules that are included in the module. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. - This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. - - System.String[] - - System.String[] - - - None - - - FunctionsToExport - - Specifies the functions that the module exports. Wildcards are permitted. - Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. - - System.String[] - - System.String[] - - - None - - - AliasesToExport - - Specifies the aliases that the module exports. Wildcards are permitted. - Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. - - System.String[] - - System.String[] - - - None - - - VariablesToExport - - Specifies the variables that the module exports. Wildcards are permitted. - Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. - - System.String[] - - System.String[] - - - None - - - CmdletsToExport - - Specifies the cmdlets that the module exports. Wildcards are permitted. - Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. - - System.String[] - - System.String[] - - - None - - - DscResourcesToExport - - Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. - - System.String[] - - System.String[] - - - None - - - PrivateData - - Specifies data that is passed to the module when it's imported. - - Hashtable - - Hashtable - - - None - - - Tags - - Specifies an array of tags. - - System.String[] - - System.String[] - - - None - - - ProjectUri - - Specifies the URL of a web page about this project. - - Uri - - Uri - - - None - - - LicenseUri - - Specifies the URL of licensing terms for the module. - - Uri - - Uri - - - None - - - IconUri - - Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. - - Uri - - Uri - - - None - - - ReleaseNotes - - Specifies a string array that contains release notes or comments that you want available for this version of the script. - - System.String[] - - System.String[] - - - None - - - Prerelease - - Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". - - System.String - - System.String - - - None - - - HelpInfoUri - - Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. - The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. - For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. - - Uri - - Uri - - - None - - - DefaultCommandPrefix - - Specifies the default command prefix. - - System.String - - System.String - - - None - - - ExternalModuleDependencies - - Specifies an array of external module dependencies. - - System.String[] - - System.String[] - - - None - - - RequireLicenseAcceptance - - Specifies that a license acceptance is required for the module. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - - - - System.String[] - - - - - - - - - - ## RELATED LINKS - - - - - -------------------------- Example 1 -------------------------- - PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" - - In this example the author property in the module manifest will be updated to "New Author". - - - - -------------------------- Example 2 -------------------------- - PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" + ---------------- Example 1: Test a valid script ---------------- + PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" +PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" +True +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 1.0.0.0 + +.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 + +.AUTHOR johndoe + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> - In this example the prerelease property will be updated to "beta2" + Assume that the script file specified was created by the New-PSScriptFileInfo cmdlet prior to this example and is valid. This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is a valid script the cmdlet outputs "True". To see what this valid script looks like we can see the contents of the file. - -------------------------- Example 3 -------------------------- - PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." + ------ Example 2: Test an invalid script (missing Author) ------ + PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\invalid_test_script.ps1" +WARNING: The .ps1 script file passed in was not valid due to: PSScript file is missing the required Author property +False + +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 1.0.0.0 + +.GUID 7ec4832e-a4e1-562b-8a8c-241e535ad7d7 + +.AUTHOR + +.COMPANYNAME + +.COPYRIGHT + +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> - In this example the tags and description will be updated to the passed in values. + This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is not a valid script and is missing the required Author metadata property, the cmdlet writes an informative warning message and outputs "False". To see what this invalid script looks like we can see the contents of the file. @@ -4469,390 +749,474 @@ PS C:\> Get-PSResourceRepository - Update-PSResource + Update-PSScriptFileInfo Update - PSResource + PSScriptFileInfo - Updates a package already installed on the user's machine. + Updates an existing .ps1 file with requested properties and ensures it's valid - The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. It updates an already installed package based on the `-Name` parameter argument. It does not return an object. Other parameters allow the package to be updated to be further filtered. + The Update-PSScriptFileInfo cmdlet updates an existing .ps1 file with requested properties and ensures it's valid. - Update-PSResource - - Name + Update-PSScriptFileInfo + + FilePath - Specifies name of a resource or resources to update. + The path the .ps1 script info file will be created at. - System.String[] + String - System.String[] + String - "*" + None - AcceptLicense + Author - For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + The author of the script. + String - System.Management.Automation.SwitchParameter + String - False + None - Credential + CompanyName - Specifies optional credentials to be used when accessing a private repository. + The name of the company owning the script. - System.Management.Automation.PSCredential + String - System.Management.Automation.PSCredential + String None - Prerelease + Copyright - When specified, allows updating to a prerelease version. + The copyright information for the script. + String - System.Management.Automation.SwitchParameter + String - False + None - Quiet + Description - Supresses progress information. + The description of the script. + String - System.Management.Automation.SwitchParameter + String - False + None - Repository + ExternalModuleDependencies - Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + The list of external module dependencies taken by this script. - System.String[] + String[] - System.String[] + String[] None - Scope + ExternalScriptDependencies - Specifies the scope of the resource to update. + The list of external script dependencies taken by this script. - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + String[] - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + String[] None - TrustRepository + Guid - Specifies optional credentials to be used when accessing a private repository. + The GUID for the script. + Guid - System.Management.Automation.SwitchParameter + Guid - False + None - Version + IconUri - Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + The Uri for the icon associated with the script. - System.String + String - System.String + String None - Force + LicenseUri - When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + The Uri for the license associated with the script. + String - System.Management.Automation.SwitchParameter + String - False + None - PassThru + PrivateData - Passes the resource updated to the console. + The private data associated with the script. + String - System.Management.Automation.SwitchParameter + String - False + None - AuthenticodeCheck + ProjectUri - Does a check to to validate signed files and catalog files on Windows. + The Uri for the project associated with the script. + String - System.Management.Automation.SwitchParameter + String - False + None - SkipdependencyCheck + ReleaseNotes - Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + The release notes for the script. + String[] - System.Management.Automation.SwitchParameter + String[] - False + None - - Confirm + + RemoveSignature - Prompts you for confirmation before running the cmdlet. + Remove signature from signed .ps1 (if present) thereby allowing update of script to happen. User should re-sign the updated script afterwards. - System.Management.Automation.SwitchParameter + SwitchParameter False - - WhatIf + + RequiredModules - Shows what would happen if the cmdlet runs. The cmdlet is not run. + The list of modules required by the script. + Hashtable[] - System.Management.Automation.SwitchParameter + Hashtable[] - False + None + + + RequiredScripts + + The list of scripts required by the script. + + String[] + + String[] + + + None + + + Tags + + The tags associated with the script. + + String[] + + String[] + + + None + + + Version + + The version of the script. + + String + + String + + + None - AcceptLicense + Author + + The author of the script. + + String + + String + + + None + + + CompanyName - For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + The name of the company owning the script. - System.Management.Automation.SwitchParameter + String - System.Management.Automation.SwitchParameter + String - False + None - Credential + Copyright - Specifies optional credentials to be used when accessing a private repository. + The copyright information for the script. - System.Management.Automation.PSCredential + String - System.Management.Automation.PSCredential + String None - - Name + + Description - Specifies name of a resource or resources to update. + The description of the script. - System.String[] + String - System.String[] + String - "*" + None - Prerelease + ExternalModuleDependencies - When specified, allows updating to a prerelease version. + The list of external module dependencies taken by this script. - System.Management.Automation.SwitchParameter + String[] - System.Management.Automation.SwitchParameter + String[] - False + None - Quiet + ExternalScriptDependencies - Supresses progress information. + The list of external script dependencies taken by this script. - System.Management.Automation.SwitchParameter + String[] - System.Management.Automation.SwitchParameter + String[] - False + None + + + FilePath + + The path the .ps1 script info file will be created at. + + String + + String + + + None - Repository + Guid - Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + The GUID for the script. - System.String[] + Guid - System.String[] + Guid None - Scope + IconUri - Specifies the scope of the resource to update. + The Uri for the icon associated with the script. - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + String - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + String None - TrustRepository + LicenseUri - Specifies optional credentials to be used when accessing a private repository. + The Uri for the license associated with the script. - System.Management.Automation.SwitchParameter + String - System.Management.Automation.SwitchParameter + String - False + None - Version + PrivateData - Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + The private data associated with the script. - System.String + String - System.String + String None - Force + ProjectUri - When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + The Uri for the project associated with the script. - System.Management.Automation.SwitchParameter + String - System.Management.Automation.SwitchParameter + String - False + None - PassThru + ReleaseNotes - Passes the resource updated to the console. + The release notes for the script. - System.Management.Automation.SwitchParameter + String[] - System.Management.Automation.SwitchParameter + String[] - False + None - AuthenticodeCheck + RemoveSignature - Does a check to to validate signed files and catalog files on Windows. + Remove signature from signed .ps1 (if present) thereby allowing update of script to happen. User should re-sign the updated script afterwards. - System.Management.Automation.SwitchParameter + SwitchParameter - System.Management.Automation.SwitchParameter + SwitchParameter False - SkipdependencyCheck + RequiredModules - Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + The list of modules required by the script. - System.Management.Automation.SwitchParameter + Hashtable[] - System.Management.Automation.SwitchParameter + Hashtable[] - False + None - - Confirm + + RequiredScripts - Prompts you for confirmation before running the cmdlet. + The list of scripts required by the script. - System.Management.Automation.SwitchParameter + String[] - System.Management.Automation.SwitchParameter + String[] - False + None - - WhatIf + + Tags - Shows what would happen if the cmdlet runs. The cmdlet is not run. + The tags associated with the script. - System.Management.Automation.SwitchParameter + String[] - System.Management.Automation.SwitchParameter + String[] - False + None + + + Version + + The version of the script. + + String + + String + + + None - System.String[] + None - + + + + None + + + + + + @@ -4860,29 +1224,56 @@ PS C:\> Get-PSResourceRepository - -------------------------- Example 1 -------------------------- - PS C:\> Update-PSResource -Name "TestModule" - Name Version Prerelease Description - ---- ------- ---------- ----------- - TestModule 1.2.0 test + ---------- Example 1: Update the version of a script ---------- + PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" +PS C:\> Update-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" +PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +<#PSScriptInfo + +.VERSION 2.0.0.0 + +.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 + +.AUTHOR johndoe + +.COMPANYNAME -PS C:\> Update-PSResource -Name "TestModule" +.COPYRIGHT -PS C:\> Update-PSResource -Name "TestModule" - Name Version Prerelease Description - ---- ------- ---------- ----------- - TestModule 1.3.0 test - TestModule 1.2.0 test +.TAGS + +.LICENSEURI + +.PROJECTURI + +.ICONURI + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES + + +.PRIVATEDATA + + +#> + +<# + +.DESCRIPTION +this is a test script + + +#> - In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. + In this example a script is created by running the New-PSScriptFileInfo cmdlet with version specified as 1.0.0.0. To update the script's version to 2.0.0.0, the Update-PSScriptFileInfo cmdlet is run with 'Version' specified as "2.0.0.0". Given that the cmdlet completed running without errors and by looking at the contents of the updated file we see the version was updated to 2.0.0.0. - - - <add> - - - + From fba5d3ac88a9d7e576b1862b4833d2ef57c30f18 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 26 Jul 2022 11:32:27 -0400 Subject: [PATCH 176/276] Script file duplicate keys and parsing help comment block (#726) Co-authored-by: Paul Higinbotham --- src/code/PSScriptContents.cs | 23 ++-- src/code/PSScriptFileInfo.cs | 6 +- src/code/PSScriptHelp.cs | 240 ++++++++++++++--------------------- src/code/PSScriptMetadata.cs | 93 +++++++++++++- src/code/Utils.cs | 68 ---------- 5 files changed, 206 insertions(+), 224 deletions(-) diff --git a/src/code/PSScriptContents.cs b/src/code/PSScriptContents.cs index c04f1dc49..63f1c4e80 100644 --- a/src/code/PSScriptContents.cs +++ b/src/code/PSScriptContents.cs @@ -15,7 +15,7 @@ public sealed class PSScriptContents /// /// End of file contents for the .ps1 file. /// - public string[] EndOfFileContents { get; private set; } = Utils.EmptyStrArray; + public string[] ScriptContents { get; private set; } = Utils.EmptyStrArray; /// /// End of file contents for the .ps1 file. @@ -38,7 +38,7 @@ public sealed class PSScriptContents /// public PSScriptContents(string[] endOfFileContents) { - EndOfFileContents = endOfFileContents; + ScriptContents = endOfFileContents; ContainsSignature = CheckForSignature(); } @@ -60,7 +60,7 @@ internal void ParseContent(string[] commentLines) { if (commentLines.Length != 0) { - EndOfFileContents = commentLines; + ScriptContents = commentLines; ContainsSignature = CheckForSignature(); } } @@ -74,7 +74,7 @@ internal void ParseContent(string[] commentLines) internal string[] EmitContent() { RemoveSignatureString(); - return EndOfFileContents; + return ScriptContents; } #endregion @@ -86,11 +86,12 @@ internal string[] EmitContent() /// private bool CheckForSignature() { - for (int i = 0; i < EndOfFileContents.Length; i++) + for (int i = 0; i < ScriptContents.Length; i++) { - if (String.Equals(EndOfFileContents[i], signatureStartString, StringComparison.InvariantCultureIgnoreCase)) + if (String.Equals(ScriptContents[i], signatureStartString, StringComparison.InvariantCultureIgnoreCase)) { _signatureStartIndex = i; + break; } } @@ -105,9 +106,13 @@ private void RemoveSignatureString() { if (ContainsSignature) { - string[] newEndOfFileContents = new string[EndOfFileContents.Length - _signatureStartIndex]; - Array.Copy(EndOfFileContents, newEndOfFileContents, _signatureStartIndex); - EndOfFileContents = newEndOfFileContents; + // The script signature comment block always appears at the end of the script file, + // so its start location becomes the end of the content section after the signature + // comment block is removed, and is also the length of the content section minus the + // signature block. + string[] contentsWithoutSignature = new string[_signatureStartIndex]; + Array.Copy(ScriptContents, contentsWithoutSignature, _signatureStartIndex); + ScriptContents = contentsWithoutSignature; ContainsSignature = false; } diff --git a/src/code/PSScriptFileInfo.cs b/src/code/PSScriptFileInfo.cs index f3c4f3b5b..dfeee2121 100644 --- a/src/code/PSScriptFileInfo.cs +++ b/src/code/PSScriptFileInfo.cs @@ -132,14 +132,15 @@ internal static bool TryParseScriptFileContents( while (j < fileContents.Length) { string blockLine = fileContents[j]; + psScriptInfoCommentContent.Add(blockLine); if (blockLine.StartsWith("#>")) { + reachedPSScriptInfoCommentEnd = true; i = j + 1; break; } - psScriptInfoCommentContent.Add(blockLine); j++; } @@ -159,6 +160,7 @@ internal static bool TryParseScriptFileContents( while (j < fileContents.Length) { string blockLine = fileContents[j]; + if (blockLine.StartsWith("#>")) { reachedHelpInfoCommentEnd = true; @@ -166,7 +168,7 @@ internal static bool TryParseScriptFileContents( endOfFileContentsStartIndex = i; break; } - + helpInfoCommentContent.Add(blockLine); j++; } diff --git a/src/code/PSScriptHelp.cs b/src/code/PSScriptHelp.cs index 9964d2159..d6cef24ba 100644 --- a/src/code/PSScriptHelp.cs +++ b/src/code/PSScriptHelp.cs @@ -18,52 +18,12 @@ public sealed class PSScriptHelp /// /// The description of the script. /// - public string Description { get; private set; } + public string Description { get; private set; } = String.Empty; /// - /// The synopsis of the script. + /// This contains all help content aside from Description /// - public string Synopsis { get; private set; } - - /// - /// The example(s) relating to the script's usage. - /// - public string[] Example { get; private set; } = Utils.EmptyStrArray; - - /// - /// The inputs to the script. - /// - public string[] Inputs { get; private set; } = Utils.EmptyStrArray; - - /// - /// The outputs to the script. - /// - public string[] Outputs { get; private set; } = Utils.EmptyStrArray; - - /// - /// The notes for the script. - /// - public string[] Notes { get; private set; } = Utils.EmptyStrArray; - - /// - /// The links for the script. - /// - public string[] Links { get; private set; } = Utils.EmptyStrArray; - - /// - /// The components for the script. - /// - public string[] Component { get; private set; } = Utils.EmptyStrArray; - - /// - /// The roles for the script. - /// - public string[] Role { get; private set; } = Utils.EmptyStrArray; - - /// - /// The functionality components for the script. - /// - public string[] Functionality { get; private set; } = Utils.EmptyStrArray; + public List HelpContent { get; private set; } = new List(); #endregion @@ -74,35 +34,7 @@ public sealed class PSScriptHelp /// public PSScriptHelp (string description) { - this.Description = description; - } - - /// - /// This constructor takes values for description as well as other properties and creates a new PSScriptHelp instance. - /// Currently, the New-PSScriptFileInfo and Update-PSScriptFileInfo cmdlets don't support the user providing these values. - /// - public PSScriptHelp ( - string description, - string synopsis, - string[] example, - string[] inputs, - string[] outputs, - string[] notes, - string[] links, - string[] component, - string[] role, - string[] functionality) - { - this.Description = description; - this.Synopsis = synopsis; - this.Example = example; - this.Inputs = inputs; - this.Outputs = outputs; - this.Notes = notes; - this.Links = links; - this.Component = component; - this.Role = role; - this.Functionality = functionality; + Description = description; } /// @@ -121,33 +53,91 @@ internal PSScriptHelp() {} /// internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord error) { - bool successfullyParsed = true; - string[] spaceDelimeter = new string[]{" "}; - string[] newlineDelimeter = new string[]{Environment.NewLine}; + error = null; - // parse content into a hashtable - Hashtable parsedHelpMetadata = Utils.ParseCommentBlockContent(commentLines); + // Parse content into a hashtable. + Hashtable parsedHelpMetadata = ParseHelpContentHelper(commentLines); - if (!ValidateParsedContent(parsedHelpMetadata, out error)) + if (!ValidateParsedContent(parsedHelpMetadata, out ErrorRecord validationError)) { + error = validationError; return false; } - // populate object - Description = (string) parsedHelpMetadata["DESCRIPTION"]; - Synopsis = (string) parsedHelpMetadata["SYNOPSIS"] ?? String.Empty; - Example = Utils.GetStringArrayFromString(newlineDelimeter, (string) parsedHelpMetadata["EXAMPLE"]); - Inputs = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["INPUT"]); - Outputs = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["OUTPUTS"]); - Notes = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["NOTES"]); - Links = Utils.GetStringArrayFromString(newlineDelimeter, (string) parsedHelpMetadata["LINKS"]); - Component = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["COMPONENT"]); - Role = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["ROLE"]); - Functionality = Utils.GetStringArrayFromString(spaceDelimeter, (string) parsedHelpMetadata["FUNCTIONALITY"]); - - return successfullyParsed; + // Populate object. + List descriptionValue = (List) parsedHelpMetadata["DESCRIPTION"]; + Description = String.Join(Environment.NewLine, descriptionValue); + if (parsedHelpMetadata.ContainsKey("HELPCONTENT")) + { + HelpContent = (List) parsedHelpMetadata["HELPCONTENT"]; + } + + return true; } + /// + /// Parses metadata out of PSScriptCommentInfo comment block's lines (which are passed in) into a hashtable. + /// + public static Hashtable ParseHelpContentHelper(string[] commentLines) + { + /** + Comment lines can look like this: + + .KEY1 value + + .KEY2 value + + .KEY2 value2 + + .KEY3 + value + + .KEY4 value + value continued + + */ + + // Parse out Description and everything else into a bucket list. + + List helpContent = new List(); + List descriptionValue = new List(); + bool parsingDescription = false; + + for(int i = 0; i < commentLines.Length; i++) + { + string line = commentLines[i]; + if (line.Trim().StartsWith(".DESCRIPTION")) + { + parsingDescription = true; + } + else if (line.Trim().StartsWith(".")) + { + parsingDescription = false; + helpContent.Add(line); + } + else if (!String.IsNullOrEmpty(line)) + { + if (parsingDescription) + { + descriptionValue.Add(line); + } + else + { + helpContent.Add(line); + } + } + } + + Hashtable parsedHelpMetadata = new Hashtable(); + parsedHelpMetadata.Add("DESCRIPTION", descriptionValue); + if (helpContent.Count != 0) + { + parsedHelpMetadata.Add("HELPCONTENT", helpContent); + } + + return parsedHelpMetadata; + } + /// /// Valides parsed help info content from the hashtable to ensure required help metadata (Description) is present /// and does not contain empty values. @@ -155,7 +145,7 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord error) internal bool ValidateParsedContent(Hashtable parsedHelpMetadata, out ErrorRecord error) { error = null; - if (!parsedHelpMetadata.ContainsKey("DESCRIPTION") || String.IsNullOrEmpty((string) parsedHelpMetadata["DESCRIPTION"]) || String.Equals(((string) parsedHelpMetadata["DESCRIPTION"]).Trim(), String.Empty)) + if (!parsedHelpMetadata.ContainsKey("DESCRIPTION")) { var exMessage = "PSScript file must contain value for Description. Ensure value for Description is passed in and try again."; var ex = new ArgumentException(exMessage); @@ -164,7 +154,18 @@ internal bool ValidateParsedContent(Hashtable parsedHelpMetadata, out ErrorRecor return false; } - if (StringContainsComment((string) parsedHelpMetadata["DESCRIPTION"])) + List descriptionValue = (List) parsedHelpMetadata["DESCRIPTION"]; + string descriptionString = String.Join("", descriptionValue); + if (descriptionValue.Count == 0 || (String.IsNullOrEmpty(descriptionString)) || String.IsNullOrWhiteSpace(descriptionString)) + { + var exMessage = "PSScript file value for Description cannot be null, empty or whitespace. Ensure value for Description meets these conditions and try again."; + var ex = new ArgumentException(exMessage); + var PSScriptInfoMissingDescriptionError = new ErrorRecord(ex, "PSScriptInfoMissingDescription", ErrorCategory.InvalidArgument, null); + error = PSScriptInfoMissingDescriptionError; + return false; + } + + if (StringContainsComment(descriptionString)) { var exMessage = "PSScript file's value for Description cannot contain '<#' or '#>'. Pass in a valid value for Description and try again."; var ex = new ArgumentException(exMessage); @@ -216,60 +217,11 @@ internal string[] EmitContent() psHelpInfoLines.Add($".DESCRIPTION"); psHelpInfoLines.Add($"{Description}{Environment.NewLine}"); - if (!String.IsNullOrEmpty(Synopsis)) - { - psHelpInfoLines.Add($".SYNOPSIS"); - psHelpInfoLines.Add($"{Synopsis}{Environment.NewLine}"); - } - - foreach (string currentExample in Example) - { - psHelpInfoLines.Add($".EXAMPLE"); - psHelpInfoLines.Add($"{currentExample}{Environment.NewLine}"); - } - - foreach (string input in Inputs) - { - psHelpInfoLines.Add($".INPUTS"); - psHelpInfoLines.Add($"{input}{Environment.NewLine}"); - } - - foreach (string output in Outputs) - { - psHelpInfoLines.Add($".OUTPUTS"); - psHelpInfoLines.Add($"{output}{Environment.NewLine}"); - } - - if (Notes.Length > 0) + if (HelpContent.Count != 0) { - psHelpInfoLines.Add($".NOTES"); - psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Notes)}{Environment.NewLine}"); - } - - foreach (string link in Links) - { - psHelpInfoLines.Add($".LINK"); - psHelpInfoLines.Add($"{link}{Environment.NewLine}"); - } - - if (Component.Length > 0) - { - psHelpInfoLines.Add($".COMPONENT"); - psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Component)}{Environment.NewLine}"); + psHelpInfoLines.AddRange(HelpContent); } - if (Role.Length > 0) - { - psHelpInfoLines.Add($".ROLE"); - psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Role)}{Environment.NewLine}"); - } - - if (Functionality.Length > 0) - { - psHelpInfoLines.Add($".FUNCTIONALITY"); - psHelpInfoLines.Add($"{String.Join(Environment.NewLine, Functionality)}{Environment.NewLine}"); - } - psHelpInfoLines.Add("#>"); return psHelpInfoLines.ToArray(); diff --git a/src/code/PSScriptMetadata.cs b/src/code/PSScriptMetadata.cs index ded8088e7..f5cadb1ed 100644 --- a/src/code/PSScriptMetadata.cs +++ b/src/code/PSScriptMetadata.cs @@ -150,7 +150,12 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error List msgsList = new List(); // parse content into a hashtable - Hashtable parsedMetadata = Utils.ParseCommentBlockContent(commentLines); + Hashtable parsedMetadata = ParseMetadataContentHelper(commentLines, out errors); + if (errors.Length != 0) + { + return false; + } + if (parsedMetadata.Count == 0) { @@ -220,6 +225,92 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error return true; } + /// + /// Parses metadata out of PSScriptCommentInfo comment block's lines (which are passed in) into a hashtable. + /// This comment block cannot have duplicate keys. + /// + public static Hashtable ParseMetadataContentHelper(string[] commentLines, out ErrorRecord[] errors) + { + /** + Comment lines can look like this: + + .KEY1 value + + .KEY2 value + + .KEY3 + value + + .KEY4 value + value continued + + */ + + errors = Array.Empty(); + List errorsList = new List(); + + Hashtable parsedHelpMetadata = new Hashtable(); + char[] spaceDelimeter = new char[]{' '}; + string keyName = ""; + string value = ""; + + for (int i = 1; i < commentLines.Length; i++) + { + string line = commentLines[i]; + + // scenario where line is: .KEY VALUE + // this line contains a new metadata property. + if (line.Trim().StartsWith(".")) + { + // check if keyName was previously populated, if so add this key value pair to the metadata hashtable + if (!String.IsNullOrEmpty(keyName)) + { + if (parsedHelpMetadata.ContainsKey(keyName)) + { + var message = String.Format("PowerShell script '<#PSScriptInfo .. #>' comment block metadata cannot contain duplicate key i.e .KEY"); + var ex = new InvalidOperationException(message); + var psScriptInfoDuplicateKeyError = new ErrorRecord(ex, "psScriptInfoDuplicateKeyError", ErrorCategory.ParserError, null); + errorsList.Add(psScriptInfoDuplicateKeyError); + continue; + } + + parsedHelpMetadata.Add(keyName, value); + } + + // setting count to 2 will get 1st separated string (key) into part[0] and the rest (value) into part[1] if any + string[] parts = line.Trim().TrimStart('.').Split(separator: spaceDelimeter, count: 2); + keyName = parts[0]; + value = parts.Length == 2 ? parts[1] : String.Empty; + } + else if (line.Trim().StartsWith("#>")) + { + // This line signifies end of comment block, so add last recorded key value pair before the comment block ends. + if (!String.IsNullOrEmpty(keyName) && !parsedHelpMetadata.ContainsKey(keyName)) + { + // only add this key value if it hasn't already been added + parsedHelpMetadata.Add(keyName, value); + } + } + else if (!String.IsNullOrEmpty(line)) + { + // scenario where line contains text that is a continuation of value from previously recorded key + // this line does not starting with .KEY, and is also not an empty line. + if (value.Equals(String.Empty)) + { + value += line; + } + else + { + value += Environment.NewLine + line; + } + } + } + + errors = errorsList.ToArray(); + + return parsedHelpMetadata; + } + /// /// Valides parsed metadata content from the hashtable to ensure required metadata (Author, Version, Guid) is present /// and does not contain empty values. diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 977d0be8a..32292d87f 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1037,74 +1037,6 @@ public static bool TryCreateModuleSpecification( return moduleSpecCreatedSuccessfully; } - /// - /// Parses metadata out of a comment block's lines (which are passed in) into a hashtable. - /// - public static Hashtable ParseCommentBlockContent(string[] commentLines) - { - /** - Comment lines can look like this: - - .KEY1 value - - .KEY2 value - - .KEY3 - value - - .KEY4 value - value continued - - */ - - Hashtable parsedHelpMetadata = new Hashtable(); - string keyName = ""; - string value = ""; - - for (int i = 1; i < commentLines.Count(); i++) - { - string line = commentLines[i]; - - // scenario where line is: .KEY VALUE - // this line contains a new metadata property. - if (line.Trim().StartsWith(".")) - { - // check if keyName was previously populated, if so add this key value pair to the metadata hashtable - if (!String.IsNullOrEmpty(keyName)) - { - parsedHelpMetadata.Add(keyName, value); - } - - string[] parts = line.Trim().TrimStart('.').Split(); - keyName = parts[0]; - value = parts.Count() > 1 ? String.Join(" ", parts.Skip(1)) : String.Empty; - } - else if (!String.IsNullOrEmpty(line)) - { - // scenario where line contains text that is a continuation of value from previously recorded key - // this line does not starting with .KEY, and is also not an empty line. - if (value.Equals(String.Empty)) - { - value += line; - } - else - { - value += Environment.NewLine + line; - } - } - } - - // this is the case where last key value had multi-line value. - // and we've captured it, but still need to add it to hashtable. - if (!String.IsNullOrEmpty(keyName) && !parsedHelpMetadata.ContainsKey(keyName)) - { - // only add this key value if it hasn't already been added - parsedHelpMetadata.Add(keyName, value); - } - - return parsedHelpMetadata; - } - #endregion #region Directory and File From 5f26c3cdac7361b6c7062f5bb4eb97e3dcd4c43d Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:35:11 -0700 Subject: [PATCH 177/276] Update Find-PSResource.md --- help/Find-PSResource.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index 02342a805..b68a15e7a 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -31,13 +31,13 @@ Searches for packages from a repository (local or remote), based on `-Name` and ### TagParameterSet ``` PowerShell -[[-Name ][-Tag ] [-Prerelease] +[-Name ][-Tag ] [-Prerelease] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` ### TypeParameterSet ``` PowerShell -[[Name ] [-Prerelease] [-Type ] +[Name ] [-Prerelease] [-Type ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` @@ -45,7 +45,7 @@ Searches for packages from a repository (local or remote), based on `-Name` and The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. ## EXAMPLES -These examples assume that the PSGallery repository is registered and contains the packages we are searching for. + ### Example 1 ```powershell PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery From 6ec28d6e0ce0f40d529d03550633200271ddb1fb Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:35:29 -0700 Subject: [PATCH 178/276] Update Get-PSResource.md --- help/Get-PSResource.md | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index 23df4b701..97484d7cd 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -49,12 +49,13 @@ PS C:\> Get-PSResource Az -version "4.0.1-preview" Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. +### Example 5 ```powershell PS C:\> Get-PSResource Az -version "4.0.1" ``` Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. -### Example 5 +### Example 6 ```powershell PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] ``` @@ -89,7 +90,7 @@ Aliases: Required: False Position: 0 Default value: None -Accept pipeline input: True (ByValue) +Accept pipeline input: True Accept wildcard characters: True ``` @@ -150,39 +151,6 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). -## OUTPUTS - -### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo -``` -PSResourceInfo : { - AdditionalMetadata - Author - CompanyName - Copyright - Dependencies - Description - IconUri - Includes - InstalledDate - InstalledLocation - IsPrerelease - LicenseUri - Name - PackageManagementProvider - PowerShellGetFormatVersion - Prerelease - ProjectUri - PublishedDate - ReleaseNotes - Repository - RepositorySourceLocation - Tags - Type - UpdatedDate - Version -} -``` - ## NOTES ## RELATED LINKS From 852a42f4ee0320cfc7ce3aa25ced7cbd20344138 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:36:43 -0700 Subject: [PATCH 179/276] Update Install-PSResource.md --- help/Install-PSResource.md | 41 +++++++++++++++----------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 042e305b8..358bf45a8 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -16,7 +16,7 @@ Installs resources (modules and scripts) from a registered repository onto the m ``` Install-PSResource [-Name ] [-Version ] [-Prerelease] [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-PassThru] [-WhatIf] [-Confirm] [] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet @@ -78,26 +78,6 @@ PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 ``` Installs the PSResources specified in the psd1 file. - - ### Example 5 -```powershell -PS C:\> Install-PSResource -RequiredResource @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} -} -``` - -Installs the PSResources specified in the hashtable. ## PARAMETERS @@ -387,7 +367,21 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - +### -AuthenticodeCheck +Does a check to to validate signed files and catalog files on Windows. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -PassThru Passes the resource installed to the console. @@ -452,9 +446,6 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). -## OUTPUTS -None - ## NOTES ## RELATED LINKS From b6d2e96b0a4e65ffd20442283dd4a5c31ca8e92c Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:37:00 -0700 Subject: [PATCH 180/276] Update New-PSScriptFileInfo.md --- help/New-PSScriptFileInfo.md | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/help/New-PSScriptFileInfo.md b/help/New-PSScriptFileInfo.md index 083893a2a..48301c3d5 100644 --- a/help/New-PSScriptFileInfo.md +++ b/help/New-PSScriptFileInfo.md @@ -131,8 +131,6 @@ this is a test script This example runs the cmdlet with the required 'FilePath' and 'Description' parameters, as well as 'Author', 'Version', and 'RequiredModules' parameters. The 'RequiredModules' parameter describes modules required by the script. It is necessary to provide the ModuleName key in the hashtable and if one wishes to specify verion they must also specify ModuleVersion, RequiredVersion, MaximumVersion, or MinimumVersion keys. The script is successfully created and if the contents of the file are viewed we can see the following values are set in the script file: Description, Author, Guid, and Version and RequiredModules. - - ## PARAMETERS ### -Author @@ -140,7 +138,7 @@ This example runs the cmdlet with the required 'FilePath' and 'Description' para The author of the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) Aliases: Accepted values: @@ -150,7 +148,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -CompanyName @@ -168,7 +165,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Copyright @@ -186,7 +182,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Description @@ -204,7 +199,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ExternalModuleDependencies @@ -222,7 +216,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ExternalScriptDependencies @@ -240,7 +233,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -FilePath @@ -258,7 +250,6 @@ Position: 0 Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Force @@ -276,7 +267,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Guid @@ -294,7 +284,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -IconUri @@ -312,7 +301,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -LicenseUri @@ -330,7 +318,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -PrivateData @@ -348,7 +335,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ProjectUri @@ -366,7 +352,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ReleaseNotes @@ -384,7 +369,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -RequiredModules @@ -402,7 +386,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -RequiredScripts @@ -420,7 +403,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Tags @@ -438,7 +420,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Version @@ -456,10 +437,8 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` - ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). @@ -474,12 +453,7 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### None - - ## NOTES - ## RELATED LINKS -Fill Related Links Here - From ebf7318c8cf5cf6435d849c943e0e74f53fb86fb Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:38:47 -0700 Subject: [PATCH 181/276] Update Publish-PSResource.md --- help/Publish-PSResource.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/help/Publish-PSResource.md b/help/Publish-PSResource.md index 8c74c9dce..22d95ea50 100644 --- a/help/Publish-PSResource.md +++ b/help/Publish-PSResource.md @@ -165,10 +165,6 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). - -## OUTPUTS -None - ## NOTES ## RELATED LINKS From cd1b42376887c52b2d30f0a7b34b28276c439624 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:42:10 -0700 Subject: [PATCH 182/276] Update Register-PSResourceRepository.md --- help/Register-PSResourceRepository.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index 183f58259..9c7d3ac90 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -33,7 +33,7 @@ Register-PSResourceRepository -Repository [-PassThru] [-WhatIf] [- The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. ## EXAMPLES -These examples assume that the repository we attempt to register is not already registered on the user's machine. + ### Example 1 ``` PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" From d3b51eb74cc5cdfce3874fa3d7ba847c0df24cc6 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:42:30 -0700 Subject: [PATCH 183/276] Update Save-PSResource.md --- help/Save-PSResource.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 2809af983..d8c1e30e3 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -15,7 +15,7 @@ Saves resources (modules and scripts) from a registered repository onto the mach ### NameParameterSet ``` Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] + [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet @@ -199,7 +199,21 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - +### -AuthenticodeCheck +Does a check to to validate signed files and catalog files on Windows. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -PassThru Passes the resource saved to the console. @@ -296,9 +310,6 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## INPUTS -## OUTPUTS -None - ## NOTES ## RELATED LINKS From 0acc701e8699c4584ac3d6818651d6282c525bfc Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:43:36 -0700 Subject: [PATCH 184/276] Update Set-PSResourceRepository.md --- help/Set-PSResourceRepository.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index 042a56113..658cb9174 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -26,7 +26,7 @@ Set-PSResourceRepository -Repository [-Priority ] [-WhatIf] The Set-PSResourceRepository cmdlet sets information for a registered repository. ## EXAMPLES -These examples are run independently of each other and assume the repositories used are already registered. The `-PassThru` parameter used with Set-PSResourceRepository is only used to display the changes made to the repository and is not mandatory. + ### Example 1 ```powershell PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" From 8e1fabd43ef8a9ddf0f168703c70fc0879d26a9d Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:44:02 -0700 Subject: [PATCH 185/276] Update Test-PSScriptFileInfo.md --- help/Test-PSScriptFileInfo.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/help/Test-PSScriptFileInfo.md b/help/Test-PSScriptFileInfo.md index 7335c7a42..fb906a964 100644 --- a/help/Test-PSScriptFileInfo.md +++ b/help/Test-PSScriptFileInfo.md @@ -13,7 +13,7 @@ Tests a .ps1 file at the specified path to ensure it is valid. ## SYNTAX -### __AllParameterSets +### AllParameterSets ``` Test-PSScriptFileInfo [-FilePath] [] @@ -150,7 +150,6 @@ Position: 0 Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` @@ -166,14 +165,8 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## OUTPUTS -### bool - - - ## NOTES ## RELATED LINKS -Fill Related Links Here - From 7eefc61eaeb10ff7bd932a3d388312c78e892c59 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:44:28 -0700 Subject: [PATCH 186/276] Update Uninstall-PSResource.md --- help/Uninstall-PSResource.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index a833341b3..ba8b0073a 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -112,6 +112,7 @@ Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False +``` ### -SkipDependencyCheck Skips check to see if other resources are dependent on the resource being uninstalled. @@ -162,9 +163,6 @@ Accept wildcard characters: False ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). -## OUTPUTS -None - ## NOTES ## RELATED LINKS From 250442221af8a967f1a95af64dcde5c8a6376163 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:44:44 -0700 Subject: [PATCH 187/276] Update Unregister-PSResourceRepository.md --- help/Unregister-PSResourceRepository.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/help/Unregister-PSResourceRepository.md b/help/Unregister-PSResourceRepository.md index 0f60bff71..d20f31944 100644 --- a/help/Unregister-PSResourceRepository.md +++ b/help/Unregister-PSResourceRepository.md @@ -122,10 +122,6 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.String[] -## OUTPUTS - -None - ## NOTES ## RELATED LINKS From a05361a6f599ba75a4f2f0c26f7f0204c8ccfc1e Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:45:02 -0700 Subject: [PATCH 188/276] Update Update-ModuleManifest.md --- help/Update-ModuleManifest.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/help/Update-ModuleManifest.md b/help/Update-ModuleManifest.md index 100e7550f..034e7a881 100644 --- a/help/Update-ModuleManifest.md +++ b/help/Update-ModuleManifest.md @@ -41,11 +41,15 @@ PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Autho ``` In this example the author property in the module manifest will be updated to "New Author". +### Example 2 + ```powershell PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" ``` In this example the prerelease property will be updated to "beta2" +### Example 3 + ```powershell PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." ``` @@ -689,10 +693,7 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### System.String[] ## OUTPUTS -None ## NOTES ## RELATED LINKS - -[]() From ccec87c1854bf580ceacd5b3fa4e6def9abf6da1 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:45:21 -0700 Subject: [PATCH 189/276] Update Update-PSResource.md --- help/Update-PSResource.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 167a60673..1471e002a 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -15,7 +15,7 @@ Updates a package already installed on the user's machine. ### NameParameterSet (Default) ``` Update-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] + [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-AuthenticodeCheck] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -215,6 +215,20 @@ Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` +### -AuthenticodeCheck +Does a check to to validate signed files and catalog files on Windows. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + Required: False Position: Named Default value: None From 12b1ff072e9ef664bf28a64e1e99a711af643a9f Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 09:45:38 -0700 Subject: [PATCH 190/276] Update Update-PSScriptFileInfo.md --- help/Update-PSScriptFileInfo.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/help/Update-PSScriptFileInfo.md b/help/Update-PSScriptFileInfo.md index 740c0eaeb..28fa2957e 100644 --- a/help/Update-PSScriptFileInfo.md +++ b/help/Update-PSScriptFileInfo.md @@ -94,7 +94,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -CompanyName @@ -112,7 +111,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Copyright @@ -130,7 +128,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Description @@ -148,7 +145,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ExternalModuleDependencies @@ -166,7 +162,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ExternalScriptDependencies @@ -184,7 +179,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -FilePath @@ -202,7 +196,6 @@ Position: 0 Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Guid @@ -220,7 +213,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -IconUri @@ -238,7 +230,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -LicenseUri @@ -256,7 +247,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -PrivateData @@ -274,7 +264,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ProjectUri @@ -292,7 +281,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -ReleaseNotes @@ -310,7 +298,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -RemoveSignature @@ -328,7 +315,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -RequiredModules @@ -346,7 +332,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -RequiredScripts @@ -364,7 +349,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Tags @@ -382,7 +366,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` ### -Version @@ -400,7 +383,6 @@ Position: Named Default value: Accept pipeline input: False Accept wildcard characters: False -DontShow: False ``` @@ -422,8 +404,3 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## NOTES - -## RELATED LINKS - -Fill Related Links Here - From 79556ee45d6237043d907cab1251bf930615b3f7 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 10:06:04 -0700 Subject: [PATCH 191/276] Update Install-PSResource.md --- help/Install-PSResource.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 358bf45a8..f4120260b 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -79,6 +79,24 @@ PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 Installs the PSResources specified in the psd1 file. +### Example 5 +```powershell +PS C:\> Install-PSResource -RequiredResource @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + TestModule99 = @{} +} +``` + +Installs the PSResources specified in the hashtable. + ## PARAMETERS ### -Name From cb48dcea1bb0247fc9f233258ad77f56fa97a61e Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 10:06:39 -0700 Subject: [PATCH 192/276] Update Find-PSResource.md --- help/Find-PSResource.md | 1 + 1 file changed, 1 insertion(+) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index b68a15e7a..2be404745 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -54,6 +54,7 @@ PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repositor Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... ``` +These examples assume that the PSGallery repository is registered and contains the packages we are searching for. This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". ### Example 2 From 3c32f3f8b7e4b80f45717037067a24cb9709b341 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Tue, 26 Jul 2022 10:52:03 -0700 Subject: [PATCH 193/276] Update PowerShellGet.dll-Help.xml --- help/en-US/PowerShellGet.dll-Help.xml | 5139 +++++++++++++++++++++---- 1 file changed, 4374 insertions(+), 765 deletions(-) diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index a26f1a072..6eb948e70 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -2,458 +2,295 @@ - New-PSScriptFileInfo - New - PSScriptFileInfo + Find-PSResource + Find + PSResource - Creates a new .ps1 file containing metadata for the script, which is used when publishing a script package. + Searches for packages from a repository (local or remote), based on `-Name` and other package properties. - The New-PSScriptFileInfo cmdlet creates a .ps1 file containing metadata for the script. + The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. - New-PSScriptFileInfo - - FilePath - - The path the .ps1 script info file will be created at. - - String - - String - - - None - - - Author - - The author of the script. - - System.String - - System.String - - - None - - - CompanyName - - The name of the company owning the script. - - String - - String - - - None - - - Copyright - - The copyright information for the script. - - String - - String - - - None - - - Description - - The description of the script. - - String - - String - - - None - - - ExternalModuleDependencies + Find-PSResource + + Name - The list of external module dependencies taken by this script. + Name of a resource or resources to find. Accepts wild card character '*'. - String[] + System.String[] - String[] + System.String[] None - ExternalScriptDependencies + Credential - The list of external script dependencies taken by this script. + Optional credentials to be used when accessing a repository. - String[] + System.Management.Automation.PSCredential - String[] + System.Management.Automation.PSCredential None - Force + IncludeDependencies - If used and the .ps1 file specified at the path exists, it rewrites the file. + When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. - SwitchParameter + System.Management.Automation.SwitchParameter False - Guid - - The GUID for the script. - - Guid - - Guid - - - None - - - IconUri - - The Uri for the icon associated with the script. - - String - - String - - - None - - - LicenseUri + ModuleName - The Uri for the license associated with the script. + Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. - String + System.String - String + System.String None - PrivateData + Prerelease - The private data associated with the script. + When specified, includes prerelease versions in search results returned. - String - String + System.Management.Automation.SwitchParameter - None + False - - ProjectUri + + Repository - The Uri for the project associated with the script. + 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. - String + System.String[] - String + System.String[] None - ReleaseNotes + Tag - The release notes for the script. + Filters search results for resources that include one or more of the specified tags. - String[] + System.String[] - String[] + System.String[] None - RequiredModules + Type - The list of modules required by the script. + Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. - Hashtable[] + + Module + Script + DscResource + Command + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - Hashtable[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] None - - RequiredScripts + + Version - The list of scripts required by the script. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - String[] + System.String - String[] + System.String None - - Tags + + Confirm - The tags associated with the script. + Prompts you for confirmation before running the cmdlet. - String[] - String[] + System.Management.Automation.SwitchParameter - None + False - - Version + + WhatIf - The version of the script. + Shows what would happen if the cmdlet runs. The cmdlet is not run. - String - String + System.Management.Automation.SwitchParameter - None + False - Author - - The author of the script. - - System.String - - System.String - - - None - - - CompanyName - - The name of the company owning the script. - - String - - String - - - None - - - Copyright - - The copyright information for the script. - - String - - String - - - None - - - Description - - The description of the script. - - String - - String - - - None - - - ExternalModuleDependencies - - The list of external module dependencies taken by this script. - - String[] - - String[] - - - None - - - ExternalScriptDependencies - - The list of external script dependencies taken by this script. - - String[] - - String[] - - - None - - - FilePath + Credential - The path the .ps1 script info file will be created at. + Optional credentials to be used when accessing a repository. - String + System.Management.Automation.PSCredential - String + System.Management.Automation.PSCredential None - Force + IncludeDependencies - If used and the .ps1 file specified at the path exists, it rewrites the file. + When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False - Guid - - The GUID for the script. - - Guid - - Guid - - - None - - - IconUri + ModuleName - The Uri for the icon associated with the script. + Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. - String + System.String - String + System.String None - - LicenseUri + + Name - The Uri for the license associated with the script. + Name of a resource or resources to find. Accepts wild card character '*'. - String + System.String[] - String + System.String[] None - PrivateData + Prerelease - The private data associated with the script. + When specified, includes prerelease versions in search results returned. - String + System.Management.Automation.SwitchParameter - String + System.Management.Automation.SwitchParameter - None + False - - ProjectUri + + Repository - The Uri for the project associated with the script. + 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. - String + System.String[] - String + System.String[] None - ReleaseNotes + Tag - The release notes for the script. + Filters search results for resources that include one or more of the specified tags. - String[] + System.String[] - String[] + System.String[] None - RequiredModules + Type - The list of modules required by the script. + Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. - Hashtable[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] - Hashtable[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] None - - RequiredScripts + + Version - The list of scripts required by the script. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - String[] + System.String - String[] + System.String None - - Tags + + Confirm - The tags associated with the script. + Prompts you for confirmation before running the cmdlet. - String[] + System.Management.Automation.SwitchParameter - String[] + System.Management.Automation.SwitchParameter - None + False - - Version + + WhatIf - The version of the script. + Shows what would happen if the cmdlet runs. The cmdlet is not run. - String + System.Management.Automation.SwitchParameter - String + System.Management.Automation.SwitchParameter - None + False - None + System.String[] @@ -463,7 +300,7 @@ - None + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo @@ -477,105 +314,273 @@ - Example 1: Creating a script with minimum required parameters - PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" -<#PSScriptInfo - -.VERSION 1.0.0.0 - -.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 - -.AUTHOR johndoe - -.COMPANYNAME - -.COPYRIGHT - -.TAGS - -.LICENSEURI - -.PROJECTURI - -.ICONURI - -.EXTERNALMODULEDEPENDENCIES - -.REQUIREDSCRIPTS - -.EXTERNALSCRIPTDEPENDENCIES - -.RELEASENOTES - - -.PRIVATEDATA - - -#> - -<# - -.DESCRIPTION -this is a test script - - -#> + -------------------------- Example 1 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... - This example runs the cmdlet with the only required parameters, the 'FilePath' parameter sets the path the script is to be created and the 'Description' parameter contains the description for the script. The script is successfully created and if the contents of the file are viewed we can see the Description set as well as Author, Guid, and Version (with default values). + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". - Example 2: Creating a script with RequiredModules, Author, Version and Description parameters - PS C:\> $requiredModules = @(@{ModuleName = "PackageManagement"; ModuleVersion = "1.0.0.0" }, @{ModuleName = "PSReadLine"}) -PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script2.ps1" -Description "this is a test script" -Version "2.0.0.0" -Author "janedoe" -RequiredModules $requiredModules -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" -<#PSScriptInfo - -.VERSION 2.0.0.0 - -.GUID 7ec4832e-a4e1-562b-8a8c-241e535ad7d7 - -.AUTHOR janedoe - -.COMPANYNAME Jane Corporation - -.COPYRIGHT - -.TAGS - -.LICENSEURI - -.PROJECTURI - -.ICONURI - -.EXTERNALMODULEDEPENDENCIES - -.REQUIREDSCRIPTS - -.EXTERNALSCRIPTDEPENDENCIES - -.RELEASENOTES - - -.PRIVATEDATA - - -#> - -#Requires -Module PSReadLine -#Requires -Module @{ ModuleName = 'PackageManagement'; ModuleVersion = '1.0.0.0' } - -<# - -.DESCRIPTION -this is a test script - - -#> + -------------------------- Example 2 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... + + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". + + + + -------------------------- Example 3 -------------------------- + PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease + Name Version Prerelease Description + ---- ------- ---------- ----------- + Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... + Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... + + This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". + + + + -------------------------- Example 4 -------------------------- + PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery + Get-TargetResource 1.0.0.4 WindowsDefender PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery + Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery + Get-TargetResource 1.2.0.0 cRegFile PSGallery + Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery + Get-TargetResource 1.0.0.0 cVNIC PSGallery + Get-TargetResource 1.1.17.0 supVsts PSGallery + + This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + + + + -------------------------- Example 5 -------------------------- + PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + + This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery + Name Version Prerelease ModuleName Repository + ---- ------- ---------- ---------- ---------- + Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery + Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + + This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. + + + + -------------------------- Example 7 -------------------------- + PS C:\> Find-PSResource -Name * + + This will search all PSResources from registered PSResourceRepositories. + + + + + + <add> + + + + + + + Get-PSResource + Get + PSResource + + Returns resources (modules and scripts) installed on the machine via PowerShellGet. + + + + The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. + + + + Get-PSResource + + Name + + Name of a resource or resources to find. Accepts wild card characters or a null value. + + System.String[] + + System.String[] + + + None + + + Path + + Specifies the path to search in. + + System.String + + System.String + + + None + + + Version + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Scope + + Specifies the scope of the resource. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + + + + Name + + Name of a resource or resources to find. Accepts wild card characters or a null value. + + System.String[] + + System.String[] + + + None + + + Path + + Specifies the path to search in. + + System.String + + System.String + + + None + + + Version + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Scope + + Specifies the scope of the resource. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Get-PSResource Az + + This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResource Az -version "1.0.0" + + This will return version 1.0.0 of the Az module. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" + + This will return all versions of the Az module within the specified range. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Get-PSResource Az -version "4.0.1-preview" + + Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. + + + + -------------------------- Example 5 -------------------------- + PS C:\> Get-PSResource Az -version "4.0.1" + + Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] + + Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. + + + + -------------------------- Example 6 -------------------------- + PS C:\> Get-PSResource Az -Path . + + This will return all versions of the Az module that have been installed in the current directory. + + + + -------------------------- Example 7 -------------------------- + PS C:\> Get-PSResource - This example runs the cmdlet with the required 'FilePath' and 'Description' parameters, as well as 'Author', 'Version', and 'RequiredModules' parameters. The 'RequiredModules' parameter describes modules required by the script. It is necessary to provide the ModuleName key in the hashtable and if one wishes to specify verion they must also specify ModuleVersion, RequiredVersion, MaximumVersion, or MinimumVersion keys. The script is successfully created and if the contents of the file are viewed we can see the following values are set in the script file: Description, Author, Guid, and Version and RequiredModules. + This will return all versions and scripts installed on the machine. @@ -583,27 +588,27 @@ this is a test script - Test-PSScriptFileInfo - Test - PSScriptFileInfo + Get-PSResourceRepository + Get + PSResourceRepository - Tests a .ps1 file at the specified path to ensure it is valid. + Finds and returns registered repository information. - The Test-PSScriptFileInfo cmdlet tests a .ps1 file at the specified path to ensure it is valid. + The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. - Test-PSScriptFileInfo - - FilePath + Get-PSResourceRepository + + Name - The path that the .ps1 script info file which is to be tested is located at. + This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. - String + String[] - String + String[] None @@ -611,14 +616,14 @@ this is a test script - - FilePath + + Name - The path that the .ps1 script info file which is to be tested is located at. + This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. - String + String[] - String + String[] None @@ -627,121 +632,3836 @@ this is a test script - None + System.String[] - + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo + + + + + + - + If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. - ---------------- Example 1: Test a valid script ---------------- - PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" -PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -True -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" -<#PSScriptInfo - -.VERSION 1.0.0.0 - -.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 - -.AUTHOR johndoe - -.COMPANYNAME - -.COPYRIGHT - -.TAGS - -.LICENSEURI - -.PROJECTURI - -.ICONURI - -.EXTERNALMODULEDEPENDENCIES - -.REQUIREDSCRIPTS - -.EXTERNALSCRIPTDEPENDENCIES - -.RELEASENOTES - - -.PRIVATEDATA - - -#> - -<# - -.DESCRIPTION -this is a test script - - -#> + -------------------------- Example 1 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*Gallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 + + This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. + + + + + + + + Install-PSResource + Install + PSResource + + Installs resources (modules and scripts) from a registered repository onto the machine. + + + + The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. + + + + Install-PSResource + + Name + + Name of a resource or resources to install. Does not accept wildcard characters or a null value. + + System.String[] + + System.String[] + + + None + + + Version + + Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + When specified, includes prerelease versions in search results returned. + + + System.Management.Automation.SwitchParameter + + + False + + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + + System.Management.Automation.SwitchParameter + + + False + + + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses installation progress bar. + + + System.Management.Automation.SwitchParameter + + + False + + + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + + + System.Management.Automation.SwitchParameter + + + False + + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Install-PSResource + + RequiredResource + + A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + The hashtable will take a format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + A json string will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + RequiredResource + + RequiredResource + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + + System.Management.Automation.SwitchParameter + + + False + + + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses installation progress bar. + + + System.Management.Automation.SwitchParameter + + + False + + + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + + + System.Management.Automation.SwitchParameter + + + False + + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Install-PSResource + + RequiredResourceFile + + Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + The psd1 will take a hashtable format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + json files will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + System.String[] + + System.String[] + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + Scope + + Specifies the scope under which a user has access. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + + System.Management.Automation.SwitchParameter + + + False + + + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses installation progress bar. + + + System.Management.Automation.SwitchParameter + + + False + + + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + + + System.Management.Automation.SwitchParameter + + + False + + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource installed to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + Name + + Name of a resource or resources to install. Does not accept wildcard characters or a null value. + + System.String[] + + System.String[] + + + None + + + Version + + Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + When specified, includes prerelease versions in search results returned. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + + RequiredResource + + A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. + The hashtable will take a format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + A json string will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + RequiredResource + + RequiredResource + + + None + + + RequiredResourceFile + + Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. + The psd1 will take a hashtable format with the module attributes like the following example + + @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + + TestModule99 = @{} + } + + json files will take the following example format + + { + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} + } + + System.String[] + + System.String[] + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + Scope + + Specifies the scope under which a user has access. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Reinstall + + Writes over any previously installed resource version that already exists on the machine. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses installation progress bar. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + AcceptLicense + + Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource installed to the console. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Install-PSResource Az + + Installs the Az module. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" + + Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Install-PSResource Az -Repository PSGallery + + Installs the latest stable Az module from the PowerShellGallery. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Install-PSResource Az -Reinstall + + Installs the Az module and will write over any previously installed version if it is already installed. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 + + Installs the PSResources specified in the psd1 file. + + + + + + Online Version: + + + + + + + Publish-PSResource + Publish + PSResource + + Publishes a specified module from the local computer to PSResource repository. + + + + The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. + + + + Publish-PSResource + + Path + + When specified, includes prerelease versions in search. + + System.String + + System.String + + + None + + + APIKey + + Specifies the API key that you want to use to publish a resource to the online gallery. + + System.String + + System.String + + + None + + + Repository + + Specifies the repository to publish to. + + System.String + + System.String + + + None + + + DestinationPath + + Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + + System.String + + System.String + + + None + + + Credential + + Specifies a user account that has rights to a specific repository (used for finding dependencies). + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + SkipDependenciesCheck + + Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + + + System.Management.Automation.SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + APIKey + + Specifies the API key that you want to use to publish a resource to the online gallery. + + System.String + + System.String + + + None + + + Repository + + Specifies the repository to publish to. + + System.String + + System.String + + + None + + + Path + + When specified, includes prerelease versions in search. + + System.String + + System.String + + + None + + + DestinationPath + + Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + + System.String + + System.String + + + None + + + Credential + + Specifies a user account that has rights to a specific repository (used for finding dependencies). + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + SkipDependenciesCheck + + Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Publish-PSResource -Path c:\Test-Module + + This will publish the module 'Test-Module' to the highest priority repository + + + + -------------------------- Example 2 -------------------------- + PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' + + This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. + + + + + + Online Version: + + + + + + + Register-PSResourceRepository + Register + PSResourceRepository + + Registers a repository for PowerShell resources. + + + + The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. + + + + Register-PSResourceRepository + + Name + + Name of the repository to be registered. Cannot be "PSGallery". + + String + + String + + + None + + + Uri + + Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + + String + + String + + + None + + + Priority + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 + + Int32 + + + 50 + + + Trusted + + Specifies whether the repository should be trusted. + + + SwitchParameter + + + False + + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo + + PSCredentialInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + PassThru + + When specified, displays the succcessfully registered repository and its information. + + + SwitchParameter + + + False + + + + Register-PSResourceRepository + + Priority + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 + + Int32 + + + 50 + + + PSGallery + + When specified, registers PSGallery repository. + + + SwitchParameter + + + False + + + Trusted + + Specifies whether the repository should be trusted. + + + SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + PassThru + + When specified, displays the succcessfully registered repository and its information. + + + SwitchParameter + + + False + + + + Register-PSResourceRepository + + Repository + + Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + + Hashtable[] + + Hashtable[] + + + None + + + Trusted + + Specifies whether the repository should be trusted. + + + SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + PassThru + + When specified, displays the succcessfully registered repository and its information. + + + SwitchParameter + + + False + + + + + + Name + + Name of the repository to be registered. Cannot be "PSGallery". + + String + + String + + + None + + + Priority + + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + + Int32 + + Int32 + + + 50 + + + PSGallery + + When specified, registers PSGallery repository. + + SwitchParameter + + SwitchParameter + + + False + + + Repository + + Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + + Hashtable[] + + Hashtable[] + + + None + + + Trusted + + Specifies whether the repository should be trusted. + + SwitchParameter + + SwitchParameter + + + False + + + Uri + + Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + + String + + String + + + None + + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo + + PSCredentialInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + PassThru + + When specified, displays the succcessfully registered repository and its information. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.String + + + + + + + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) + + + + + + + + + Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. + Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). + Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + + This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Register-PSResourceRepository -PSGallery +PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. + + + + -------------------------- Example 3 -------------------------- + PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} +PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables +PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir False 50 + + This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. + + + + + + + + Save-PSResource + Save + PSResource + + Saves resources (modules and scripts) from a registered repository onto the machine. + + + + The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. + + + + Save-PSResource + + Name + + Name of a resource or resources to save. Does not accept wildcard characters or a null value. + + System.String[] + + System.String[] + + + None + + + Version + + Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + Specifies to include prerelease versions. + + + System.Management.Automation.SwitchParameter + + + False + + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + AsNupkg + + Saves the resource as a zipped .nupkg file. + + + System.Management.Automation.SwitchParameter + + + False + + + IncludeXML + + Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + + + System.Management.Automation.SwitchParameter + + + False + + + Path + + Specifies the path to save the resource to. + + System.String + + System.String + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource saved to the console. + + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses progress information. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + Name + + Name of a resource or resources to save. Does not accept wildcard characters or a null value. + + System.String[] + + System.String[] + + + None + + + Version + + Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Prerelease + + Specifies to include prerelease versions. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Repository + + Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + + System.String[] + + System.String[] + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + AsNupkg + + Saves the resource as a zipped .nupkg file. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + IncludeXML + + Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Path + + Specifies the path to save the resource to. + + System.String + + System.String + + + None + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Does a check to to validate signed files and catalog files on Windows. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + Passes the resource saved to the console. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + SkipDependencyCheck + + Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Quiet + + Supresses progress information. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Save-PSResource -Name Az + + Saves the Az module + + + + -------------------------- Example 2 -------------------------- + PS C:\> Save-PSResource -Name Az -Repository PSGallery + + Saves the Az module found in the PowerShellGallery + + + + -------------------------- Example 3 -------------------------- + PS C:\> Save-PSResource Az -AsNupkg + + Saves the Az module as a .nupkg file + + + + -------------------------- Example 4 -------------------------- + PS C:\> Save-PSResource Az -IncludeXML + + Saves the Az module and includes the PowerShellGet XML metadata + + + + + + Online Version: + + + + + + + Set-PSResourceRepository + Set + PSResourceRepository + + Sets information for a registered repository. + + + + The Set-PSResourceRepository cmdlet sets information for a registered repository. + + + + Set-PSResourceRepository + + Name + + Specifies the name of the repository to be set. + + System.String + + System.String + + + None + + + Priority + + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + + System.Int32 + + System.Int32 + + + None + + + Trusted + + Specifies whether the repository should be trusted. + + + System.Management.Automation.SwitchParameter + + + False + + + Uri + + Specifies the location of the repository to be set. + + String + + String + + + None + + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo + + PSCredentialInfo + + + None + + + PassThru + + When specified, displays the succcessfully registered repository and its information + + + System.Management.Automation.SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + Name + + Specifies the name of the repository to be set. + + System.String + + System.String + + + None + + + Priority + + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + + System.Int32 + + System.Int32 + + + None + + + Trusted + + Specifies whether the repository should be trusted. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Uri + + Specifies the location of the repository to be set. + + String + + String + + + None + + + CredentialInfo + + Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. + `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + + PSCredentialInfo + + PSCredentialInfo + + + None + + + PassThru + + When specified, displays the succcessfully registered repository and its information + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + System.String + + + + + + + + System.Collections.Hashtable[] + + + + + + + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) + + + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery file:///c:/code/testdir False 50 + + This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PSGallery" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 +PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 25 + + This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Get-PSResourceRepository -Name "*" + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + +PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} + +PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 True 50 + PoshTestGallery file:///c:/code/testdir False 50 + + This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. + + + + + + + + Uninstall-PSResource + Uninstall + PSResource + + Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. + + + + The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. + + + + Uninstall-PSResource + + Name + + Name of a resource or resources that has been installed. Accepts wild card characters. + + System.String[] + + System.String[] + + + None + + + Version + + Specifies the version of the resource to be uninstalled. + + System.String + + System.String + + + None + + + Scope + + Specifies the scope of the resource to uninstall. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + SkipDependencyCheck + + Skips check to see if other resources are dependent on the resource being uninstalled. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + Name + + Name of a resource or resources that has been installed. Accepts wild card characters. + + System.String[] + + System.String[] + + + None + + + Version + + Specifies the version of the resource to be uninstalled. + + System.String + + System.String + + + None + + + Scope + + Specifies the scope of the resource to uninstall. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + SkipDependencyCheck + + Skips check to see if other resources are dependent on the resource being uninstalled. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Uninstall-PSResource Az + + Uninstalls the latest version of the Az module. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "1.0.0" + + Uninstalls version 1.0.0 of the Az module. + + + + -------------------------- Example 3 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" + + Uninstalls all versions within the specified version range. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" + + Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. + + + + -------------------------- Example 4 -------------------------- + PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease + + Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. + + + + + + + + Unregister-PSResourceRepository + Unregister + PSResourceRepository + + Un-registers a repository from the repository store. + + + + The Unregister-PSResourceRepository cmdlet unregisters a repository. + + + + Unregister-PSResourceRepository + + Name + + This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + + String[] + + String[] + + + None + + + PassThru + + Passes the resource installed to the console. + + + SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Name + + This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + + String[] + + String[] + + + None + + + PassThru + + Passes the resource installed to the console. + + SwitchParameter + + SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.String[] + + + + + + + + + + + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" +PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" +PS C:\> + + In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. + + + + -------------------------- Example 2 -------------------------- + PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 + PSGallery https://www.powershellgallery.com/api/v2 False 50 + psgettestlocal file:///c:/code/testdir True 50 + +PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" +PS C:\> Get-PSResourceRepository + Name Uri Trusted Priority + ---- --- ------- -------- + PSGallery https://www.powershellgallery.com/api/v2 False 50 + + In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. + + + + + + + + Update-ModuleManifest + Update + ModuleManifest + + Updates a module manifest file. + + + + The Update-ModuleManifest cmdlet replaces the Update-ModuleManifest cmdlet from V2. It updates a module manifest based on the `-Path` parameter argument. It does not return an object. Other parameters allow specific properties of the manifest to be updated. + + + + Update-ModuleManifest + + Path + + Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + + String + + String + + + None + + + NestedModules + + Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + + Object[] + + Object[] + + + None + + + Guid + + Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + + System.Guid + + System.Guid + + + None + + + Author + + Specifies the module author. + + String + + String + + + None + + + CompanyName + + Specifies the company or vendor who created the module. + + String + + String + + + None + + + Copyright + + Specifies a copyright statement for the module. + + String + + String + + + None + + + RootModule + + Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. + If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). + To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + + System.String + + System.String + + + None + + + ModuleVersion + + Specifies the version of the module. + + System.Version + + System.Version + + + None + + + Description + + Specifies a description of the module. + + System.String + + System.String + + + None + + + ProcessorArchitecture + + Specifies the processor architecture that the module requires. + The acceptable values for this parameter are: + * Amd64 + * Arm + * IA64 + * MSIL + * None (unknown or unspecified) + * X86 + + System.Reflection.ProcessorArchitecture + + System.Reflection.ProcessorArchitecture + + + None + + + CompatiblePSEditions + + Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + + + Desktop + Core + + System.String[] + + System.String[] + + + None + + + PowerShellVersion + + Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + + System.Version + + System.Version + + + None + + + ClrVersion + + Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + DotNetFrameworkVersion + + Specifies the minimum version of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + PowerShellHostName + + Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + To find the name of a host program, in the program, type $Host.Name. + + System.String + + System.String + + + None + + + PowerShellHostVersion + + Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + + System.Version + + System.Version + + + None + + + RequiredModules + + Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + + System.Object[] + + System.Object[] + + + None + + + TypesToProcess + + Specifies the type files (.ps1xml) that run when the module is imported. + When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + FormatsToProcess + + Specifies the formatting files (.ps1xml) that run when the module is imported. + When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + ScriptsToProcess + + Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + To specify scripts that run in the module's session state, use the NestedModules key. + + System.String[] + + System.String[] + + + None + + + RequiredAssemblies + + Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. + Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + + System.String[] + + System.String[] + + + None + + + FileList + + Specifies all items that are included in the module. + + System.String[] + + System.String[] + + + None + + + ModuleList + + Specifies an array of modules that are included in the module. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. + + System.String[] + + System.String[] + + + None + + + FunctionsToExport + + Specifies the functions that the module exports. Wildcards are permitted. + Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + + System.String[] + + System.String[] + + + None + + + AliasesToExport + + Specifies the aliases that the module exports. Wildcards are permitted. + Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + + System.String[] + + System.String[] + + + None + + + VariablesToExport + + Specifies the variables that the module exports. Wildcards are permitted. + Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + + System.String[] + + System.String[] + + + None + + + CmdletsToExport + + Specifies the cmdlets that the module exports. Wildcards are permitted. + Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + + System.String[] + + System.String[] + + + None + + + DscResourcesToExport + + Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + + System.String[] + + System.String[] + + + None + + + PrivateData + + Specifies data that is passed to the module when it's imported. + + Hashtable + + Hashtable + + + None + + + Tags + + Specifies an array of tags. + + System.String[] + + System.String[] + + + None + + + ProjectUri + + Specifies the URL of a web page about this project. + + Uri + + Uri + + + None + + + LicenseUri + + Specifies the URL of licensing terms for the module. + + Uri + + Uri + + + None + + + IconUri + + Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + + Uri + + Uri + + + None + + + ReleaseNotes + + Specifies a string array that contains release notes or comments that you want available for this version of the script. + + System.String[] + + System.String[] + + + None + + + Prerelease + + Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + + System.String + + System.String + + + None + + + HelpInfoUri + + Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. + The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. + For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + + Uri + + Uri + + + None + + + DefaultCommandPrefix + + Specifies the default command prefix. + + System.String + + System.String + + + None + + + ExternalModuleDependencies + + Specifies an array of external module dependencies. + + System.String[] + + System.String[] + + + None + + + RequireLicenseAcceptance + + Specifies that a license acceptance is required for the module. + + + System.Management.Automation.SwitchParameter + + + False + + + + + + Path + + Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + + String + + String + + + None + + + NestedModules + + Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + + Object[] + + Object[] + + + None + + + Guid + + Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + + System.Guid + + System.Guid + + + None + + + Author + + Specifies the module author. + + String + + String + + + None + + + CompanyName + + Specifies the company or vendor who created the module. + + String + + String + + + None + + + Copyright + + Specifies a copyright statement for the module. + + String + + String + + + None + + + RootModule + + Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. + If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). + To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + + System.String + + System.String + + + None + + + ModuleVersion + + Specifies the version of the module. + + System.Version + + System.Version + + + None + + + Description + + Specifies a description of the module. + + System.String + + System.String + + + None + + + ProcessorArchitecture + + Specifies the processor architecture that the module requires. + The acceptable values for this parameter are: + * Amd64 + * Arm + * IA64 + * MSIL + * None (unknown or unspecified) + * X86 + + System.Reflection.ProcessorArchitecture + + System.Reflection.ProcessorArchitecture + + + None + + + CompatiblePSEditions + + Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + + System.String[] + + System.String[] + + + None + + + PowerShellVersion + + Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + + System.Version + + System.Version + + + None + + + ClrVersion + + Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + DotNetFrameworkVersion + + Specifies the minimum version of the Microsoft .NET Framework that the module requires. + + System.Version + + System.Version + + + None + + + PowerShellHostName + + Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + To find the name of a host program, in the program, type $Host.Name. + + System.String + + System.String + + + None + + + PowerShellHostVersion + + Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + + System.Version + + System.Version + + + None + + + RequiredModules + + Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + + System.Object[] + + System.Object[] + + + None + + + TypesToProcess + + Specifies the type files (.ps1xml) that run when the module is imported. + When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + FormatsToProcess + + Specifies the formatting files (.ps1xml) that run when the module is imported. + When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + + System.String[] + + System.String[] + + + None + + + ScriptsToProcess + + Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + To specify scripts that run in the module's session state, use the NestedModules key. + + System.String[] + + System.String[] + + + None + + + RequiredAssemblies + + Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. + Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + + System.String[] + + System.String[] + + + None + + + FileList + + Specifies all items that are included in the module. + + System.String[] + + System.String[] + + + None + + + ModuleList + + Specifies an array of modules that are included in the module. + Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. + + System.String[] + + System.String[] + + + None + + + FunctionsToExport + + Specifies the functions that the module exports. Wildcards are permitted. + Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + + System.String[] + + System.String[] + + + None + + + AliasesToExport + + Specifies the aliases that the module exports. Wildcards are permitted. + Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + + System.String[] + + System.String[] + + + None + + + VariablesToExport + + Specifies the variables that the module exports. Wildcards are permitted. + Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + + System.String[] + + System.String[] + + + None + + + CmdletsToExport + + Specifies the cmdlets that the module exports. Wildcards are permitted. + Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + + System.String[] + + System.String[] + + + None + + + DscResourcesToExport + + Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + + System.String[] + + System.String[] + + + None + + + PrivateData + + Specifies data that is passed to the module when it's imported. + + Hashtable + + Hashtable + + + None + + + Tags + + Specifies an array of tags. + + System.String[] + + System.String[] + + + None + + + ProjectUri + + Specifies the URL of a web page about this project. + + Uri + + Uri + + + None + + + LicenseUri + + Specifies the URL of licensing terms for the module. + + Uri + + Uri + + + None + + + IconUri + + Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + + Uri + + Uri + + + None + + + ReleaseNotes + + Specifies a string array that contains release notes or comments that you want available for this version of the script. + + System.String[] + + System.String[] + + + None + + + Prerelease + + Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + + System.String + + System.String + + + None + + + HelpInfoUri + + Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. + The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. + For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + + Uri + + Uri + + + None + + + DefaultCommandPrefix + + Specifies the default command prefix. + + System.String + + System.String + + + None + + + ExternalModuleDependencies + + Specifies an array of external module dependencies. + + System.String[] + + System.String[] + + + None + + + RequireLicenseAcceptance + + Specifies that a license acceptance is required for the module. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + + + + System.String[] + + + + + + + + + + ## RELATED LINKS + + + + + -------------------------- Example 1 -------------------------- + PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" - Assume that the script file specified was created by the New-PSScriptFileInfo cmdlet prior to this example and is valid. This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is a valid script the cmdlet outputs "True". To see what this valid script looks like we can see the contents of the file. + In this example the author property in the module manifest will be updated to "New Author". - ------ Example 2: Test an invalid script (missing Author) ------ - PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\invalid_test_script.ps1" -WARNING: The .ps1 script file passed in was not valid due to: PSScript file is missing the required Author property -False - -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" -<#PSScriptInfo - -.VERSION 1.0.0.0 - -.GUID 7ec4832e-a4e1-562b-8a8c-241e535ad7d7 - -.AUTHOR - -.COMPANYNAME - -.COPYRIGHT - -.TAGS - -.LICENSEURI - -.PROJECTURI - -.ICONURI - -.EXTERNALMODULEDEPENDENCIES - -.REQUIREDSCRIPTS - -.EXTERNALSCRIPTDEPENDENCIES - -.RELEASENOTES - - -.PRIVATEDATA - - -#> - -<# - -.DESCRIPTION -this is a test script - - -#> + -------------------------- Example 2 -------------------------- + PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" + + In this example the prerelease property will be updated to "beta2" + + + + -------------------------- Example 3 -------------------------- + PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." - This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is not a valid script and is missing the required Author metadata property, the cmdlet writes an informative warning message and outputs "False". To see what this invalid script looks like we can see the contents of the file. + In this example the tags and description will be updated to the passed in values. @@ -749,474 +4469,390 @@ this is a test script - Update-PSScriptFileInfo + Update-PSResource Update - PSScriptFileInfo + PSResource - Updates an existing .ps1 file with requested properties and ensures it's valid + Updates a package already installed on the user's machine. - The Update-PSScriptFileInfo cmdlet updates an existing .ps1 file with requested properties and ensures it's valid. + The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. It updates an already installed package based on the `-Name` parameter argument. It does not return an object. Other parameters allow the package to be updated to be further filtered. - Update-PSScriptFileInfo - - FilePath - - The path the .ps1 script info file will be created at. - - String - - String - - - None - - - Author - - The author of the script. - - String - - String - - - None - - - CompanyName - - The name of the company owning the script. - - String - - String - - - None - - - Copyright + Update-PSResource + + Name - The copyright information for the script. + Specifies name of a resource or resources to update. - String + System.String[] - String + System.String[] - None + "*" - Description + AcceptLicense - The description of the script. + For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. - String - String + System.Management.Automation.SwitchParameter - None + False - ExternalModuleDependencies + Credential - The list of external module dependencies taken by this script. + Specifies optional credentials to be used when accessing a private repository. - String[] + System.Management.Automation.PSCredential - String[] + System.Management.Automation.PSCredential None - ExternalScriptDependencies + Prerelease - The list of external script dependencies taken by this script. + When specified, allows updating to a prerelease version. - String[] - String[] + System.Management.Automation.SwitchParameter - None + False - Guid + Quiet - The GUID for the script. + Supresses progress information. - Guid - Guid + System.Management.Automation.SwitchParameter - None + False - IconUri + Repository - The Uri for the icon associated with the script. + Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. - String + System.String[] - String + System.String[] None - LicenseUri + Scope - The Uri for the license associated with the script. + Specifies the scope of the resource to update. - String + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - PrivateData + TrustRepository - The private data associated with the script. + Specifies optional credentials to be used when accessing a private repository. - String - String + System.Management.Automation.SwitchParameter - None + False - ProjectUri + Version - The Uri for the project associated with the script. + Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - String + System.String - String + System.String None - ReleaseNotes + Force - The release notes for the script. + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. - String[] - String[] + System.Management.Automation.SwitchParameter - None + False - RemoveSignature + PassThru - Remove signature from signed .ps1 (if present) thereby allowing update of script to happen. User should re-sign the updated script afterwards. + Passes the resource updated to the console. - SwitchParameter + System.Management.Automation.SwitchParameter False - RequiredModules + AuthenticodeCheck - The list of modules required by the script. + Does a check to to validate signed files and catalog files on Windows. - Hashtable[] - Hashtable[] + System.Management.Automation.SwitchParameter - None + False - RequiredScripts + SkipdependencyCheck - The list of scripts required by the script. + Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. - String[] - String[] + System.Management.Automation.SwitchParameter - None + False - - Tags + + Confirm - The tags associated with the script. + Prompts you for confirmation before running the cmdlet. - String[] - String[] + System.Management.Automation.SwitchParameter - None + False - - Version + + WhatIf - The version of the script. + Shows what would happen if the cmdlet runs. The cmdlet is not run. - String - String + System.Management.Automation.SwitchParameter - None + False - Author - - The author of the script. - - String - - String - - - None - - - CompanyName - - The name of the company owning the script. - - String - - String - - - None - - - Copyright + AcceptLicense - The copyright information for the script. + For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. - String + System.Management.Automation.SwitchParameter - String + System.Management.Automation.SwitchParameter - None + False - Description + Credential - The description of the script. + Specifies optional credentials to be used when accessing a private repository. - String + System.Management.Automation.PSCredential - String + System.Management.Automation.PSCredential None - - ExternalModuleDependencies + + Name - The list of external module dependencies taken by this script. + Specifies name of a resource or resources to update. - String[] + System.String[] - String[] + System.String[] - None + "*" - ExternalScriptDependencies - - The list of external script dependencies taken by this script. - - String[] - - String[] - - - None - - - FilePath + Prerelease - The path the .ps1 script info file will be created at. + When specified, allows updating to a prerelease version. - String + System.Management.Automation.SwitchParameter - String + System.Management.Automation.SwitchParameter - None + False - Guid + Quiet - The GUID for the script. + Supresses progress information. - Guid + System.Management.Automation.SwitchParameter - Guid + System.Management.Automation.SwitchParameter - None + False - IconUri + Repository - The Uri for the icon associated with the script. + Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. - String + System.String[] - String + System.String[] None - LicenseUri + Scope - The Uri for the license associated with the script. + Specifies the scope of the resource to update. - String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - PrivateData + TrustRepository - The private data associated with the script. + Specifies optional credentials to be used when accessing a private repository. - String + System.Management.Automation.SwitchParameter - String + System.Management.Automation.SwitchParameter - None + False - ProjectUri + Version - The Uri for the project associated with the script. + Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - String + System.String - String + System.String None - ReleaseNotes + Force - The release notes for the script. + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. - String[] + System.Management.Automation.SwitchParameter - String[] + System.Management.Automation.SwitchParameter - None + False - RemoveSignature + PassThru - Remove signature from signed .ps1 (if present) thereby allowing update of script to happen. User should re-sign the updated script afterwards. + Passes the resource updated to the console. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False - RequiredModules + AuthenticodeCheck - The list of modules required by the script. + Does a check to to validate signed files and catalog files on Windows. - Hashtable[] + System.Management.Automation.SwitchParameter - Hashtable[] + System.Management.Automation.SwitchParameter - None + False - RequiredScripts + SkipdependencyCheck - The list of scripts required by the script. + Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. - String[] + System.Management.Automation.SwitchParameter - String[] + System.Management.Automation.SwitchParameter - None + False - - Tags + + Confirm - The tags associated with the script. + Prompts you for confirmation before running the cmdlet. - String[] + System.Management.Automation.SwitchParameter - String[] + System.Management.Automation.SwitchParameter - None + False - - Version + + WhatIf - The version of the script. + Shows what would happen if the cmdlet runs. The cmdlet is not run. - String + System.Management.Automation.SwitchParameter - String + System.Management.Automation.SwitchParameter - None + False - None + System.String[] - - - - None - - - - - - + @@ -1224,56 +4860,29 @@ this is a test script - ---------- Example 1: Update the version of a script ---------- - PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" -PS C:\> Update-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" -<#PSScriptInfo - -.VERSION 2.0.0.0 - -.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 - -.AUTHOR johndoe - -.COMPANYNAME + -------------------------- Example 1 -------------------------- + PS C:\> Update-PSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.2.0 test -.COPYRIGHT +PS C:\> Update-PSResource -Name "TestModule" -.TAGS - -.LICENSEURI - -.PROJECTURI - -.ICONURI - -.EXTERNALMODULEDEPENDENCIES - -.REQUIREDSCRIPTS - -.EXTERNALSCRIPTDEPENDENCIES - -.RELEASENOTES - - -.PRIVATEDATA - - -#> - -<# - -.DESCRIPTION -this is a test script - - -#> +PS C:\> Update-PSResource -Name "TestModule" + Name Version Prerelease Description + ---- ------- ---------- ----------- + TestModule 1.3.0 test + TestModule 1.2.0 test - In this example a script is created by running the New-PSScriptFileInfo cmdlet with version specified as 1.0.0.0. To update the script's version to 2.0.0.0, the Update-PSScriptFileInfo cmdlet is run with 'Version' specified as "2.0.0.0". Given that the cmdlet completed running without errors and by looking at the contents of the updated file we see the version was updated to 2.0.0.0. + In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. - + + + <add> + + + From daa5e67e01fedffb77816a1cc99a912e5b2b8f05 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 26 Jul 2022 11:25:45 -0700 Subject: [PATCH 194/276] Update pkg version, changelog, release notes for 3.0.15-beta15 release (#725) --- .ci/ci_release.yml | 2 +- CHANGELOG.md | 10 ++++++++++ src/PowerShellGet.psd1 | 14 ++++++++++++-- src/code/FindPSResource.cs | 3 +-- src/code/PowerShellGet.csproj | 6 +++--- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 8f1a739df..46a67f715 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -244,7 +244,7 @@ stages: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' PackageName: 'PowerShellGet' - PackageVersion: '3.0.14' + PackageVersion: '3.0.15' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' diff --git a/CHANGELOG.md b/CHANGELOG.md index 99ff88819..80a5829e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # CHANGELOG +## 3.0.15-beta15 + +### New Features +- Implementation of New-ScriptFileInfo, Update-ScriptFileInfo, and Test-ScriptFileInfo cmdlets (#708) +- Implementation of Update-ModuleManifest cmdlet (#677) +- Implentation of Authenticode validation via -AuthenticodeCheck for Install-PSResource (#632) + +### Bug Fixes +- Bug fix for installing modules with manifests that contain dynamic script blocks (#681) + ## 3.0.14-beta14 ### Bug Fixes diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 2b4953d39..ec1415ddb 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.14' + ModuleVersion = '3.0.15' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -34,7 +34,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta14' + Prerelease = 'beta15' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -44,6 +44,16 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 3.0.15-beta15 + +### New Features +- Implementation of New-ScriptFileInfo, Update-ScriptFileInfo, and Test-ScriptFileInfo cmdlets (#708) +- Implementation of Update-ModuleManifest cmdlet (#677) +- Implentation of Authenticode validation via -AuthenticodeCheck for Install-PSResource (#632) + +### Bug Fixes +- Bug fix for installing modules with manifests that contain dynamic script blocks (#681) + ## 3.0.14-beta14 ### Bug Fixes diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index b99b520c5..6d01c9753 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -20,8 +20,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// [Cmdlet(VerbsCommon.Find, "PSResource", - DefaultParameterSetName = ResourceNameParameterSet, - SupportsShouldProcess = true)] + DefaultParameterSetName = ResourceNameParameterSet)] [OutputType(typeof(PSResourceInfo), typeof(PSCommandResourceInfo))] public sealed class FindPSResource : PSCmdlet { diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 68ada6965..85e5c80d2 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.14.0 - 3.0.14 - 3.0.14 + 3.0.15.0 + 3.0.15 + 3.0.15 netstandard2.0 8.0 From 3971392e97ea206847fab7993b60c04d1318a030 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Tue, 26 Jul 2022 15:58:35 -0700 Subject: [PATCH 195/276] Fixes for use of IEnumerable and dependent module re-install issues (#728) * Remove unneeded IEnumerable interfaces * Add missing clean up * Fix always reinstall * Fix logic error * Style change * Minor clean up * Use count property --- src/code/FindHelper.cs | 184 +++++++++++++++++--------------- src/code/FindPSResource.cs | 35 +++--- src/code/GetHelper.cs | 38 +++++++ src/code/GetPSResource.cs | 6 +- src/code/InstallHelper.cs | 84 +++++++-------- src/code/PublishPSResource.cs | 16 ++- test/FindPSResource.Tests.ps1 | 2 +- test/UpdatePSResource.Tests.ps1 | 2 +- 8 files changed, 207 insertions(+), 160 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 916e5a793..97457d74d 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -9,18 +9,14 @@ using NuGet.Protocol.Core.Types; using NuGet.Versioning; using System; -using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; using System.Management.Automation; using System.Net; using System.Net.Http; -using System.Security; using System.Threading; -using Dbg = System.Diagnostics.Debug; - namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { /// @@ -70,7 +66,7 @@ public FindHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) #region Public methods - public IEnumerable FindByResourceName( + public List FindByResourceName( string[] name, ResourceType type, string version, @@ -87,13 +83,16 @@ public IEnumerable FindByResourceName( _credential = credential; _includeDependencies = includeDependencies; - Dbg.Assert(name.Length != 0, "Name length cannot be 0"); + List foundPackages = new List(); - _pkgsLeftToFind = name.ToList(); + if (name.Length == 0) + { + return foundPackages; + } - List repositoriesToSearch; + _pkgsLeftToFind = name.ToList(); - //determine if repository array of names of repositories input to be searched contains wildcard + // Error out if repository array of names to be searched contains wildcards. if (repository != null) { repository = Utils.ProcessNameWildcards(repository, out string[] errorMsgs, out _repositoryNameContainsWildcard); @@ -107,6 +106,8 @@ public IEnumerable FindByResourceName( } } + // Get repositories to search. + List repositoriesToSearch; try { repositoriesToSearch = RepositorySettings.Read(repository, out string[] errorList); @@ -126,11 +127,12 @@ public IEnumerable FindByResourceName( "ErrorLoadingRepositoryStoreFile", ErrorCategory.InvalidArgument, this)); - yield break; + + return foundPackages; } - // loop through repositoriesToSearch and if PSGallery or PoshTestGallery add its Scripts endpoint repo - // 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++) { @@ -185,9 +187,11 @@ public IEnumerable FindByResourceName( repositoryUri: repositoriesToSearch[i].Uri, repositoryCredentialInfo: repositoriesToSearch[i].CredentialInfo)) { - yield return pkg; + foundPackages.Add(pkg); } } + + return foundPackages; } #endregion @@ -204,7 +208,7 @@ private IEnumerable SearchFromRepository( SearchFilter filter; SourceCacheContext context; - // file based Uri scheme + // File based Uri scheme. if (repositoryUri.Scheme == Uri.UriSchemeFile) { FindLocalPackagesResourceV2 localResource = new FindLocalPackagesResourceV2(repositoryUri.ToString()); @@ -225,16 +229,16 @@ private IEnumerable SearchFromRepository( yield break; } - // check if ADOFeed- for which searching for Name with wildcard has a different logic flow + // Check if ADOFeed- for which searching for Name with wildcard has a different logic flow. if (repositoryUri.ToString().Contains("pkgs.")) { _isADOFeedRepository = true; } - // HTTP, HTTPS, FTP Uri schemes (only other Uri schemes allowed by RepositorySettings.Read() API) + // HTTP, HTTPS, FTP Uri schemes (only other Uri schemes allowed by RepositorySettings.Read() API). PackageSource source = new PackageSource(repositoryUri.ToString()); - // Explicitly passed in Credential takes precedence over repository CredentialInfo + // Explicitly passed in Credential takes precedence over repository CredentialInfo. if (_credential != null) { string password = new NetworkCredential(string.Empty, _credential.Password).Password; @@ -253,7 +257,7 @@ private IEnumerable SearchFromRepository( _cmdletPassedIn.WriteVerbose("credential successfully read from vault and set for repository: " + repositoryName); } - // GetCoreV3() API is able to handle V2 and V3 repository endpoints + // GetCoreV3() API is able to handle V2 and V3 repository endpoints. var provider = FactoryExtensionsV3.GetCoreV3(NuGet.Protocol.Core.Types.Repository.Provider); SourceRepository repository = new SourceRepository(source, provider); resourceSearch = null; @@ -351,7 +355,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( if (!pkgName.Contains("*")) { // case: searching for specific package name i.e "Carbon" - IEnumerable retrievedPkgs = null; + IEnumerable retrievedPkgs; try { // GetMetadataAsync() API returns all versions for a specific non-wildcard package name @@ -372,23 +376,24 @@ private IEnumerable FindFromPackageSourceSearchAPI( { _cmdletPassedIn.WriteWarning(String.Format("Error receiving package from PSGallery. To check if this is due to a PSGallery outage check: https://aka.ms/psgallerystatus . Specific error: {0}", ex.Message)); } + + yield break; } catch (Exception e) { Utils.WriteVerboseOnCmdlet(_cmdletPassedIn, "FindHelper MetadataAsync: error receiving package: " + e.Message); + yield break; } - if (retrievedPkgs == null || retrievedPkgs.Count() == 0) + // Iterate through any packages found in repository. + bool packagesFound = false; + foreach (var pkg in retrievedPkgs) { - _cmdletPassedIn.WriteVerbose(string.Format("'{0}' could not be found in repository '{1}'", pkgName, repositoryName)); - yield break; + foundPackagesMetadata.Add(pkg); + if (!packagesFound) { packagesFound = true; } } - foundPackagesMetadata.AddRange(retrievedPkgs.ToList()); - - // _pkgsLeftToFind.Remove(pkgName); - - if (!_repositoryNameContainsWildcard) + if (packagesFound && !_repositoryNameContainsWildcard) { _pkgsLeftToFind.Remove(pkgName); } @@ -404,8 +409,9 @@ private IEnumerable FindFromPackageSourceSearchAPI( this)); yield break; } - // case: searching for name containing wildcard i.e "Carbon.*" - IEnumerable wildcardPkgs = null; + + // Case: searching for name containing wildcard i.e "Carbon.*". + List wildcardPkgs; try { // SearchAsync() API returns the latest version only for all packages that match the wild-card name @@ -415,11 +421,13 @@ private IEnumerable FindFromPackageSourceSearchAPI( skip: 0, take: SearchAsyncMaxTake, log: NullLogger.Instance, - cancellationToken: _cancellationToken).GetAwaiter().GetResult(); - if (wildcardPkgs.Count() > SearchAsyncMaxReturned) + cancellationToken: _cancellationToken).GetAwaiter().GetResult().ToList(); + + if (wildcardPkgs.Count > SearchAsyncMaxReturned) { - // get the rest of the packages - wildcardPkgs = wildcardPkgs.Concat(pkgSearchResource.SearchAsync( + // Get the rest of the packages. + wildcardPkgs.AddRange( + pkgSearchResource.SearchAsync( searchTerm: pkgName, filters: searchFilter, skip: SearchAsyncMaxTake, @@ -447,12 +455,13 @@ private IEnumerable FindFromPackageSourceSearchAPI( // filter additionally because NuGet wildcard search API returns more than we need // perhaps validate in Find-PSResource, and use debugassert here? WildcardPattern nameWildcardPattern = new WildcardPattern(pkgName, WildcardOptions.IgnoreCase); - foundPackagesMetadata.AddRange(wildcardPkgs.Where( - p => nameWildcardPattern.IsMatch(p.Identity.Id)).ToList()); + foundPackagesMetadata.AddRange( + wildcardPkgs.Where( + p => nameWildcardPattern.IsMatch(p.Identity.Id))); if (!_repositoryNameContainsWildcard) { - // if the Script Uri endpoint still needs to be searched, don't remove the wildcard name from _pkgsLeftToFind + // 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) @@ -462,7 +471,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( if (String.Equals(repositoryName, _psGalleryRepoName, StringComparison.InvariantCultureIgnoreCase) || String.Equals(repositoryName, _poshTestGalleryRepoName, StringComparison.InvariantCultureIgnoreCase)) { - if (foundPackagesMetadata.Any() && _type != ResourceType.None) + if (foundPackagesMetadata.Count > 0 && _type != ResourceType.None) { _pkgsLeftToFind.Remove(pkgName); } @@ -477,7 +486,7 @@ private IEnumerable FindFromPackageSourceSearchAPI( if (foundPackagesMetadata.Count == 0) { // no need to attempt to filter further - _cmdletPassedIn.WriteVerbose("no packages found"); + _cmdletPassedIn.WriteVerbose($"No packages found in repository: {repositoryName}."); yield break; } @@ -605,72 +614,75 @@ SourceCacheContext sourceCacheContext { foreach(var dep in currentPkg.Dependencies) { - IEnumerable depPkgs = packageMetadataResource.GetMetadataAsync( + List depPkgs = packageMetadataResource.GetMetadataAsync( packageId: dep.Name, includePrerelease: _prerelease, includeUnlisted: false, sourceCacheContext: sourceCacheContext, log: NullLogger.Instance, - token: _cancellationToken).GetAwaiter().GetResult(); + token: _cancellationToken).GetAwaiter().GetResult().ToList(); - if (depPkgs.Count() > 0) + if (depPkgs.Count is 0) { - if (dep.VersionRange == VersionRange.All) - { - // return latest version - IPackageSearchMetadata depPkgLatestVersion = depPkgs.First(); - - if (!PSResourceInfo.TryConvert( - metadataToParse: depPkgLatestVersion, - psGetInfo: out PSResourceInfo depPSResourceInfoPkg, - repositoryName: currentPkg.Repository, - type: currentPkg.Type, - errorMsg: out string errorMsg)) - { - _cmdletPassedIn.WriteError(new ErrorRecord( - new PSInvalidOperationException("Error parsing dependency IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), - "DependencyIPackageSearchMetadataToPSResourceInfoParsingError", - ErrorCategory.InvalidResult, - this)); - } + continue; + } - thoseToAdd.Add(depPSResourceInfoPkg); - FindDependencyPackagesHelper(depPSResourceInfoPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); - } - else + if (dep.VersionRange == VersionRange.All) + { + // Return latest version, which is first in the list. + IPackageSearchMetadata depPkgLatestVersion = depPkgs[0]; + + if (!PSResourceInfo.TryConvert( + metadataToParse: depPkgLatestVersion, + psGetInfo: out PSResourceInfo depPSResourceInfoPkg, + repositoryName: currentPkg.Repository, + type: currentPkg.Type, + errorMsg: out string errorMsg)) { - List pkgVersionsInRange = depPkgs.Where( - p => dep.VersionRange.Satisfies( - p.Identity.Version, VersionComparer.VersionRelease)).OrderByDescending( - p => p.Identity.Version).ToList(); + _cmdletPassedIn.WriteError(new ErrorRecord( + new PSInvalidOperationException("Error parsing dependency IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), + "DependencyIPackageSearchMetadataToPSResourceInfoParsingError", + ErrorCategory.InvalidResult, + this)); + } + + thoseToAdd.Add(depPSResourceInfoPkg); + FindDependencyPackagesHelper(depPSResourceInfoPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); + } + else + { + List pkgVersionsInRange = depPkgs.Where( + p => dep.VersionRange.Satisfies( + p.Identity.Version, VersionComparer.VersionRelease)).OrderByDescending( + p => p.Identity.Version).ToList(); - if (pkgVersionsInRange.Count() > 0) + if (pkgVersionsInRange.Count > 0) + { + IPackageSearchMetadata depPkgLatestInRange = pkgVersionsInRange[0]; + if (depPkgLatestInRange != null) { - IPackageSearchMetadata depPkgLatestInRange = pkgVersionsInRange.First(); - if (depPkgLatestInRange != null) + if (!PSResourceInfo.TryConvert( + metadataToParse: depPkgLatestInRange, + psGetInfo: out PSResourceInfo depPSResourceInfoPkg, + repositoryName: currentPkg.Repository, + type: currentPkg.Type, + errorMsg: out string errorMsg)) { - if (!PSResourceInfo.TryConvert( - metadataToParse: depPkgLatestInRange, - psGetInfo: out PSResourceInfo depPSResourceInfoPkg, - repositoryName: currentPkg.Repository, - type: currentPkg.Type, - errorMsg: out string errorMsg)) - { - _cmdletPassedIn.WriteError(new ErrorRecord( - new PSInvalidOperationException("Error parsing dependency range IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), - "DependencyRangeIPackageSearchMetadataToPSResourceInfoParsingError", - ErrorCategory.InvalidResult, - this)); - } - - thoseToAdd.Add(depPSResourceInfoPkg); - FindDependencyPackagesHelper(depPSResourceInfoPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); + _cmdletPassedIn.WriteError(new ErrorRecord( + new PSInvalidOperationException("Error parsing dependency range IPackageSearchMetadata to PSResourceInfo with message: " + errorMsg), + "DependencyRangeIPackageSearchMetadataToPSResourceInfoParsingError", + ErrorCategory.InvalidResult, + this)); } + + thoseToAdd.Add(depPSResourceInfoPkg); + FindDependencyPackagesHelper(depPSResourceInfoPkg, thoseToAdd, packageMetadataResource, sourceCacheContext); } } } } } + #endregion } } diff --git a/src/code/FindPSResource.cs b/src/code/FindPSResource.cs index 6d01c9753..41644153a 100644 --- a/src/code/FindPSResource.cs +++ b/src/code/FindPSResource.cs @@ -216,24 +216,19 @@ private void ProcessResourceNameParameterSet() return; } - List foundPackages = new List(); - - foreach (PSResourceInfo package in _findHelper.FindByResourceName( - Name, - Type, - Version, - Prerelease, - Tag, - Repository, - Credential, - IncludeDependencies)) - { - foundPackages.Add(package); - } + List foundPackages = _findHelper.FindByResourceName( + name: Name, + type: Type, + version: Version, + prerelease: Prerelease, + tag: Tag, + repository: Repository, + credential: Credential, + includeDependencies: IncludeDependencies); foreach (var uniquePackageVersion in foundPackages.GroupBy( m => new {m.Name, m.Version, m.Repository}).Select( - group => group.First()).ToList()) + group => group.First())) { WriteObject(uniquePackageVersion); } @@ -291,21 +286,15 @@ private void ProcessCommandOrDscParameterSet(bool isSearchingForCommands) moduleNamesToSearch = new string[] {"*"}; } - List foundPackages = new List(); - - foreach (PSResourceInfo package in _findHelper.FindByResourceName( + List foundPackages = _findHelper.FindByResourceName( name: moduleNamesToSearch, - // provide type so Scripts endpoint for PSGallery won't be searched type: isSearchingForCommands? ResourceType.Command : ResourceType.DscResource, version: Version, prerelease: Prerelease, tag: Tag, repository: Repository, credential: Credential, - includeDependencies: IncludeDependencies)) - { - foundPackages.Add(package); - } + includeDependencies: IncludeDependencies); // if a single package contains multiple commands we are interested in, return a unique entry for each: // Command1 , PackageA diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index c96586d40..49b24bc9b 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -37,6 +37,44 @@ public GetHelper(PSCmdlet cmdletPassedIn) #region Public methods + /// + /// Retrieves package paths from provided search paths for installed packages + /// by name *and* version. + /// + public IEnumerable GetInstalledPackages( + IEnumerable pkgs, + List pathsToSearch) + { + foreach (var pkg in pkgs) + { + // Filter on specific version. + var nugetVersion = new NuGetVersion(pkg.Version); + var pkgVersionRange = new VersionRange( + minVersion: nugetVersion, + includeMinVersion: true, + maxVersion: nugetVersion, + includeMaxVersion: true); + + // Search by package name. + var foundPkgPaths = FilterPkgPathsByName( + names: new string[] { pkg.Name }, + pathsToSearch); + + // Filter by package version. + foreach (var pkgPath in FilterPkgPathsByVersion( + versionRange: pkgVersionRange, + dirsToSearch: foundPkgPaths, + selectPrereleaseOnly: false)) + { + PSResourceInfo returnPkg = OutputPackageObject(pkgPath, _scriptDictionary); + if (returnPkg != null) + { + yield return returnPkg; + } + } + } + } + public IEnumerable GetPackagesFromPath( string[] name, VersionRange versionRange, diff --git a/src/code/GetPSResource.cs b/src/code/GetPSResource.cs index 0db720a5f..453555d53 100644 --- a/src/code/GetPSResource.cs +++ b/src/code/GetPSResource.cs @@ -127,15 +127,15 @@ protected override void ProcessRecord() this)); } - // this catches the case where Name wasn't passed in as null or empty, - // but after filtering out unsupported wildcard names in BeginProcessing() there are no elements left in Name + // This catches the case where Name wasn't passed in as null or empty, + // but after filtering out unsupported wildcard names in BeginProcessing() there are no elements left in Name. if (namesToSearch.Length == 0) { return; } + // SelectPrereleaseOnly is false because we want both stable and prerelease versions all the time.. GetHelper getHelper = new GetHelper(this); - // selectPrereleaseOnly is false because we want both stable and prerelease versions all the time. foreach (PSResourceInfo pkg in getHelper.GetPackagesFromPath( name: namesToSearch, versionRange: _versionRange, diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 35fea684c..515cdd762 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using Microsoft.PowerShell.Commands; using Microsoft.PowerShell.PowerShellGet.UtilClasses; using MoreLinq.Extensions; using NuGet.Common; @@ -15,7 +14,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Linq; @@ -192,20 +190,19 @@ private List ProcessRepositories( var isLocalRepo = repo.Uri.AbsoluteUri.StartsWith(Uri.UriSchemeFile + Uri.SchemeDelimiter, StringComparison.OrdinalIgnoreCase); // Finds parent packages and dependencies - IEnumerable pkgsFromRepoToInstall = findHelper.FindByResourceName( + List pkgsFromRepoToInstall = findHelper.FindByResourceName( name: _pkgNamesToInstall.ToArray(), type: ResourceType.None, - version: _versionRange != null ? _versionRange.OriginalString : null, + version: _versionRange?.OriginalString, prerelease: _prerelease, tag: null, repository: new string[] { repoName }, credential: credential, includeDependencies: !skipDependencyCheck); - if (!pkgsFromRepoToInstall.Any()) + if (pkgsFromRepoToInstall.Count == 0) { _cmdletPassedIn.WriteVerbose(string.Format("None of the specified resources were found in the '{0}' repository.", repoName)); - // Check in the next repository continue; } @@ -225,7 +222,7 @@ private List ProcessRepositories( pkgsFromRepoToInstall = FilterByInstalledPkgs(pkgsFromRepoToInstall); } - if (!pkgsFromRepoToInstall.Any()) + if (pkgsFromRepoToInstall.Count is 0) { continue; } @@ -261,58 +258,61 @@ private List ProcessRepositories( } // Check if any of the pkg versions are already installed, if they are we'll remove them from the list of packages to install - private IEnumerable FilterByInstalledPkgs(IEnumerable packages) + private List FilterByInstalledPkgs(List packages) { - // Create list of installation paths to search. - List _pathsToSearch = new List(); - // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable) - // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations + // Package install paths. + // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable). + // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations. // e.g.: // ./InstallPackagePath1/PackageA // ./InstallPackagePath1/PackageB // ./InstallPackagePath2/PackageC // ./InstallPackagePath3/PackageD - foreach (var path in _pathsToInstallPkg) - { - _pathsToSearch.AddRange(Utils.GetSubDirectories(path)); - } - var filteredPackages = new Dictionary(); - foreach (var pkg in packages) + // Get currently installed packages. + var getHelper = new GetHelper(_cmdletPassedIn); + var installedPackageNames = new HashSet(StringComparer.CurrentCultureIgnoreCase); + foreach (var installedPkg in getHelper.GetInstalledPackages( + pkgs: packages, + pathsToSearch: _pathsToSearch)) { - filteredPackages.Add(pkg.Name, pkg); + installedPackageNames.Add(installedPkg.Name); } - GetHelper getHelper = new GetHelper(_cmdletPassedIn); - // Get currently installed packages. - // selectPrereleaseOnly is false because even if Prerelease is true we want to include both stable and prerelease, never select prerelease only. - IEnumerable pkgsAlreadyInstalled = getHelper.GetPackagesFromPath( - name: filteredPackages.Keys.ToArray(), - versionRange: _versionRange, - pathsToSearch: _pathsToSearch, - selectPrereleaseOnly: false); - if (!pkgsAlreadyInstalled.Any()) + if (installedPackageNames.Count is 0) { return packages; } - // Remove from list package versions that are already installed. - foreach (PSResourceInfo pkg in pkgsAlreadyInstalled) + // Return only packages that are not already installed. + var filteredPackages = new List(); + foreach (var pkg in packages) { - _cmdletPassedIn.WriteWarning( - string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", - pkg.Name, - pkg.Version)); + if (!installedPackageNames.Contains(pkg.Name)) + { + // Add packages that still need to be installed. + filteredPackages.Add(pkg); + } + else + { + // Remove from tracking list of packages to install. + _cmdletPassedIn.WriteWarning( + string.Format("Resource '{0}' with version '{1}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter", + pkg.Name, + pkg.Version)); - filteredPackages.Remove(pkg.Name); - _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + _pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase)); + } } - return filteredPackages.Values.ToArray(); + return filteredPackages; } + /// + /// Install provided list of packages, which include Dependent packages if requested. + /// private List InstallPackage( - IEnumerable pkgsToInstall, // those found to be required to be installed (includes Dependency packages as well) + List pkgsToInstall, string repoName, string repoUri, PSCredentialInfo repoCredentialInfo, @@ -320,13 +320,13 @@ private List InstallPackage( bool isLocalRepo) { List pkgsSuccessfullyInstalled = new List(); - int totalPkgs = pkgsToInstall.Count(); + int totalPkgs = pkgsToInstall.Count; // Counters for tracking current package out of total - int totalInstalledPkgCount = 0; + int currentInstalledPkgCount = 0; foreach (PSResourceInfo pkg in pkgsToInstall) { - totalInstalledPkgCount++; + currentInstalledPkgCount++; var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try { @@ -344,7 +344,7 @@ private List InstallPackage( if (!_quiet) { int activityId = 0; - int percentComplete = ((totalInstalledPkgCount * 100) / totalPkgs); + int percentComplete = ((currentInstalledPkgCount * 100) / totalPkgs); string activity = string.Format("Installing {0}...", pkg.Name); string statusDescription = string.Format("{0}% Complete", percentComplete); _cmdletPassedIn.WriteProgress( diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 752255eae..2854da350 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -236,7 +236,6 @@ protected override void EndProcessing() try { Utils.ValidateModuleManifest(resourceFilePath, out errorMsgs); - } finally { if (errorMsgs.Length > 0) @@ -885,9 +884,17 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam FindHelper findHelper = new FindHelper(_cancellationToken, this); bool depPrerelease = depVersion.Contains("-"); - var repository = new[] { repositoryName }; - var dependencyFound = findHelper.FindByResourceName(depName, ResourceType.Module, depVersion, depPrerelease, null, repository, Credential, false); - if (dependencyFound == null || !dependencyFound.Any()) + var foundDependencies = findHelper.FindByResourceName( + name: depName, + type: ResourceType.Module, + version: depVersion, + prerelease: depPrerelease, + tag: null, + repository: new[] { repositoryName }, + credential: Credential, + includeDependencies: false); + + if (foundDependencies.Count is 0) { var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryName); var ex = new ArgumentException(message); @@ -897,6 +904,7 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam return false; } } + return true; } diff --git a/test/FindPSResource.Tests.ps1 b/test/FindPSResource.Tests.ps1 index 9d946b33b..53449b2d9 100644 --- a/test/FindPSResource.Tests.ps1 +++ b/test/FindPSResource.Tests.ps1 @@ -122,7 +122,7 @@ Describe 'Test Find-PSResource for Module' { ) { param($Version, $Description) - $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName + $res = Find-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName 2>$null $res | Should -BeNullOrEmpty } diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 0bbbdc2da..901a5a0bc 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -123,7 +123,7 @@ Describe 'Test Update-PSResource' { param($Version, $Description) Install-PSResource -Name $testModuleName -Version "1.0.0.0" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $testModuleName -Version $Version -Repository $PSGalleryName -TrustRepository 2>$null $res = Get-PSResource -Name $testModuleName $isPkgUpdated = $false From f82cda767b90b24559875ac95c60711e65f73d70 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 27 Jul 2022 15:11:58 -0400 Subject: [PATCH 196/276] Update NuGet.Packaging to version 6.2.1 (#733) * updat NuGet.Packaging to version 6.2.1 which depends on Newtonsoft 13.0.1 or higher * update other NuGet package versions --- src/code/PowerShellGet.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 85e5c80d2..8d9d749ea 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -15,12 +15,12 @@ - - - - - - + + + + + + From 9b4eaffb85bc3b453c18ef0bf17371e9009271da Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 27 Jul 2022 15:31:15 -0400 Subject: [PATCH 197/276] Update pkg version and notes for release (#734) --- .ci/ci_release.yml | 2 +- CHANGELOG.md | 5 +++++ src/PowerShellGet.psd1 | 9 +++++++-- src/code/PowerShellGet.csproj | 6 +++--- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 46a67f715..b5a3f326c 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -244,7 +244,7 @@ stages: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' PackageName: 'PowerShellGet' - PackageVersion: '3.0.15' + PackageVersion: '3.0.16' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' diff --git a/CHANGELOG.md b/CHANGELOG.md index 80a5829e8..ed4333725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 3.0.16-beta16 + +### Bug Fixes +- Update NuGet dependency packages for security vulnerabilities (#733) + ## 3.0.15-beta15 ### New Features diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index ec1415ddb..6c9289575 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.15' + ModuleVersion = '3.0.16' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -34,7 +34,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta15' + Prerelease = 'beta16' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -44,6 +44,11 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 3.0.16-beta16 + +### Bug Fixes +- Update NuGet dependency packages for security vulnerabilities (#733) + ## 3.0.15-beta15 ### New Features diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 8d9d749ea..5f6856f3b 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.15.0 - 3.0.15 - 3.0.15 + 3.0.16.0 + 3.0.16 + 3.0.16 netstandard2.0 8.0 From ca5d5582d813bdde07999479a5442f6bfd4497c2 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:53:33 +0000 Subject: [PATCH 198/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index b5a3f326c..dd69322c5 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -238,6 +238,17 @@ stages: displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + - pwsh | + $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" + $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" + + $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" + + Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose + Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose + + displayName: Copy Notice and License files. + - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo parameters: From 9a1721268e969ff929df9f18140038fa3794d32a Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:54:46 +0000 Subject: [PATCH 199/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index dd69322c5..35e2f8ef1 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -248,6 +248,7 @@ stages: Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose displayName: Copy Notice and License files. + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From abe899eda5e51b3cd6c45ed9af69872cb9f94dbb Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:55:41 +0000 Subject: [PATCH 200/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 35e2f8ef1..835122159 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -246,7 +246,6 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) From cae2a9bc28d191b5bb8ef6c0d067c9a9c27548ad Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:56:24 +0000 Subject: [PATCH 201/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 835122159..6c4a9d072 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -246,7 +246,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. + displayName: Copy Notice and License files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: @@ -263,7 +263,7 @@ stages: $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force - # + $config = Get-PSPackageProjectConfiguration $artifactName = "$($config.ModuleName)" if ($env:SkipSigning -eq 'True') From dd255adf1fcc9e8facb5344580c326f9821b82fc Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:11 +0000 Subject: [PATCH 202/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 6c4a9d072..88f391cd6 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -246,8 +246,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + displayName: Copy notice and license files - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 22e24c65a952179abb0c26ad771ebb5f42906401 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:59 +0000 Subject: [PATCH 203/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 88f391cd6..b1333c777 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -235,10 +235,6 @@ stages: } } } - displayName: Copy already properly signed third party files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - - pwsh | $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" @@ -246,7 +242,8 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy notice and license files + displayName: Copy already properly signed third party files + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From f81abc253e2710240507a60234d028e19bdc86ef Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 27 Jul 2022 16:15:18 -0700 Subject: [PATCH 204/276] Copy LICENSE and Notice.txt to build output path (#735) * Remove ShouldProcess in FindPSResource * Copy LICENSE and notice.txt to output path in yamls * Update .ci/ci_auto.yml Co-authored-by: Paul Higinbotham * Update .ci/ci_auto.yml Co-authored-by: Paul Higinbotham * Update .ci/ci_release.yml Co-authored-by: Paul Higinbotham * Update .ci/ci_release.yml Co-authored-by: Paul Higinbotham Co-authored-by: Paul Higinbotham --- .ci/ci_auto.yml | 4 ++++ .ci/ci_release.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.ci/ci_auto.yml b/.ci/ci_auto.yml index 78090b56d..603e9e525 100644 --- a/.ci/ci_auto.yml +++ b/.ci/ci_auto.yml @@ -233,6 +233,10 @@ stages: # en-US Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse + # Copy Notice.txt + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Notice.txt") -Dest $signOutPath + # Copy LICENSE + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "LICENSE") -Dest $signOutPath # NetStandard directory $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index b5a3f326c..94b00eb42 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -220,6 +220,10 @@ stages: # en-US Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "en-US") -Dest $signOutPath -Recurse + # Copy Notice.txt + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "Notice.txt") -Dest $signOutPath + # Copy LICENSE + Copy-Item -Path (Join-Path -Path $srcPath -ChildPath "LICENSE") -Dest $signOutPath # NetStandard directory $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" From b790c2e3f019d2d79bc8745d509222878e2af855 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:53:33 +0000 Subject: [PATCH 205/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 94b00eb42..4019750d5 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -242,6 +242,17 @@ stages: displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + - pwsh | + $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" + $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" + + $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" + + Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose + Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose + + displayName: Copy Notice and License files. + - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo parameters: From 8da460a2c5b11a820006a226f6127db3218bd72e Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:54:46 +0000 Subject: [PATCH 206/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 4019750d5..cde9a3071 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -252,6 +252,7 @@ stages: Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose displayName: Copy Notice and License files. + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 2fad52d0885a111f7e35eada338fc9f91c3fdbeb Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:55:41 +0000 Subject: [PATCH 207/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index cde9a3071..c62208590 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -250,7 +250,6 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) From e9bb3e2de2119ae595770f86db62afd401eb7b21 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:56:24 +0000 Subject: [PATCH 208/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index c62208590..9355d6909 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -250,7 +250,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. + displayName: Copy Notice and License files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: @@ -267,7 +267,7 @@ stages: $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force - # + $config = Get-PSPackageProjectConfiguration $artifactName = "$($config.ModuleName)" if ($env:SkipSigning -eq 'True') From 0c1f8108a22dbae511127e0cf70962c7bfe05a9f Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:11 +0000 Subject: [PATCH 209/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 9355d6909..4a3236642 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -250,8 +250,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + displayName: Copy notice and license files - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From abe6f93f732df85d569b51f24b340c6d9dcb0bcb Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:59 +0000 Subject: [PATCH 210/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 4a3236642..8aa38bbfc 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -239,10 +239,6 @@ stages: } } } - displayName: Copy already properly signed third party files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - - pwsh | $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" @@ -250,7 +246,8 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy notice and license files + displayName: Copy already properly signed third party files + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 5647287094099bd9b145054327b35471920839cc Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:53:33 +0000 Subject: [PATCH 211/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 94b00eb42..4019750d5 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -242,6 +242,17 @@ stages: displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + - pwsh | + $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" + $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" + + $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" + + Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose + Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose + + displayName: Copy Notice and License files. + - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo parameters: From 4bdcd95604a7e2da0e367caf1d7e847579ed0901 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:54:46 +0000 Subject: [PATCH 212/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 4019750d5..cde9a3071 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -252,6 +252,7 @@ stages: Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose displayName: Copy Notice and License files. + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From c8b85eaaee9a25af83ef62ed5c49a58677071d7e Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:55:41 +0000 Subject: [PATCH 213/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index cde9a3071..c62208590 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -250,7 +250,6 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) From 5bd969557b8388174af5bbd0865b97ce597ab511 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:56:24 +0000 Subject: [PATCH 214/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index c62208590..9355d6909 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -250,7 +250,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. + displayName: Copy Notice and License files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: @@ -267,7 +267,7 @@ stages: $modPath = Join-Path -Path $modulePath -ChildPath PSPackageProject Write-Verbose -Verbose "Importing PSPackageProject from: $modPath" Import-Module -Name $modPath -Force - # + $config = Get-PSPackageProjectConfiguration $artifactName = "$($config.ModuleName)" if ($env:SkipSigning -eq 'True') From ad5cd62b4ff03cd5bbe11768eadefcaa6c616c8c Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:11 +0000 Subject: [PATCH 215/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 9355d6909..4a3236642 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -250,8 +250,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + displayName: Copy notice and license files - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 277426e18a9251d5259e9c37127c27f9c4c60f41 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:59 +0000 Subject: [PATCH 216/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 4a3236642..8aa38bbfc 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -239,10 +239,6 @@ stages: } } } - displayName: Copy already properly signed third party files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - - pwsh | $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" @@ -250,7 +246,8 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy notice and license files + displayName: Copy already properly signed third party files + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 727d317f5600822ca024477afcfd063901c3e4ff Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:53:33 +0000 Subject: [PATCH 217/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 8aa38bbfc..37d43e317 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -249,6 +249,17 @@ stages: displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + - pwsh | + $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" + $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" + + $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" + + Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose + Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose + + displayName: Copy Notice and License files. + - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo parameters: From 5d6ece5dd55d164d62e2c96b59650ba9101302f5 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:54:46 +0000 Subject: [PATCH 218/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 37d43e317..47f4231d9 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -259,6 +259,7 @@ stages: Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose displayName: Copy Notice and License files. + condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 115916a6e6601401cd6c8df96284af727c61ea40 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:55:41 +0000 Subject: [PATCH 219/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 47f4231d9..b8ff2a82f 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -257,7 +257,6 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) From 1390a18f52fcec0ed04258ae15d7511c155fa4ab Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:56:24 +0000 Subject: [PATCH 220/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index b8ff2a82f..2c57bd0a8 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -257,7 +257,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files. + displayName: Copy Notice and License files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - ${{ if ne(variables.SkipSigning, 'True') }}: From ea2fe9f2b6f02fe71ae0e20bd27ab74333b4bc06 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:11 +0000 Subject: [PATCH 221/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 2c57bd0a8..1be3ada98 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -257,8 +257,7 @@ stages: Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy Notice and License files - condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) + displayName: Copy notice and license files - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo From 7bc06261a7e4effd2a2b56a867e48fa3ef84d0ab Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 27 Jul 2022 21:58:59 +0000 Subject: [PATCH 222/276] Update ci_release.yml for Azure Pipelines --- .ci/ci_release.yml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 1be3ada98..706572091 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -239,26 +239,9 @@ stages: } } } - $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" - $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" - - $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" - - Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose - Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) - - pwsh | - $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" - $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" - - $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" - - Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose - Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose - displayName: Copy notice and license files - - ${{ if ne(variables.SkipSigning, 'True') }}: - template: Sbom.yml@ComplianceRepo parameters: From 30ff560f37c65ac6eb9acd43870f5a8673e20839 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Wed, 27 Jul 2022 17:12:37 -0700 Subject: [PATCH 223/276] Remove unneeded copy (#736) --- .ci/ci_release.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 8aa38bbfc..706572091 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -239,13 +239,6 @@ stages: } } } - $noticeTxt = "$(signSrcPath)\PowerShellGet\Notice.txt" - $licenseTxt = "$(signSrcPath)\PowerShellGet\LICENSE" - - $netStandardSignedOutPath = Join-Path -Path $signOutPath -ChildPath "netstandard2.0" - - Copy-Item -Path $noticeTxt -Dest "$netStandardSignedOutPath\Notice.txt" -Force -Verbose - Copy-Item -Path $licenseTxt -Dest "$netStandardSignedOutPath\LICENSE" -Force -Verbose displayName: Copy already properly signed third party files condition: and(and(succeeded(), eq(variables['Build.Reason'], 'Manual')), ne(variables['SkipSigning'], 'True')) From d335be1ebddeb4eab6db92e045a1cd2c8c598bfe Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 28 Jul 2022 13:21:39 -0700 Subject: [PATCH 224/276] Add error message for failure to install after choosing not to trust repository (#712) --- src/code/InstallHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 515cdd762..d1b4962bb 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -155,6 +155,7 @@ private List ProcessRepositories( var findHelper = new FindHelper(_cancellationToken, _cmdletPassedIn); List allPkgsInstalled = new List(); + bool sourceTrusted = true; foreach (var repo in listOfRepositories) { @@ -166,7 +167,6 @@ private List ProcessRepositories( // Source is only trusted if it's set at the repository level to be trusted, -TrustRepository flag is true, -Force flag is true // OR the user issues trust interactively via console. - var sourceTrusted = true; if (repo.Trusted == false && !trustRepository && !_force) { _cmdletPassedIn.WriteVerbose("Checking if untrusted repository should be used"); @@ -246,9 +246,9 @@ private List ProcessRepositories( // At this only package names left were those which could not be found in registered repositories foreach (string pkgName in _pkgNamesToInstall) { - var message = String.Format("Package '{0}' with requested version range {1} could not be installed as it was not found in any registered repositories", - pkgName, - _versionRange.ToString()); + string message = !sourceTrusted ? $"Package '{pkgName}' with requested version range '{_versionRange.ToString()}' could not be found in any trusted repositories" : + $"Package '{pkgName}' with requested version range '{_versionRange.ToString()}' could not be installed as it was not found in any registered repositories"; + var ex = new ArgumentException(message); var ResourceNotFoundError = new ErrorRecord(ex, "ResourceNotFoundError", ErrorCategory.ObjectNotFound, null); _cmdletPassedIn.WriteError(ResourceNotFoundError); From d3b8043d76c6965008ad44d95ccdd90068871ea4 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 28 Jul 2022 13:22:17 -0700 Subject: [PATCH 225/276] Remove ShouldProcess from FindPSResource (#710) From b75c4c878e5780e2ec03a97f296534caa456405e Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 28 Jul 2022 13:23:06 -0700 Subject: [PATCH 226/276] Add OutputType attributes to Get-PSResource and Get-PSResourceRepository (#706) --- src/code/GetPSResource.cs | 1 + src/code/GetPSResourceRepository.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/code/GetPSResource.cs b/src/code/GetPSResource.cs index 453555d53..6a167eca1 100644 --- a/src/code/GetPSResource.cs +++ b/src/code/GetPSResource.cs @@ -14,6 +14,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// Returns a single resource or multiple resource. /// [Cmdlet(VerbsCommon.Get, "PSResource")] + [OutputType(typeof(PSResourceInfo))] public sealed class GetPSResource : PSCmdlet { #region Members diff --git a/src/code/GetPSResourceRepository.cs b/src/code/GetPSResourceRepository.cs index 54eaa8ecb..8000c5445 100644 --- a/src/code/GetPSResourceRepository.cs +++ b/src/code/GetPSResourceRepository.cs @@ -16,6 +16,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// It returns PSRepositoryInfo objects which describe each resource item found. /// [Cmdlet(VerbsCommon.Get, "PSResourceRepository")] + [OutputType(typeof(PSRepositoryInfo))] public sealed class GetPSResourceRepository : PSCmdlet { #region Parameters From f9331f143d3ec6eae5d40e478c89bb04dc6258e6 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 2 Aug 2022 16:34:17 -0700 Subject: [PATCH 227/276] Add PSModulePath paths when retrieving resource paths (#700) --- src/code/Utils.cs | 52 ++++++++++++++------------------ test/InstallPSResource.Tests.ps1 | 7 +++++ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 32292d87f..66beebdf5 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -614,16 +614,17 @@ public static string GetInstalledPackageName(string pkgPath) // expecting the full version module path // ex: ./PowerShell/Modules/TestModule/1.0.0 return new DirectoryInfo(pkgPath).Parent.Name; - } - - public static List GetAllResourcePaths( + } + + // Find all potential resource paths + public static List GetPathsFromEnvVarAndScope( PSCmdlet psCmdlet, - ScopeType? scope = null) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); + ScopeType? scope) + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, + out string programFilesPath); List resourcePaths = new List(); @@ -646,6 +647,15 @@ public static List GetAllResourcePaths( resourcePaths.Add(Path.Combine(programFilesPath, "Scripts")); } + return resourcePaths; + } + + public static List GetAllResourcePaths( + PSCmdlet psCmdlet, + ScopeType? scope = null) + { + List resourcePaths = GetPathsFromEnvVarAndScope(psCmdlet, scope); + // resourcePaths should now contain, eg: // ./PowerShell/Scripts // ./PowerShell/Modules @@ -692,26 +702,10 @@ public static List GetAllResourcePaths( // Find all potential installation paths given a scope public static List GetAllInstallationPaths( PSCmdlet psCmdlet, - ScopeType scope) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, - out string programFilesPath); - - // The default user scope is CurrentUser - var installationPaths = new List(); - if (scope == ScopeType.AllUsers) - { - installationPaths.Add(Path.Combine(programFilesPath, "Modules")); - installationPaths.Add(Path.Combine(programFilesPath, "Scripts")); - } - else - { - installationPaths.Add(Path.Combine(myDocumentsPath, "Modules")); - installationPaths.Add(Path.Combine(myDocumentsPath, "Scripts")); - } - + ScopeType? scope) + { + List installationPaths = GetPathsFromEnvVarAndScope(psCmdlet, scope); + installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); installationPaths.ForEach(dir => psCmdlet.WriteVerbose(string.Format("All paths to search: '{0}'", dir))); diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index e2666efb0..bef8111ae 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -173,6 +173,13 @@ Describe 'Test Install-PSResource for Module' { $pkg.Version | Should -Be "5.0.0.0" } + It "Install resource under specified in PSModulePath" { + Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Name | Should -Be $testModuleName + ($env:PSModulePath).Contains($pkg.InstalledLocation) + } + # Windows only It "Install resource under CurrentUser scope - Windows only" -Skip:(!(Get-IsWindows)) { Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope CurrentUser From 767cb52b4c36ca8937ddc06bef0318d28b4035dd Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 2 Aug 2022 16:35:21 -0700 Subject: [PATCH 228/276] Remove .nupkg.metadata file (#738) --- src/code/InstallHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index d1b4962bb..8d2e9e4db 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -774,7 +774,7 @@ private void DeleteExtraneousFiles(PackageIdentity pkgIdentity, string dirNameVe var nupkgSHAToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.sha512"); var nuspecToDelete = Path.Combine(dirNameVersion, pkgIdentity.Id + ".nuspec"); var nupkgToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg"); - var nupkgMetadataToDelete = Path.Combine(dirNameVersion, pkgIdString + ".nupkg.metadata"); + var nupkgMetadataToDelete = Path.Combine(dirNameVersion, ".nupkg.metadata"); var contentTypesToDelete = Path.Combine(dirNameVersion, "[Content_Types].xml"); var relsDirToDelete = Path.Combine(dirNameVersion, "_rels"); var packageDirToDelete = Path.Combine(dirNameVersion, "package"); From b49a6c5b8d6c97403915c3ceef8c08077bb89dca Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 2 Aug 2022 16:36:45 -0700 Subject: [PATCH 229/276] Change "IncludeXML" to "IncludeXml" (#739) --- help/Save-PSResource.md | 8 ++++---- help/en-US/PowerShellGet.dll-Help.xml | 6 +++--- src/code/InstallHelper.cs | 12 ++++++------ src/code/InstallPSResource.cs | 2 +- src/code/SavePSResource.cs | 4 ++-- src/code/UpdatePSResource.cs | 2 +- test/SavePSResource.Tests.ps1 | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index d8c1e30e3..0d80b2298 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -15,13 +15,13 @@ Saves resources (modules and scripts) from a registered repository onto the mach ### NameParameterSet ``` Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] + [-Credential ] [-AsNupkg] [-IncludeXml] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet ``` Save-PSResource [-InputObject] [-Credential ] [-AsNupkg] - [-IncludeXML] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] + [-IncludeXml] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -50,7 +50,7 @@ Saves the Az module as a .nupkg file ### Example 4 ```powershell -PS C:\> Save-PSResource Az -IncludeXML +PS C:\> Save-PSResource Az -IncludeXml ``` Saves the Az module and includes the PowerShellGet XML metadata @@ -155,7 +155,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -IncludeXML +### -IncludeXml Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). ```yaml diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 6eb948e70..f251ef402 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -2406,7 +2406,7 @@ PS C:\> Get-PSResourceRepository False - IncludeXML + IncludeXml Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). @@ -2594,7 +2594,7 @@ PS C:\> Get-PSResourceRepository False - IncludeXML + IncludeXml Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). @@ -2745,7 +2745,7 @@ PS C:\> Get-PSResourceRepository -------------------------- Example 4 -------------------------- - PS C:\> Save-PSResource Az -IncludeXML + PS C:\> Save-PSResource Az -IncludeXml Saves the Az module and includes the PowerShellGet XML metadata diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 8d2e9e4db..75f6d54f2 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -47,7 +47,7 @@ internal class InstallHelper : PSCmdlet private bool _trustRepository; private PSCredential _credential; private bool _asNupkg; - private bool _includeXML; + private bool _includeXml; private bool _noClobber; private bool _authenticodeCheck; private bool _savePkg; @@ -78,14 +78,14 @@ public List InstallPackages( bool noClobber, PSCredential credential, bool asNupkg, - bool includeXML, + bool includeXml, bool skipDependencyCheck, bool authenticodeCheck, bool savePkg, List pathsToInstallPkg) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXML '{10}'; SavePackage '{11}'", + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXml '{10}'; SavePackage '{11}'", string.Join(",", names), versionRange != null ? (versionRange.OriginalString != null ? versionRange.OriginalString : string.Empty) : string.Empty, prerelease.ToString(), @@ -96,7 +96,7 @@ public List InstallPackages( trustRepository.ToString(), noClobber.ToString(), asNupkg.ToString(), - includeXML.ToString(), + includeXml.ToString(), savePkg.ToString())); _versionRange = versionRange; @@ -110,7 +110,7 @@ public List InstallPackages( _noClobber = noClobber; _credential = credential; _asNupkg = asNupkg; - _includeXML = includeXML; + _includeXml = includeXml; _savePkg = savePkg; _pathsToInstallPkg = pathsToInstallPkg; @@ -557,7 +557,7 @@ private List InstallPackage( // Delete the extra nupkg related files that are not needed and not part of the module/script DeleteExtraneousFiles(pkgIdentity, tempDirNameVersion); - if (_includeXML) + if (_includeXml) { CreateMetadataXMLFile(tempDirNameVersion, installPath, pkg, isModule); } diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index cb9bb3510..4149a2ba5 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -524,7 +524,7 @@ private void ProcessInstallHelper(string[] pkgNames, VersionRange pkgVersion, bo noClobber: NoClobber, credential: pkgCredential, asNupkg: false, - includeXML: true, + includeXml: true, skipDependencyCheck: SkipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: false, diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 73b6d1c19..2fa8f0480 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -76,7 +76,7 @@ public sealed class SavePSResource : PSCmdlet /// Saves the metadata XML file with the resource /// [Parameter] - public SwitchParameter IncludeXML { get; set; } + public SwitchParameter IncludeXml { get; set; } /// /// The destination where the resource is to be installed. Works for all resource types. @@ -264,7 +264,7 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p credential: Credential, noClobber: false, asNupkg: AsNupkg, - includeXML: IncludeXML, + includeXml: IncludeXml, skipDependencyCheck: SkipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: true, diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 5ca79d529..bce9ed295 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -183,7 +183,7 @@ protected override void ProcessRecord() credential: Credential, noClobber: false, asNupkg: false, - includeXML: true, + includeXml: true, skipDependencyCheck: SkipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: false, diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index b9ddac47d..2d5e2e27f 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -217,7 +217,7 @@ Describe 'Test Save-PSResource for PSResources' { } It "Save module and include XML metadata file" { - Save-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -Path $SaveDir -IncludeXML -TrustRepository + Save-PSResource -Name $testModuleName -Version "1.0.0" -Repository $PSGalleryName -Path $SaveDir -IncludeXml -TrustRepository $pkgDir = Get-ChildItem -Path $SaveDir | Where-Object Name -eq $testModuleName $pkgDir | Should -Not -BeNullOrEmpty $pkgDirVersion = Get-ChildItem -Path $pkgDir.FullName From b2b2528c3abdc2aabd8eea8aeb10b081cc3de5d1 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 4 Aug 2022 17:26:06 -0400 Subject: [PATCH 230/276] Cannot assume PSScriptInfo metadata will have empty lines in between (#744) * for PSScriptInfo metadata not assume first line will be empty line and can be ignored * add test scripts without empty lines --- src/code/PSScriptMetadata.cs | 2 +- test/TestPSScriptFileInfo.Tests.ps1 | 14 +++++++++++ ...tWithoutEmptyLinesBetweenCommentBlocks.ps1 | 24 +++++++++++++++++++ .../ScriptWithoutEmptyLinesInMetadata.ps1 | 23 ++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/testFiles/testScripts/ScriptWithoutEmptyLinesBetweenCommentBlocks.ps1 create mode 100644 test/testFiles/testScripts/ScriptWithoutEmptyLinesInMetadata.ps1 diff --git a/src/code/PSScriptMetadata.cs b/src/code/PSScriptMetadata.cs index f5cadb1ed..8ce8d0360 100644 --- a/src/code/PSScriptMetadata.cs +++ b/src/code/PSScriptMetadata.cs @@ -254,7 +254,7 @@ value continued string keyName = ""; string value = ""; - for (int i = 1; i < commentLines.Length; i++) + for (int i = 0; i < commentLines.Length; i++) { string line = commentLines[i]; diff --git a/test/TestPSScriptFileInfo.Tests.ps1 b/test/TestPSScriptFileInfo.Tests.ps1 index 30adae47b..eb1079c22 100644 --- a/test/TestPSScriptFileInfo.Tests.ps1 +++ b/test/TestPSScriptFileInfo.Tests.ps1 @@ -57,4 +57,18 @@ Describe "Test Test-PSScriptFileInfo" { Test-PSScriptFileInfo $scriptFilePath | Should -Be $false } + + It "determine script without empty lines in PSScriptInfo comment content is valid" { + $scriptName = "ScriptWithoutEmptyLinesInMetadata.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $true + } + + It "determine script without empty lines between comment blocks is valid" { + $scriptName = "ScriptWithoutEmptyLinesBetweenCommentBlocks.ps1" + $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName + + Test-PSScriptFileInfo $scriptFilePath | Should -Be $true + } } diff --git a/test/testFiles/testScripts/ScriptWithoutEmptyLinesBetweenCommentBlocks.ps1 b/test/testFiles/testScripts/ScriptWithoutEmptyLinesBetweenCommentBlocks.ps1 new file mode 100644 index 000000000..8d8d2aa88 --- /dev/null +++ b/test/testFiles/testScripts/ScriptWithoutEmptyLinesBetweenCommentBlocks.ps1 @@ -0,0 +1,24 @@ + +<#PSScriptInfo +.VERSION 1.0 +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd +.AUTHOR annavied +.COMPANYNAME +.COPYRIGHT +.TAGS +.LICENSEURI +.PROJECTURI +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES +.PRIVATEDATA +#> +<# + +.DESCRIPTION + this is a test for a script that will be published remotely + +#> +Param() diff --git a/test/testFiles/testScripts/ScriptWithoutEmptyLinesInMetadata.ps1 b/test/testFiles/testScripts/ScriptWithoutEmptyLinesInMetadata.ps1 new file mode 100644 index 000000000..2b28db61f --- /dev/null +++ b/test/testFiles/testScripts/ScriptWithoutEmptyLinesInMetadata.ps1 @@ -0,0 +1,23 @@ + +<#PSScriptInfo +.VERSION 1.0 +.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd +.AUTHOR annavied +.COMPANYNAME +.COPYRIGHT +.TAGS +.LICENSEURI +.PROJECTURI +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES +.PRIVATEDATA +#> + +<# +.DESCRIPTION + this is a test for a script that will be published remotely +#> +Param() From 81fc032dd5cc7400fe6d88c006e92e16f0db5be9 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 8 Aug 2022 15:43:39 -0400 Subject: [PATCH 231/276] Change ConfirmImpact from Medium to Low --- src/code/RegisterPSResourceRepository.cs | 3 ++- src/code/SavePSResource.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 6564f4d18..d6857837a 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -20,7 +20,8 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets [Cmdlet(VerbsLifecycle.Register, "PSResourceRepository", DefaultParameterSetName = NameParameterSet, - SupportsShouldProcess = true)] + SupportsShouldProcess = true, + ConfirmImpact = ConfirmImpact.Low)] public sealed class RegisterPSResourceRepository : PSCmdlet { diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 2fa8f0480..9441b79d7 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -17,7 +17,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// The Save-PSResource cmdlet saves a resource to a machine. /// It returns nothing. /// - [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true)] + [Cmdlet(VerbsData.Save, "PSResource", DefaultParameterSetName = "NameParameterSet", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low)] public sealed class SavePSResource : PSCmdlet { #region Members From 7517e74e60d559d1f3d7746632e7c4c58c716ab5 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 8 Aug 2022 15:09:46 -0700 Subject: [PATCH 232/276] Change default path to CurrentFileSystemLocation (#742) --- src/code/SavePSResource.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 2fa8f0480..4ee691b7e 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -91,8 +91,12 @@ public string Path set { string resolvedPath = string.Empty; - if (!string.IsNullOrEmpty(value)) + if (string.IsNullOrEmpty(value)) { + // If the user does not specify a path to save to, use the user's current working directory + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(SessionState.Path.CurrentFileSystemLocation.Path).First().Path; + } + else { resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } @@ -155,12 +159,6 @@ protected override void BeginProcessing() // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); - // If the user does not specify a path to save to, use the user's current working directory - if (string.IsNullOrWhiteSpace(_path)) - { - _path = SessionState.Path.CurrentLocation.Path; - } - _installHelper = new InstallHelper(cmdletPassedIn: this); } From 1131479cc701e754b1689cfeb6519837c4bdb987 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Wed, 10 Aug 2022 12:51:31 -0400 Subject: [PATCH 233/276] Fix -PassThru to return all properties --- src/code/RepositorySettings.cs | 23 ++++++++++++++++++++++- test/SetPSResourceRepository.Tests.ps1 | 11 ++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index dec5d2d15..49f698eb4 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -168,7 +168,7 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // determine if existing repository node (which we wish to update) had Url to Uri attribute Uri thisUrl = null; - if (repoUri != null) + /*if (repoUri != null) { if (urlAttributeExists) { @@ -188,8 +188,29 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); } } + }*/ + + if (urlAttributeExists) { + if (repoUri != null) { + node.Attribute("Url").Value = repoUri.AbsoluteUri; + } + if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); + } + } + else { + if (repoUri != null) { + node.Attribute("Uri").Value = repoUri.AbsoluteUri; + } + if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); + } } + + diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index 25eb1c820..a7c27124c 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -241,7 +241,7 @@ Describe "Test Set-PSResourceRepository" { $Res.Uri.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" } - It "set repository and see updated repository with -PassThru" { + It "set repository given Uri and see updated repository with -PassThru" { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $res = Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir2Path -PassThru $res.Name | Should -Be $TestRepoName1 @@ -250,6 +250,15 @@ Describe "Test Set-PSResourceRepository" { $res.Trusted | Should -Be False } + It "set repository given Priority and see updated repository with -PassThru" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + $res = Set-PSResourceRepository -Name $TestRepoName1 -Priority 30 -PassThru + $res.Name | Should -Be $TestRepoName1 + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 30 + $res.Trusted | Should -Be False + } + It "prints a warning if CredentialInfo is passed in without SecretManagement module setup" { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $output = Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -CredentialInfo $credentialInfo1 3>&1 From ce2c803f0e9cfaa56580301cf45d80d54c824624 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Wed, 10 Aug 2022 13:26:03 -0400 Subject: [PATCH 234/276] Delete commented code --- src/code/RepositorySettings.cs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 49f698eb4..928e5ddbd 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -168,28 +168,6 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // determine if existing repository node (which we wish to update) had Url to Uri attribute Uri thisUrl = null; - /*if (repoUri != null) - { - if (urlAttributeExists) - { - node.Attribute("Url").Value = repoUri.AbsoluteUri; - // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. - if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) - { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); - } - } - else - { - // Uri attribute exists - node.Attribute("Uri").Value = repoUri.AbsoluteUri; - if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) - { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); - } - } - }*/ - if (urlAttributeExists) { if (repoUri != null) { node.Attribute("Url").Value = repoUri.AbsoluteUri; From 51256a30ba8112fb1d9aa3eb34a4486c5a36c905 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 10 Aug 2022 19:29:34 -0700 Subject: [PATCH 235/276] Add ValueFromPipelineByPropertyName to Set-PSResourceRepository (#705) --- src/code/SetPSResourceRepository.cs | 2 +- test/SetPSResourceRepository.Tests.ps1 | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 2ada5bdee..c1a71a05e 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -34,7 +34,7 @@ public sealed class SetPSResourceRepository : PSCmdlet /// /// Specifies the name of the repository to be set. /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = NameParameterSet)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = NameParameterSet)] [ArgumentCompleter(typeof(RepositoryNameCompleter))] [ValidateNotNullOrEmpty] public string Name { get; set; } diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index 25eb1c820..d3d15a9a9 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -69,6 +69,17 @@ Describe "Test Set-PSResourceRepository" { $res.CredentialInfo | Should -BeNullOrEmpty } + It "set repository given pipeline input ValueFromPipelineByPropertyName passed in" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path + Get-PSResourceRepository -Name $TestRepoName1 | Set-PSResourceRepository -Trusted + $res = Get-PSResourceRepository -Name $TestRepoName1 + $res.Name | Should -Be $TestRepoName1 + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be True + $res.CredentialInfo | Should -BeNullOrEmpty + } + It "set repository given Name and CredentialInfo parameters" { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path Set-PSResourceRepository -Name $TestRepoName1 -CredentialInfo $credentialInfo1 From fc5e2fd0b89da34f009c764cd454b0516a88f205 Mon Sep 17 00:00:00 2001 From: Alyssa Vu <49544763+alyssa1303@users.noreply.github.com> Date: Thu, 11 Aug 2022 12:22:04 -0400 Subject: [PATCH 236/276] Fix typo Co-authored-by: Anam Navied --- src/code/RepositorySettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 928e5ddbd..cfb74594f 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -166,7 +166,7 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // A null Uri (or Url) value passed in signifies the Uri was not attempted to be set. // So only set Uri attribute if non-null value passed in for repoUri - // determine if existing repository node (which we wish to update) had Url to Uri attribute + // determine if existing repository node (which we wish to update) had Url or Uri attribute Uri thisUrl = null; if (urlAttributeExists) { if (repoUri != null) { From 862ab3c6a0ce87d7f2685e393e023f9f6b625a19 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Thu, 11 Aug 2022 13:02:22 -0500 Subject: [PATCH 237/276] Editorial pass on cmdlet ref (#743) --- .gitignore | 2 + help/Find-PSResource.md | 313 +++++++++------ help/Get-PSResource.md | 151 +++++--- help/Get-PSResourceRepository.md | 93 +++-- help/Install-PSResource.md | 465 +++++++++++++---------- help/New-PSScriptFileInfo.md | 260 +++++++------ help/PowerShellGet.md | 48 ++- help/Publish-PSResource.md | 118 ++++-- help/Register-PSResourceRepository.md | 283 +++++++++----- help/Save-PSResource.md | 243 +++++++----- help/Set-PSResourceRepository.md | 240 ++++++++---- help/Test-PSScriptFileInfo.md | 117 ++---- help/Uninstall-PSResource.md | 166 ++++++-- help/Unregister-PSResourceRepository.md | 110 ++++-- help/Update-ModuleManifest.md | 481 +++++++++++++++--------- help/Update-PSResource.md | 238 +++++++----- help/Update-PSScriptFileInfo.md | 212 ++++++----- 17 files changed, 2201 insertions(+), 1339 deletions(-) diff --git a/.gitignore b/.gitignore index 557d7d4e0..ab0db5255 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ src/code/obj srcOld/code/bin srcOld/code/obj out +test/**/obj +test/**/bin \ No newline at end of file diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index 2be404745..67db70601 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -1,6 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet +ms.date: 08/03/2022 online version: schema: 2.0.0 --- @@ -8,127 +9,189 @@ schema: 2.0.0 # Find-PSResource ## SYNOPSIS -Searches for packages from a repository (local or remote), based on `-Name` and other package properties. +Searches for packages from a repository (local or remote), based on a name or other package +properties. ## SYNTAX ### ResourceNameParameterSet (Default) -``` PowerShell -[[-Name] ] [-Type ] [-Version ] [-Prerelease] [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] + +``` +Find-PSResource [[-Name] ] [-Type ] [-Version ] [-Prerelease] + [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] + [] ``` ### CommandNameParameterSet -``` PowerShell -[[-CommandName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] + +``` +Find-PSResource -CommandName [-Version ] [-Prerelease] [-ModuleName ] + [-Tag ] [-Repository ] [-Credential ] [-IncludeDependencies] + [] ``` ### DscResourceNameParameterSet -``` PowerShell -[[-DscResourceName] ] [-ModuleName ] [-Version ] [-Prerelease] [-Tag ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] -``` -### TagParameterSet -``` PowerShell -[-Name ][-Tag ] [-Prerelease] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] ``` - -### TypeParameterSet -``` PowerShell -[Name ] [-Prerelease] [-Type ] -[-Repository ] [-Credential ] [-IncludeDependencies] [-WhatIf] [-Confirm] [] +Find-PSResource -DscResourceName [-Version ] [-Prerelease] + [-ModuleName ] [-Tag ] [-Repository ] [-Credential ] + [-IncludeDependencies] [] ``` ## DESCRIPTION -The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. + +The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on a +name or other package properties. ## EXAMPLES ### Example 1 + +This examples searches PowerShell Gallery for the **PowerShellGet** package. The cmdlet returns the +highest non-prerelease version. + ```powershell -PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... +Find-PSResource -Name PowerShellGet -Repository PSGallery ``` -These examples assume that the PSGallery repository is registered and contains the packages we are searching for. -This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PowerShellGet 2.2.5.0 PSGallery PowerShell module with commands for discovering, installing, updating and … +``` ### Example 2 + +This examples searches PowerShell Gallery for the **PowerShellGet** package, including prerelease +versions. + ```powershell -PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... +Find-PSResource -Name PowerShellGet -Repository PSGallery -Prerelease ``` -This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PowerShellGet 3.0.14.0 beta14 PSGallery PowerShell module with commands for discovering, installing, updating and… +``` ### Example 3 + +This examples searches PowerShell Gallery for the **Microsoft.PowerShell.SecretManagement** package. +The cmdlet returns all versions that satisfy the specified **Version** range. + ```powershell -PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... - Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... +Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.2.0.0]" -Repository PSGallery -Prerelease ``` -This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +Microsoft.PowerShell.SecretManagement 1.1.2.0 PSGallery … +Microsoft.PowerShell.SecretManagement 1.1.1.0 PSGallery … +Microsoft.PowerShell.SecretManagement 1.1.0.0 PSGallery … +Microsoft.PowerShell.SecretManagement 1.0.0.0 PSGallery … +Microsoft.PowerShell.SecretManagement 0.9.1.0 PSGallery … +``` ### Example 4 -```powershell -PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery - Get-TargetResource 1.0.0.4 WindowsDefender PSGallery - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery - Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery - Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery - Get-TargetResource 1.2.0.0 cRegFile PSGallery - Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery - Get-TargetResource 1.0.0.0 cVNIC PSGallery - Get-TargetResource 1.1.17.0 supVsts PSGallery +This examples searches for all module resources containing the **CommandName** of +`Get-TargetResource`. The cmdlet returns all the module resources that include the command. + +```powershell +Find-PSResource -CommandName Get-TargetResource -Repository PSGallery | + Select-Object -ExpandProperty ParentResource ``` -This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +xPowerShellExecutionPolicy 3.1.0.0 PSGallery This DSC resource can change the user preference for the W… +WindowsDefender 1.0.0.4 PSGallery Windows Defender module allows you to configure Windows De… +SystemLocaleDsc 1.2.0.0 PSGallery This DSC Resource allows configuration of the Windows Syst… +xInternetExplorerHomePage 1.0.0.0 PSGallery This DSC Resources can easily set an URL for the home page… +OctopusDSC 4.0.1127.0 PSGallery Module with DSC resource to install and configure an Octop… +cRegFile 1.2.0.0 PSGallery DSC resource which is designed to manage large numbers of … +cWindowsErrorReporting 1.1.0.0 PSGallery DSC Resource to enable or disable Windows Error Reporting +cVNIC 1.0.0.0 PSGallery DSC Module to create and configuring virutal network adapt… +supVsts 1.1.17.0 PSGallery Dsc module for interfacing with VSTS. +``` ### Example 5 + +This examples searches for a module resource with a a specific module with a named command. + ```powershell -PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery +Find-PSResource -CommandName Get-TargetResource -ModuleName SystemLocaleDsc -Repository PSGallery | + Select-Object -ExpandProperty ParentResource ``` -This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +SystemLocaleDsc 1.2.0.0 PSGallery This DSC Resource allows configuration of the Windows System Locale. +``` ### Example 6 -```powershell -PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery +This examples searches for all module resources containing the DSC Resource `SystemLocale`. + +```powershell +Find-PSResource -DscResourceName SystemLocale -Repository PSGallery | + Select-Object -ExpandProperty ParentResource ``` -This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +ComputerManagementDsc 8.5.0.0 PSGallery DSC resources for configuration of a Windows computer. These DSC r… +SystemLocaleDsc 1.2.0.0 PSGallery This DSC Resource allows configuration of the Windows System Local… +``` ### Example 7 + +This example searches all registered PSResourceRepositories for resources with names starting with +`Computer`. + ```powershell -PS C:\> Find-PSResource -Name * +Find-PSResource -Name Computer* ``` -This will search all PSResources from registered PSResourceRepositories. +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +ComputerManagementDsc 8.5.0.0 PSGallery DSC resources for configuration … +ComputerManagement 1.1.2.3 PSGallery A PowerShell module for working … +Computer_JoinDomain_Config 1.0.0.0 PSGalleryScripts This configuration sets the mach… +Computer_UnjoinDomainAndJoinWorkgroup_Config 1.0.0.0 PSGalleryScripts This example switches the comput… +Computer_SetComputerDescriptionInWorkgroup_Config 1.0.0.0 PSGalleryScripts This example will set the comput… +Computer_JoinDomainSpecifyingDC_Config 1.0.0.0 PSGalleryScripts This configuration sets the mach… +Computer_RenameComputerAndSetWorkgroup_Config 1.0.0.0 PSGalleryScripts This configuration will set the … +Computer_RenameComputerInDomain_Config 1.0.0.0 PSGalleryScripts This example will change the mac… +Computer_RenameComputerInWorkgroup_Config 1.0.0.0 PSGalleryScripts This example will set the machin… +``` ## PARAMETERS +### -CommandName + +The name of the command to search for. + +```yaml +Type: System.String[] +Parameter Sets: CommandNameParameterSet +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Credential + Optional credentials to be used when accessing a repository. ```yaml @@ -143,9 +206,26 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -DscResourceName + +The name of the DSC Resource to search for. + +```yaml +Type: System.String[] +Parameter Sets: DscResourceNameParameterSet +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -IncludeDependencies -When specified, search will return all matched resources along with any resources the matched resources depends on. -Dependencies are deduplicated. + +When specified, search returns all matching resources their dependencies. Dependencies are +deduplicated. ```yaml Type: System.Management.Automation.SwitchParameter @@ -154,19 +234,20 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -ModuleName -Specifies a module resource package name type to search for. -Wildcards are supported. + +Specifies a module resource package name type to search for. Wildcards are supported. + Not yet implemented. ```yaml -Type: System.String -Parameter Sets: (All) +Type: System.String[] +Parameter Sets: CommandNameParameterSet, DscResourceNameParameterSet Aliases: Required: False @@ -177,22 +258,25 @@ Accept wildcard characters: False ``` ### -Name -Name of a resource or resources to find. -Accepts wild card character '*'. + +Name of a resource to find. Wildcards are supported but NuGet only accepts the `*` character. NuGet +does not support wildcard searches of local (file-based) repositories. + ```yaml Type: System.String[] -Parameter Sets: (All) +Parameter Sets: ResourceNameParameterSet Aliases: -Required: True +Required: False Position: 0 Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: True (ByValue) Accept wildcard characters: True ``` ### -Prerelease + When specified, includes prerelease versions in search results returned. ```yaml @@ -202,14 +286,19 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Repository -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. + +Specifies one or more repository names to search. Wildcards are supported. + +If not specified, search includes all registered repositories, in priority order (highest first), +until a repository is found that contains the package. + +Lower **Priority** values have a higher precedence. ```yaml Type: System.String[] @@ -224,6 +313,7 @@ Accept wildcard characters: True ``` ### -Tag + Filters search results for resources that include one or more of the specified tags. ```yaml @@ -239,12 +329,17 @@ Accept wildcard characters: False ``` ### -Type -Specifies one or more resource types to find. -Resource types supported are: Module, Script, Command, DscResource. + +Specifies one or more resource types to find. Resource types supported are: + +- `Module` +- `Script` +- `Command` +- `DscResource` ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] -Parameter Sets: (All) +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType +Parameter Sets: ResourceNameParameterSet Aliases: Accepted values: Module, Script, DscResource, Command @@ -256,16 +351,17 @@ Accept wildcard characters: False ``` ### -Version + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. -For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) +Wildcards are supported but NuGet only accepts wildcard character `*`. For more information about +NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges). PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range -documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher -(minimum inclusive range). Instead, the values is considered as the required version and yields -version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as -the version range. +documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum +inclusive range). Instead, the value is considered to be the required version. To search for a +minimum inclusive range, use `[1.0.0.0, ]` as the version range. ```yaml Type: System.String @@ -279,39 +375,12 @@ Accept pipeline input: False Accept wildcard characters: True ``` -### -Confirm -Prompts you for confirmation before running the cmdlet. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: cf - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. - -```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: wi - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS @@ -324,5 +393,3 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## NOTES ## RELATED LINKS - -[]() diff --git a/help/Get-PSResource.md b/help/Get-PSResource.md index 97484d7cd..1e4b281be 100644 --- a/help/Get-PSResource.md +++ b/help/Get-PSResource.md @@ -1,6 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet +ms.date: 08/03/2022 online version: schema: 2.0.0 --- @@ -8,98 +9,151 @@ schema: 2.0.0 # Get-PSResource ## SYNOPSIS -Returns resources (modules and scripts) installed on the machine via PowerShellGet. +Returns modules and scripts installed on the machine via **PowerShellGet**. ## SYNTAX +### __AllParameterSets + ``` -Get-PSResource [[-Name] ] [-Version ] [-Path ] [-Scope ] [] +Get-PSResource [[-Name] ] [-Version ] [-Path ] [-Scope ] + [] ``` ## DESCRIPTION -The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. + +This cmdlet searches the module and script installation paths and returns **PSResourceInfo** objects +that describes each resource item found. This is equivalent to the combined output of the +`Get-InstalledModule` and `Get-InstalledScript` cmdlets from **PowerShellGet** v2. ## EXAMPLES ### Example 1 + +This example return all versions of modules and scripts installed on the machine. + ```powershell -PS C:\> Get-PSResource Az +Get-PSResource ``` -This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. - ### Example 2 + +This example returns all versions of the **Az** module installed using **PowerShellGet**. + ```powershell -PS C:\> Get-PSResource Az -version "1.0.0" +Get-PSResource Az ``` -This will return version 1.0.0 of the Az module. - ### Example 3 + +This example return all versions of the **Az** module installed in the current directory. + ```powershell -PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" +Get-PSResource Az -Path . ``` -This will return all versions of the Az module within the specified range. - ### Example 4 + +This example returns a specific version of the Az module if it's installed on the system.. + ```powershell -PS C:\> Get-PSResource Az -version "4.0.1-preview" +Get-PSResource Az -Version 1.0.0 ``` -Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. - ### Example 5 + +This example return all installed versions of the Az module within the specified version range. + ```powershell -PS C:\> Get-PSResource Az -version "4.0.1" +Get-PSResource Az -Version "(1.0.0, 3.0.0)" ``` -Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. ### Example 6 + +This example returns a specific preview version of the **PowerShellGet** module if it's installed +on the system. + ```powershell -PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] +Get-PSResource PowerShellGet -Version 3.0.14-beta14 ``` -Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. - +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PowerShellGet 3.0.14 beta14 PSGallery PowerShell module with commands for discovering, installing, updating and … +``` ### Example 6 + +The previous example showed that **PowerShellGet** version 3.0.14-beta14 was installed on the +system. This example shows that you must provide the full version, including the **Prerelease** +label to identify the installed module by **Version**. + ```powershell -PS C:\> Get-PSResource Az -Path . +Get-PSResource PowerShellGet -Version 3.0.14 ``` -This will return all versions of the Az module that have been installed in the current directory. +There is no output from this command. ### Example 7 + +In this example you see that there are four version of **PSReadLine** installed on the system. The +second command searches for a range of version between `2.2.0` and `2.3.0`. + ```powershell -PS C:\> Get-PSResource +Get-PSResource PSReadLine +``` + +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PSReadLine 2.2.6 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.5 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.2 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.0 beta4 PSGallery Great command line editing in the PowerShell console host +``` + +```powershell +Get-PSResource PSReadLine -Version '[2.2.0, 2.3.0]' +``` + +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PSReadLine 2.2.6 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.5 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.2 PSGallery Great command line editing in the PowerShell console host ``` -This will return all versions and scripts installed on the machine. +According to NuGet version rules a prerelease version is less than a stable version, so +`2.2.0-beta4` is less than the `2.2.0` version in the specified version range. ## PARAMETERS ### -Name -Name of a resource or resources to find. Accepts wild card characters or a null value. + +Name of a resource to find. Wildcards are supported but NuGet only accepts the `*` character. NuGet +does not support wildcard searches of local (file-based) repositories. ```yaml Type: System.String[] -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False Position: 0 Default value: None -Accept pipeline input: True +Accept pipeline input: True (ByValue) Accept wildcard characters: True ``` ### -Path + Specifies the path to search in. ```yaml Type: System.String -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False @@ -109,22 +163,15 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Version -Specifies the version of the resource to be returned. The value can be an exact version or a version -range using the NuGet versioning syntax. - -For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) +### -Scope -PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range -documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher -(minimum inclusive range). Instead, the values is considered as the required version and yields -version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as -the version range. +Specifies the scope of the resource. ```yaml -Type: System.String -Parameter Sets: NameParameterSet +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Parameter Sets: (All) Aliases: +Accepted values: CurrentUser, AllUsers Required: False Position: Named @@ -132,14 +179,24 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` -### -Scope -Specifies the scope of the resource. + +### -Version + +Specifies the version of the resource to be returned. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see +[Package versioning](/nuget/concepts/package-versioning#version-ranges). + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum +inclusive range). Instead, the value is considered to be the required version. To search for a +minimum inclusive range, use `[1.0.0.0, ]` as the version range. ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Type: System.String Parameter Sets: (All) Aliases: -Accepted values: CurrentUser, AllUsers Required: False Position: Named @@ -149,7 +206,11 @@ Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## NOTES diff --git a/help/Get-PSResourceRepository.md b/help/Get-PSResourceRepository.md index 87689c67d..6b96388e9 100644 --- a/help/Get-PSResourceRepository.md +++ b/help/Get-PSResourceRepository.md @@ -1,7 +1,8 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- @@ -12,69 +13,88 @@ Finds and returns registered repository information. ## SYNTAX +### __AllParameterSets + ``` -Get-PSResourceRepository [[-Name] ] [] +Get-PSResourceRepository [[-Name] ] [] ``` ## DESCRIPTION -The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. + +This cmdlet searches for PowerShell resource repositories that are registered on the machine. By +default, it returns all registered repositories. ## EXAMPLES ### Example 1 -``` -PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 + +This example returns all the repositories registered on the machine. + +```powershell +Get-PSResourceRepository ``` -This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 +psgettestlocal file:///c:/code/testdir True 50 +``` ### Example 2 -``` -PS C:\> Get-PSResourceRepository -Name "*Gallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 +This example uses the **Name** parameter to get a specific repository. + +```powershell +Get-PSResourceRepository -Name PSGallery ``` -This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +``` ### Example 3 -``` -PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 +This example uses the **Name** parameter to get all repositories that end with `Gallery`. + +```powershell +Get-PSResourceRepository -Name "*Gallery" ``` -This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 +``` ### Example 4 -``` -PS C:\> Get-PSResourceRepository -Name "*" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir True 50 +This example uses the **Name** parameter to get a list of named respositories. + +```powershell +Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" ``` -This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 +``` ## PARAMETERS ### -Name -This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + +The name of the repository to search for. Wildcards are supported. Tab completion for this parameter +cycles through the registered repository names. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) Aliases: @@ -86,7 +106,11 @@ Accept wildcard characters: True ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS @@ -97,6 +121,5 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo ## NOTES -If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. ## RELATED LINKS diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index f4120260b..28eb45d6f 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -1,165 +1,156 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- # Install-PSResource ## SYNOPSIS -Installs resources (modules and scripts) from a registered repository onto the machine. +Installs resources from a registered repository. ## SYNTAX -### NameParameterSet +### NameParameterSet (Default) + ``` -Install-PSResource [-Name ] [-Version ] [-Prerelease] - [-Repository ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] +Install-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] + [-Credential ] [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] + [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] + [-Confirm] [] ``` ### InputObjectParameterSet + ``` -Install-PSResource [-InputObject ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] [] +Install-PSResource [-InputObject] [-Credential ] + [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] + [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` - -### RequiredResourceParameterSet + +### RequiredResourceFileParameterSet + ``` -Install-PSResource [-RequiredResource ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] +Install-PSResource [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] + [-PassThru] [-RequiredResourceFile ] [-WhatIf] [-Confirm] [] ``` - -### RequiredResourceFileParameterSet + +### RequiredResourceParameterSet + ``` -Install-PSResource [-RequiredResourceFile ] [-Credential ] [-Scope ] [-TrustRepository] - [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] +Install-PSResource [-Credential ] [-Scope ] [-TrustRepository] + [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] + [-PassThru] [-RequiredResource ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. -It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. + +This cmdlet installs resources from a registered repository to an installation path on a machine. By +default, the cmdlet doesn't return any object. Other parameters allow you to specify the repository, +scope, and version for a resource, and suppress license prompts. + +This cmdlet combines the functions of the `Install-Module` and `Install-Script` cmdlets from +**PowerShellGet** v2. ## EXAMPLES ### Example 1 -```powershell -PS C:\> Install-PSResource Az -``` -Installs the Az module. +Installs the latest stable (non-prerelease) version of the **Az** module. -### Example 2 ```powershell -PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" +Install-PSResource Az ``` -Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. +### Example 2 + +Installs the latest stable **Az** module within the between versions `7.3.0` and `8.3.0`. -### Example 3 ```powershell -PS C:\> Install-PSResource Az -Repository PSGallery +Install-PSResource Az -Version '[7.3.0, 8.3.0]' ``` -Installs the latest stable Az module from the PowerShellGallery. +### Example 3 +Installs the latest stable version of the **Az** module. When the **Reinstall** parameter is used, +the cmdlet writes over any previously installed version. -### Example 3 ```powershell -PS C:\> Install-PSResource Az -Reinstall +Install-PSResource Az -Reinstall ``` -Installs the Az module and will write over any previously installed version if it is already installed. - ### Example 4 -```powershell -PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 -``` Installs the PSResources specified in the psd1 file. +```powershell +Install-PSResource -RequiredResourceFile myRequiredModules.psd1 +``` + ### Example 5 + +Installs the PSResources specified in the hashtable. + ```powershell -PS C:\> Install-PSResource -RequiredResource @{ +Install-PSResource -RequiredResource @{ TestModule = @{ version = "[0.0.1,1.3.0]" repository = "PSGallery" } - TestModulePrerelease = @{ + TestModulePrerelease = @{ version = "[0.0.0,0.0.5]" repository = "PSGallery" prerelease = "true" - } + } TestModule99 = @{} } ``` -Installs the PSResources specified in the hashtable. - ## PARAMETERS -### -Name -Name of a resource or resources to install. Does not accept wildcard characters or a null value. - -```yaml -Type: System.String[] -Parameter Sets: NameParameterSet -Aliases: - -Required: True -Position: 0 -Default value: None -Accept pipeline input: True (ByValue) -Accept wildcard characters: False -``` - -### -Version -Specifies the version of the resource to be installed. The value can be an exact version or a version -range using the NuGet versioning syntax. - -For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) +### -AcceptLicense -PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range -documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher -(minimum inclusive range). Instead, the values is considered as the required version and yields -version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as -the version range. +Specifies that the resource should accept any request to accept the license agreement. This +suppresses prompting if the module mandates that a user accept the license agreement. ```yaml -Type: System.String -Parameter Sets: NameParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Prerelease -When specified, includes prerelease versions in search results returned. +### -AuthenticodeCheck + +Validates Authenticode signatures and catalog files on Windows. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Repository -Specifies one or more repository names to search. -If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. +### -Credential + +Optional credentials used when accessing a repository. ```yaml -Type: System.String[] -Parameter Sets: NameParameterSet +Type: System.Management.Automation.PSCredential +Parameter Sets: (All) Aliases: Required: False @@ -168,93 +159,30 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` -### -RequiredResource -A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. -The hashtable will take a format with the module attributes like the following example -```Powershell - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } +### -InputObject - TestModule99 = @{} -} -``` -A json string will take the following example format -```json -{ - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} -} -``` +Used for pipeline input. ```yaml -Type: RequiredResource -Parameter Sets: RequiredResource +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Parameter Sets: InputObjectParameterSet Aliases: Required: True -Position: 0 +Position: Named Default value: None Accept pipeline input: True (ByValue) Accept wildcard characters: False -``` - -### -RequiredResourceFile -Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. +``` -The psd1 will take a hashtable format with the module attributes like the following example -```Powershell - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } +### -Name - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} -} -``` -json files will take the following example format -```json -{ - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} -} -``` +The name of one or more resources to install. ```yaml Type: System.String[] -Parameter Sets: RequiredResourceFileParameterSet +Parameter Sets: NameParameterSet Aliases: Required: True @@ -264,55 +192,57 @@ Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` +### -NoClobber -### -Credential -Optional credentials to be used when accessing a repository. +Prevents installing a package that contains cmdlets that already exist on the machine. ```yaml -Type: System.Management.Automation.PSCredential +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Scope -Specifies the scope under which a user has access. +### -PassThru + +When specified, outputs a **PSResourceInfo** object for the saved resource. ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: -Accepted values: CurrentUser, AllUsers Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -TrustRepository -Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. +### -Prerelease + +When specified, includes prerelease versions in search results returned. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Reinstall -Writes over any previously installed resource version that already exists on the machine. +### -Quiet + +Suppresses installation progress bar. ```yaml Type: System.Management.Automation.SwitchParameter @@ -321,13 +251,18 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Quiet -Supresses installation progress bar. +### -Reinstall + +Installs the latest version of a module even if the latest version is already installed. The +installed version is overwritten. This allows you to repair a damaged installation of the module. + +If an older version of the module is installed, the new version is installed side-by-side in a new +version-specific folder. ```yaml Type: System.Management.Automation.SwitchParameter @@ -336,17 +271,23 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -AcceptLicense -Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. +### -Repository + +Specifies one or more repository names to search. Wildcards are supported. + +If not specified, search includes all registered repositories, in priority order (highest first), +until a repository is found that contains the package. + +Lower **Priority** values have a higher precedence. ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Type: System.String[] +Parameter Sets: NameParameterSet Aliases: Required: False @@ -356,28 +297,64 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -NoClobber -Prevents installing a package that contains cmdlets that already exist on the machine. +### -RequiredResource + +A hashtable or JSON string that specifies resources to install. Wildcard characters aren't allowed. +See the [NOTES](#notes) section for a description of the file formats. ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: +Type: System.Object +Parameter Sets: RequiredResourceParameterSet +Aliases: Required: False -Position: Named +Position: 0 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` -### -SkipDependencyCheck -Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. +### -RequiredResourceFile + +Path to a `.psd1` or `.json` that specifies resources to install. Wildcard characters aren't +allowed. See the [NOTES](#notes) section for a description of the file formats. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: System.String +Parameter Sets: RequiredResourceFileParameterSet +Aliases: + +Required: False +Position: 0 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Scope + +Specifies the installation scope. Accepted values are: + +- `CurrentUser` +- `AllUsers` + +The default scope is `CurrentUser`, which doesn't require elevation for install. + +The `AllUsers` scope installs modules in a location accessible to all users of the computer. For +example: + +- `$env:ProgramFiles\PowerShell\Modules` + +The `CurrentUser` installs modules in a location accessible only to the current user of the +computer. For example: + +- `$home\Documents\PowerShell\Modules` + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType Parameter Sets: (All) -Aliases: +Aliases: +Accepted values: CurrentUser, AllUsers Required: False Position: Named @@ -385,23 +362,28 @@ Default value: None Accept pipeline input: False Accept wildcard characters: False ``` -### -AuthenticodeCheck -Does a check to to validate signed files and catalog files on Windows. + +### -SkipDependencyCheck + +Skips the check for resource dependencies. Only found resources are installed. No resources of the +found resource are installed. ```yaml Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: +Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False -``` +``` -### -PassThru -Passes the resource installed to the console. +### -TrustRepository + +Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository +isn't configured as trusted. ```yaml Type: System.Management.Automation.SwitchParameter @@ -410,18 +392,28 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -InputObject -Used for pipeline input. +### -Version + +Specifies the version of the resource to be returned. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see +[Package versioning](/nuget/concepts/package-versioning#version-ranges). + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum +inclusive range). Instead, the value is considered to be the required version. To search for a +minimum inclusive range, use `[1.0.0.0, ]` as the version range. ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo -Parameter Sets: (All) -Aliases: wi +Type: System.String +Parameter Sets: NameParameterSet +Aliases: Required: False Position: Named @@ -431,6 +423,7 @@ Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml @@ -440,14 +433,14 @@ Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml Type: System.Management.Automation.SwitchParameter @@ -456,14 +449,86 @@ Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + +By default, the cmdlet doesn't return any objects. When the **PassThru** parameter is used, the +cmdlet outputs a **PSResourceInfo** object for the saved resource. ## NOTES +The **RequiredResource** and **RequiredResourceFile** parameters are used to match **PSResources** +matching specific criteria. You can specify the criteria using a hashtable or a JSON object. For the +**RequiredResourceFile** parameter, the hashtable is stored in a `.psd1` file and the JSON object is +stored in a `.json` file. + +The hashtable can contain attributes for multiple modules. The following example show the structure +of the module specification: + +```Syntax +@{ + = @{ + version = '' + repository = '' + prerelease = '' + } +} +``` + +This example contains specifications for three modules. As you can, the module attributes are +optional. + +```powershell + @{ + TestModule = @{ + version = '[0.0.1,1.3.0]' + repository = 'PSGallery' + } + + TestModulePrerelease = @{ + version = '[0.0.0,0.0.5]' + repository = 'PSGallery' + prerelease = 'true' + } + + TestModule99 = @{} +} +``` + +The next example shows the same specification in JSON format. + +```json +{ + "TestModule": { + "version": "[0.0.1,1.3.0)", + "repository": "PSGallery" + }, + "TestModulePrerelease": { + "version": "[0.0.0,0.0.5]", + "repository": "PSGallery", + "prerelease": "true" + }, + "TestModule99": {} +} +``` + ## RELATED LINKS + +[Package versioning](/nuget/concepts/package-versioning#version-ranges) + +[Uninstall-PSResource](Uninstall-PSResource.md) diff --git a/help/New-PSScriptFileInfo.md b/help/New-PSScriptFileInfo.md index 48301c3d5..d21f2db2c 100644 --- a/help/New-PSScriptFileInfo.md +++ b/help/New-PSScriptFileInfo.md @@ -1,35 +1,48 @@ --- external help file: PowerShellGet-help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- # New-PSScriptFileInfo ## SYNOPSIS - -Creates a new .ps1 file containing metadata for the script, which is used when publishing a script package. +The cmdlet creates a new script file, including metadata about the script. ## SYNTAX ### __AllParameterSets ``` -New-PSScriptFileInfo [-FilePath] -Description [-Author ] [-CompanyName ] [-Copyright ] [-ExternalModuleDependencies ] [-ExternalScriptDependencies ] [-Force] [-Guid ] [-IconUri ] [-LicenseUri ] [-PrivateData ] [-ProjectUri ] [-ReleaseNotes ] [-RequiredModules ] [-RequiredScripts ] [-Tags ] [-Version ] [] +New-PSScriptFileInfo [-FilePath] -Description [-Version ] + [-Author ] [-Guid ] [-CompanyName ] [-Copyright ] + [-RequiredModules ] [-ExternalModuleDependencies ] + [-RequiredScripts ] [-ExternalScriptDependencies ] [-Tags ] + [-ProjectUri ] [-LicenseUri ] [-IconUri ] [-ReleaseNotes ] + [-PrivateData ] [-Force] [] ``` ## DESCRIPTION -The New-PSScriptFileInfo cmdlet creates a .ps1 file containing metadata for the script. +The cmdlet creates a new script file containing the required metadata needed to publish a script +package. ## EXAMPLES -### Example 1: Creating a script with minimum required parameters +### Example 1: Creating an empty script with minimal information + +This example runs the cmdlet using only required parameters. The **FilePath** parameter specifies +the nane and location of the script. The **Description** parameter provide the description used in +the comment-based help for the script. +```powershell +New-PSScriptFileInfo -FilePath ./test_script.ps1 -Description "This is a test script." +Get-Content ./test_script.ps1 ``` -PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" + +```Output <#PSScriptInfo .VERSION 1.0.0.0 @@ -50,11 +63,11 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .ICONURI -.EXTERNALMODULEDEPENDENCIES +.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS +.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES +.EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES @@ -67,21 +80,36 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" <# .DESCRIPTION -this is a test script +This is a test script. #> - -``` -This example runs the cmdlet with the only required parameters, the 'FilePath' parameter sets the path the script is to be created and the 'Description' parameter contains the description for the script. The script is successfully created and if the contents of the file are viewed we can see the Description set as well as Author, Guid, and Version (with default values). - -### Example 2: Creating a script with RequiredModules, Author, Version and Description parameters +``` +### Example 2: Creating a script with required modules + +This example runs the cmdlet with additional parameters, including **RequiredModules**. The +**RequiredModules** parameter describes modules required by the script. The parameter takes an array +of hashtables. The **ModuleName** key in the hashtable is required. You can also include +**ModuleVersion**, **RequiredVersion**, **MaximumVersion**, or **MinimumVersion** keys. + +```powershell +$parameters = @{ + FilePath = './test_script2.ps1' + Description = 'This is a test script.' + Version = '2.0.0.0' + Author = 'janedoe' + RequiredModules = @( + @{ModuleName = "PackageManagement"; ModuleVersion = "1.0.0.0" }, + @{ModuleName = "PSReadLine"} + ) +} +New-PSScriptFileInfo @parameters +Get-Content ./test_script2.ps1 ``` -PS C:\> $requiredModules = @(@{ModuleName = "PackageManagement"; ModuleVersion = "1.0.0.0" }, @{ModuleName = "PSReadLine"}) -PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script2.ps1" -Description "this is a test script" -Version "2.0.0.0" -Author "janedoe" -RequiredModules $requiredModules -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" + +```Output <#PSScriptInfo .VERSION 2.0.0.0 @@ -90,7 +118,7 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .AUTHOR janedoe -.COMPANYNAME Jane Corporation +.COMPANYNAME .COPYRIGHT @@ -102,11 +130,11 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .ICONURI -.EXTERNALMODULEDEPENDENCIES +.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS +.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES +.EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES @@ -122,30 +150,27 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" <# .DESCRIPTION -this is a test script +This is a test script. #> - -``` -This example runs the cmdlet with the required 'FilePath' and 'Description' parameters, as well as 'Author', 'Version', and 'RequiredModules' parameters. The 'RequiredModules' parameter describes modules required by the script. It is necessary to provide the ModuleName key in the hashtable and if one wishes to specify verion they must also specify ModuleVersion, RequiredVersion, MaximumVersion, or MinimumVersion keys. The script is successfully created and if the contents of the file are viewed we can see the following values are set in the script file: Description, Author, Guid, and Version and RequiredModules. +``` ## PARAMETERS ### -Author -The author of the script. +The name of the author of the script. ```yaml Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -155,14 +180,13 @@ Accept wildcard characters: False The name of the company owning the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -172,14 +196,13 @@ Accept wildcard characters: False The copyright information for the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -189,14 +212,13 @@ Accept wildcard characters: False The description of the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: True Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -206,14 +228,13 @@ Accept wildcard characters: False The list of external module dependencies taken by this script. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -223,99 +244,94 @@ Accept wildcard characters: False The list of external script dependencies taken by this script. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -FilePath -The path the .ps1 script info file will be created at. +The filename and location where the script is created. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: True Position: 0 -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Force -If used and the .ps1 file specified at the path exists, it rewrites the file. +Forces the cmdlet to overwrite any existing file. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Guid -The GUID for the script. +The unique identifier for the script in GUID format. If you don't provide a GUID, the cmdlet creates +a new one automatically. ```yaml -Type: Guid +Type: System.Guid Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: Randomly generated Accept pipeline input: False Accept wildcard characters: False ``` ### -IconUri -The Uri for the icon associated with the script. +A Uniform Resource Identifier (URI) pointing to the icon associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -LicenseUri -The Uri for the license associated with the script. +The URI pointing to the license agreement file associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -325,31 +341,29 @@ Accept wildcard characters: False The private data associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ProjectUri -The Uri for the project associated with the script. +The URI pointing to the project site associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -359,31 +373,37 @@ Accept wildcard characters: False The release notes for the script. ```yaml -Type: String[] +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -RequiredModules -The list of modules required by the script. +The parameter takes an array of module specification hashtables. A module specification is a +hashtable that has the following keys. + +- **ModuleName** - Required Specifies the module name. +- **GUID** - Optional Specifies the GUID of the module. +- One of these three version key is Required. These keys can't be used together. + - **ModuleVersion** - Specifies a minimum acceptable version of the module. + - **RequiredVersion** - Specifies an exact, required version of the module. + - **MaximumVersion** - Specifies the maximum acceptable version of the module. ```yaml -Type: Hashtable[] +Type: System.Collections.Hashtable[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -393,67 +413,75 @@ Accept wildcard characters: False The list of scripts required by the script. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: -Required: True (None) False (All) +Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Tags -The tags associated with the script. +The tags associated with the script. Tag values are strings that should not contain spaces. For more +information, see [Tag details][1]. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: -Required: True (None) False (All) +Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Version -The version of the script. +The version of the script. If no value is provided **Version** defaults to `1.0.0.0`. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: -Required: True (None) False (All) +Required: False Position: Named -Default value: +Default value: 1.0.0.0 Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ### None - - ## OUTPUTS -### None +### System.Object ## NOTES ## RELATED LINKS +[PowerShellGallery Publishing Guidelines and Best Practices][2] + +[Package manifest values that impact the PowerShell Gallery UI][3] + + + +[1]: /powershell/scripting/gallery/concepts/package-manifest-affecting-ui#tag-details +[2]: /powershell/scripting/gallery/concepts/publishing-guidelines +[3]: /powershell/scripting/gallery/concepts/package-manifest-affecting-ui diff --git a/help/PowerShellGet.md b/help/PowerShellGet.md index 548aaf5ab..fe3f5e99f 100644 --- a/help/PowerShellGet.md +++ b/help/PowerShellGet.md @@ -1,46 +1,64 @@ --- -Module Name: PowerShellGet -Module Guid: 1d73a601-4a6c-43c5-ba3f-619b18bbb404 -Download Help Link: {{ Update Download Link }} -Help Version: {{ Please enter version of help manually (X.X.X.X) format }} +Download Help Link: https://aka.ms/powershell73-help +Help Version: 3.0.16 Locale: en-US +Module Guid: 1d73a601-4a6c-43c5-ba3f-619b18bbb404 +Module Name: PowerShellGet +ms.date: 08/03/2022 --- # PowerShellGet Module ## Description -{{ Fill in the Description }} +PowerShellGet is a module with commands for discovering, installing, updating and publishing +PowerShell artifacts like Modules, DSC Resources, Role Capabilities, and Scripts. + +This documentation covers the latest preview version PowerShellGet v3. ## PowerShellGet Cmdlets ### [Find-PSResource](Find-PSResource.md) -{{ Fill in the Description }} +Searches for packages from a repository (local or remote), based on a name or other package properties. ### [Get-PSResource](Get-PSResource.md) -{{ Fill in the Description }} +Returns modules and scripts installed on the machine via **PowerShellGet**. ### [Get-PSResourceRepository](Get-PSResourceRepository.md) -{{ Fill in the Description }} +Finds and returns registered repository information. ### [Install-PSResource](Install-PSResource.md) +Installs resources from a registered repository. + +### [New-PSScriptFileInfo](New-PSScriptFileInfo.md) +The cmdlet creates a new script file, including metadata about the script. + +### [PowerShellGet](PowerShellGet.md) {{ Fill in the Description }} ### [Publish-PSResource](Publish-PSResource.md) -{{ Fill in the Description }} +Publishes a specified module from the local computer to PSResource repository. ### [Register-PSResourceRepository](Register-PSResourceRepository.md) -{{ Fill in the Description }} +Registers a repository for PowerShell resources. ### [Save-PSResource](Save-PSResource.md) -{{ Fill in the Description }} +Saves resources (modules and scripts) from a registered repository onto the machine. ### [Set-PSResourceRepository](Set-PSResourceRepository.md) -{{ Fill in the Description }} +Sets information for a registered repository. + +### [Test-PSScriptFileInfo](Test-PSScriptFileInfo.md) +Tests the comment-based metadata in a `.ps1` file to ensure it's valid for publication. ### [Uninstall-PSResource](Uninstall-PSResource.md) -{{ Fill in the Description }} +Uninstalls a resource that was installed using **PowerShellGet**. ### [Unregister-PSResourceRepository](Unregister-PSResourceRepository.md) -{{ Fill in the Description }} +Removes a registered repository from the local machine. + +### [Update-ModuleManifest](Update-ModuleManifest.md) +Updates a module manifest file. ### [Update-PSResource](Update-PSResource.md) -{{ Fill in the Description }} +Downloads and installs the newest version of a package already installed on the local machine. +### [Update-PSScriptFileInfo](Update-PSScriptFileInfo.md) +This cmdlet updates the comment-based metadata in an existing script `.ps1` file. diff --git a/help/Publish-PSResource.md b/help/Publish-PSResource.md index 22d95ea50..4bf3bc1c7 100644 --- a/help/Publish-PSResource.md +++ b/help/Publish-PSResource.md @@ -1,7 +1,8 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- @@ -13,35 +14,41 @@ Publishes a specified module from the local computer to PSResource repository. ## SYNTAX ``` -Publish-PSResource [-APIKey ] [-Repository ] [-Path] [-DestinationPath] - [-Credential ] [-SkipDependenciesCheck] - [-WhatIf] [-Confirm] [] +Publish-PSResource -Path [-ApiKey ] [-Repository ] + [-DestinationPath ] [-Credential ] [-SkipDependenciesCheck] [-Proxy ] + [-ProxyCredential ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. -It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. -You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. + +This cmdlet combines the functions of the `Publish-Module` and `Publish-Script` cmdlets from +**PowerShellGet** v2. `Publish-PSResource` publishes a resource from the local computer to an online +Nuget-based repository. You can specify the resource by the resource's name or by the path +containing the module or script resource. ## EXAMPLES ### Example 1 + +This example publishes the module **TestModule** to the repository registered with highest priority. + ```powershell -PS C:\> Publish-PSResource -Path c:\Test-Module +Publish-PSResource -Path c:\TestModule ``` -This will publish the module 'Test-Module' to the highest priority repository - ### Example 2 + +This example publishes the module **TestModule** to the PowerShell Gallery. The API key is a secret +that is generated by the PowerShell Gallery for a user account. + ```powershell -PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' +Publish-PSResource -Path c:\TestModule -Repository PSGallery -APIKey '1234567' ``` -This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. - ## PARAMETERS -### -APIKey +### -ApiKey + Specifies the API key that you want to use to publish a resource to the online gallery. ```yaml @@ -56,8 +63,27 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Repository -Specifies the repository to publish to. +### -Credential + +Specifies a user account that has rights to a specific repository. + +```yaml +Type: System.Management.Automation.PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -DestinationPath + +Specifies the path where the NuGet package `.nupkg` file should be saved. This parameter can be used +in conjunction with the **Repository** parameter to publish to a repository and also save the exact +same package to the local file system. ```yaml Type: System.String @@ -72,7 +98,9 @@ Accept wildcard characters: False ``` ### -Path -When specified, includes prerelease versions in search. + +The path to the module or script file or the path to a folder containing the module or script file +to be published. ```yaml Type: System.String @@ -86,23 +114,25 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -DestinationPath -Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. +### -Proxy + +The URL to a proxy server used to access repositories outside of your network. ```yaml -Type: System.String +Type: System.Uri Parameter Sets: (All) Aliases: -Required: True +Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` -### -Credential -Specifies a user account that has rights to a specific repository (used for finding dependencies). +### -ProxyCredential + +The credentials required to use the proxy server. ```yaml Type: System.Management.Automation.PSCredential @@ -116,8 +146,25 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Repository + +Specifies the repository to publish to. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -SkipDependenciesCheck -Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + +Bypasses the default check that all dependencies are present in the target repository. ```yaml Type: System.Management.Automation.SwitchParameter @@ -126,12 +173,13 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml @@ -141,14 +189,14 @@ Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml Type: System.Management.Automation.SwitchParameter @@ -157,15 +205,21 @@ Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## NOTES -## RELATED LINKS +Fileshare-based repository have no metadata about the resources. Therefore, there is no way to check +for dependencies. +## RELATED LINKS diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index 9c7d3ac90..a0b52ae53 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -1,7 +1,8 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- @@ -13,71 +14,142 @@ Registers a repository for PowerShell resources. ## SYNTAX ### NameParameterSet (Default) + ``` -Register-PSResourceRepository [-Name ] [-Uri ] [CredentialInfo ] [-Trusted] [-Priority ] [-PassThru] +Register-PSResourceRepository [-Name] [-Uri] [-Trusted] [-Priority ] + [-CredentialInfo ] [-Proxy ] [-ProxyCredential ] [-PassThru] [-WhatIf] [-Confirm] [] ``` ### PSGalleryParameterSet + ``` -Register-PSResourceRepository [-PSGallery] [-Trusted] [-Priority ] [-PassThru] [-WhatIf] [-Confirm] - [] +Register-PSResourceRepository -PSGallery [-Trusted] [-Priority ] [-Proxy ] + [-ProxyCredential ] [-PassThru] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet + ``` -Register-PSResourceRepository -Repository [-PassThru] [-WhatIf] [-Confirm] [] +Register-PSResourceRepository -Repository [-Proxy ] + [-ProxyCredential ] [-PassThru] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. + +The cmdlet registers a NuGet repository containing PowerShell resources. ## EXAMPLES ### Example 1 -``` -PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + +This example registers the repository with the **Name** of `PoshTestGallery`. + +```powershell +Register-PSResourceRepository -Name PoshTestGallery -Uri "https://www.powershellgallery.com/api/v2" +Get-PSResourceRepository -Name PoshTestGallery ``` -This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +``` ### Example 2 -``` -PS C:\> Register-PSResourceRepository -PSGallery -PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 + +This example registers the default `PSGallery` repository. Unlike the previous example, we can't use +the **Name** and **Uri** parameters to register the `PSGallery` repository. The `PSGallery` +repository is registered by default but can be removed. Use this command to restore the default +registration. + +```powershell +Register-PSResourceRepository -PSGallery +Get-PSResourceRepository -Name "PSGallery" ``` -This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +``` ### Example 3 + +This example registers multiple repositories at once. To do so, we use the **Repository** parameter +and provide an array of hashtables. Each hashtable can only have keys associated with parameters for +the **NameParameterSet** or the **PSGalleryParameterSet**. + +```powershell +$arrayOfHashtables = @{Name = "Local"; Uri = "D:/PSRepoLocal/"; Trusted = $true; Priority = 20 }, + @{Name = "PSGv3"; Uri = "https://www.powershellgallery.com/api/v3"; Trusted = $true; Priority = 50 }, + @{PSGallery = $true; Trusted = $true; Priority = 10 } +Register-PSResourceRepository -Repository $arrayOfHashtables +Get-PSResourceRepository ``` -PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} -PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir False 50 +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +psgettestlocal file:///c:/code/testdir False 50 ``` -This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. +### Example 4 + +This example registers a repository with credential information to be retrieved from a registered +**Microsoft.PowerShell.SecretManagement** vault. You must have the +**Microsoft.PowerShell.SecretManagement** module install and have a registered vault containing the +stored secret. The format of the secret must match the requirements of the repository. + +```powershell +$parameters = @{ + Name = "PSGv3" + Uri = "https://www.powershellgallery.com/api/v3" + Trusted = $true + Priority = 50 + CredentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ('SecretStore', 'TestSecret') +} +Register-PSResourceRepository @parameters +Get-PSResourceRepository | Select-Object * -ExpandProperty CredentialInfo +``` + +```Output +Name : PSGv3 +Uri : https://www.powershellgallery.com/api/v3 +Trusted : True +Priority : 50 +CredentialInfo : Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo +VaultName : SecretStore +SecretName : TestSecret +Credential : +``` ## PARAMETERS +### -CredentialInfo + +A **PSCredentialInfo** object that includes the name of a vault and a secret that is stored in a +**Microsoft.PowerShell.SecretManagement** store. + +```yaml +Type: PSCredentialInfo +Parameter Sets: NameParameterSet +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Name -Name of the repository to be registered. -Cannot be "PSGallery". + +Name of the repository to be registered. Can't be `PSGallery`. ```yaml -Type: String +Type: System.String Parameter Sets: NameParameterSet Aliases: @@ -88,12 +160,31 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -PassThru + +When specified, displays the successfully registered repository and its information. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Priority -Specifies the priority ranking of the repository. -Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + +Specifies the priority ranking of the repository. Valid priority values range from 0 to 50. Lower +values have a higher priority ranking. The default value is `50`. + +Repositories are searched in priority order (highest first). ```yaml -Type: Int32 +Type: System.Int32 Parameter Sets: NameParameterSet, PSGalleryParameterSet Aliases: @@ -104,11 +195,44 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Proxy + +The URL to a proxy server used to access repositories outside of your network. + +```yaml +Type: System.Uri +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ProxyCredential + +The credentials required to use the proxy server. + +```yaml +Type: System.Management.Automation.PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -PSGallery -When specified, registers PSGallery repository. + +When specified, registers **PSGallery** repository. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: PSGalleryParameterSet Aliases: @@ -120,26 +244,30 @@ Accept wildcard characters: False ``` ### -Repository -Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + +Specifies an array of hashtables that contain repository information. Use this parameter to register +multiple repositories at once. Each hashtable can only have keys associated with parameters for +the **NameParameterSet** or the **PSGalleryParameterSet**. ```yaml -Type: Hashtable[] +Type: System.Collections.Hashtable[] Parameter Sets: RepositoriesParameterSet Aliases: Required: True Position: Named Default value: None -Accept pipeline input: True (ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` ### -Trusted + Specifies whether the repository should be trusted. ```yaml -Type: SwitchParameter -Parameter Sets: (All) +Type: System.Management.Automation.SwitchParameter +Parameter Sets: NameParameterSet, PSGalleryParameterSet Aliases: Required: False @@ -150,44 +278,33 @@ Accept wildcard characters: False ``` ### -Uri -Specifies the location of the repository to be registered. -Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. -```yaml -Type: String -Parameter Sets: NameParameterSet -Aliases: - -Required: True -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` -### -CredentialInfo -Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. -Takes a PSCredentialInfo Objects which takes in a vault name and secret name. -This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. +Specifies the location of the repository to be registered. The value must use one of the following +URI schemas: -`New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` +- `https://` +- `http://` +- `ftp://` +- `file://` ```yaml -Type: PSCredentialInfo +Type: System.String Parameter Sets: NameParameterSet Aliases: -Required: False -Position: Named +Required: True +Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: cf @@ -199,11 +316,11 @@ Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: wi @@ -214,23 +331,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -PassThru -When specified, displays the succcessfully registered repository and its information. - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS @@ -238,13 +344,16 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## OUTPUTS -### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo -## NOTES -Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. +By default, the cmdlet produces no output. When you use the **PassThru** parameter, the cmdlet +returns a **PSRepositoryInfo** object. -Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). +## NOTES -Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File +Repositories are unique by **Name**. Attempting to register a repository with same name results in +an error. ## RELATED LINKS + +[Microsoft.PowerShell.SecretManagement](/powershell/utility-modules/secretmanagement/overview) diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 0d80b2298..2029fb6d4 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -1,7 +1,8 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- @@ -13,94 +14,108 @@ Saves resources (modules and scripts) from a registered repository onto the mach ## SYNTAX ### NameParameterSet + ``` -Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXml] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] +Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] + [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] + [-PassThru] [-SkipDependencyCheck] [-AuthenticodeCheck] [-Quiet] [-WhatIf] [-Confirm] + [] ``` ### InputObjectParameterSet + ``` -Save-PSResource [-InputObject] [-Credential ] [-AsNupkg] - [-IncludeXml] [-Path ] [-TrustRepository] [-SkipDependencyCheck] [-PassThru] [-Quiet] [-WhatIf] [-Confirm] [] +Save-PSResource [-InputObject] [-Credential ] [-AsNupkg] + [-IncludeXML] [-Path ] [-TrustRepository] [-PassThru] [-SkipDependencyCheck] + [-AuthenticodeCheck] [-Quiet] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. -It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. + +This cmdlet combines the functionality of the `Save-Module` and `Save-Script` cmdlets from +**PowerShellGet** v2. `Save-PSResource` downloads a resource from a registered repository to a +specific path on the local machine. By default, the resource is saved in the unpacked or installed +format. The scripts or modules could be run from the saved location. There is also an option to +download the resource in `.nupkg` format. ## EXAMPLES ### Example 1 + +Downloads the **Az** module from the highest priority repository and saves it to the current +location. + ```powershell -PS C:\> Save-PSResource -Name Az +Save-PSResource -Name Az ``` -Saves the Az module ### Example 2 + +Downloads the **Az** module from the PowerShell Gallery and saves it to the current location. + ```powershell -PS C:\> Save-PSResource -Name Az -Repository PSGallery +Save-PSResource -Name Az -Repository PSGallery ``` -Saves the Az module found in the PowerShellGallery ### Example 3 + +Downloads the **Az** module from the highest priority repository and saves it in `.nupkg` format to +the current location. + ```powershell -PS C:\> Save-PSResource Az -AsNupkg +Save-PSResource Az -AsNupkg ``` -Saves the Az module as a .nupkg file ### Example 4 + +Downloads the **Az** module from the highest priority repository and includes the **PowerShellGet** +XML metadata file. + ```powershell -PS C:\> Save-PSResource Az -IncludeXml +Save-PSResource Az -IncludeXML ``` -Saves the Az module and includes the PowerShellGet XML metadata ## PARAMETERS -### -Name -Name of a resource or resources to save. Does not accept wildcard characters or a null value. +### -AsNupkg + +Saves the resource as a `.nupkg` file. ```yaml -Type: System.String[] -Parameter Sets: NameParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: -Required: True -Position: 0 -Default value: None -Accept pipeline input: True (ByValue) +Required: False +Position: Named +Default value: False +Accept pipeline input: False Accept wildcard characters: False ``` -### -Version -Specifies the version of the resource to be saved. The value can be an exact version or a version -range using the NuGet versioning syntax. - -For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) +### -AuthenticodeCheck -PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range -documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher -(minimum inclusive range). Instead, the values is considered as the required version and yields -version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as -the version range. +Validates the resource's signed files and catalog files on Windows. ```yaml -Type: System.String -Parameter Sets: NameParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Prerelease -Specifies to include prerelease versions. +### -Credential + +Optional credentials used when accessing a repository. ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Type: System.Management.Automation.PSCredential +Parameter Sets: (All) Aliases: Required: False @@ -110,53 +125,58 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Repository -Specifies one or more repository names to search. -If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. +### -IncludeXML + +Includes the **PowerShellGet** metadata XML used to verify that **PowerShellGet** has installed a +module. ```yaml -Type: System.String[] -Parameter Sets: NameParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Credential -Optional credentials to be used when accessing a repository. +### -InputObject + +Used for pipeline input. ```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: (All) +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Parameter Sets: InputObjectParameterSet Aliases: -Required: False +Required: True Position: Named Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` -### -AsNupkg -Saves the resource as a zipped .nupkg file. +### -Name + +The name of one or more resources to install. + ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Type: System.String[] +Parameter Sets: NameParameterSet Aliases: -Required: False -Position: Named +Required: True +Position: 0 Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` -### -IncludeXml -Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). +### -PassThru + +When specified, outputs a **PSResourceInfo** object for the saved resource. ```yaml Type: System.Management.Automation.SwitchParameter @@ -165,13 +185,15 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Path -Specifies the path to save the resource to. + +Specifies the path to save the resource to. If no path is provided, the resource is saved to the +current location. ```yaml Type: System.String @@ -181,71 +203,84 @@ Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) +Accept pipeline input: False Accept wildcard characters: False ``` -### -TrustRepository -Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. +### -Prerelease + +When specified, includes prerelease versions in search results returned. ```yaml Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -AuthenticodeCheck -Does a check to to validate signed files and catalog files on Windows. + +### -Quiet + +Supresses progress information. ```yaml Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: +Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -PassThru -Passes the resource saved to the console. +### -Repository + +Specifies one or more repository names to search. Wildcards are supported. + +If not specified, search includes all registered repositories, in priority order (highest first), +until a repository is found that contains the package. + +Lower **Priority** values have a higher precedence. ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) +Type: System.String[] +Parameter Sets: NameParameterSet Aliases: Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -SkipDependencyCheck -Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + +Skips the check for resource dependencies. Only found resources are installed. No resources of the +found resource are installed. ```yaml Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: +Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Quiet -Supresses progress information. +### -TrustRepository + +Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository +isn't configured as trusted. ```yaml Type: System.Management.Automation.SwitchParameter @@ -254,18 +289,28 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -InputObject -Used for pipeline input. +### -Version + +Specifies the version of the resource to be returned. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see +[Package versioning](/nuget/concepts/package-versioning#version-ranges). + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum +inclusive range). Instead, the value is considered to be the required version. To search for a +minimum inclusive range, use `[1.0.0.0, ]` as the version range. ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo -Parameter Sets: (All) -Aliases: wi +Type: System.String +Parameter Sets: NameParameterSet +Aliases: Required: False Position: Named @@ -275,6 +320,7 @@ Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml @@ -284,14 +330,14 @@ Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml Type: System.Management.Automation.SwitchParameter @@ -300,16 +346,27 @@ Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS +## OUTPUTS + +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + +By default, the cmdlet doesn't return any objects. When the **PassThru** parameter is used, the +cmdlet outputs a **PSResourceInfo** object for the saved resource. + ## NOTES ## RELATED LINKS diff --git a/help/Set-PSResourceRepository.md b/help/Set-PSResourceRepository.md index 658cb9174..1027234be 100644 --- a/help/Set-PSResourceRepository.md +++ b/help/Set-PSResourceRepository.md @@ -1,6 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet +ms.date: 08/03/2022 online version: schema: 2.0.0 --- @@ -13,71 +14,159 @@ Sets information for a registered repository. ## SYNTAX ### NameParameterSet (Default) + ``` -Set-PSResourceRepository [-Name] [-Uri ][CredentialInfo ] [-Trusted] [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository [-Name] [-Uri ] [-Trusted] [-Priority ] + [-CredentialInfo ] [-PassThru] [-WhatIf] [-Confirm] [] ``` ### RepositoriesParameterSet + ``` -Set-PSResourceRepository -Repository [-Priority ] [-WhatIf] [-Confirm] [] +Set-PSResourceRepository -Repository [-PassThru] [-WhatIf] [-Confirm] + [] ``` ## DESCRIPTION + The Set-PSResourceRepository cmdlet sets information for a registered repository. ## EXAMPLES ### Example 1 + +In this example, the **Uri** for the **PoshTestGallery** repository has been registered. The +`Set-PSResourceRepository` cmdlet is used to change the **Uri** to a local path. The **PassThru** +parameter allows you to see the changed repository. + +```powershell +Get-PSResourceRepository -Name "PoshTestGallery" +``` + +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +``` + ```powershell -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery file:///c:/code/testdir False 50 +Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru ``` -This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery file:///c:/code/testdir False 50 +``` ### Example 2 + +This example changes the **Priority** and **Trusted** values of the repository. were changed. + +> [!NOTE] +> The **Uri** value of the default **PSGallery** repository can't be changed. + ```powershell -PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 True 25 +Get-PSResourceRepository -Name "PSGallery" +``` + +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 + +Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru ``` -This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 25 +``` ### Example 3 + +This example uses the **Repository** parameter to change values for multiple respositories. The +parameter takes an array of hashtables. Each hashtable contains information the repository being +updated. + ```powershell -PS C:\> Get-PSResourceRepository -Name "*" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +Get-PSResourceRepository +``` -PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 +``` -PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 True 50 - PoshTestGallery file:///c:/code/testdir False 50 +```powershell +$arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, + @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} +Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru ``` -This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 50 +PoshTestGallery file:///c:/code/testdir False 50 +``` + +### Example 4 + +This example updates a repository with credential information to be retrieved from a registered +**Microsoft.PowerShell.SecretManagement** vault. You must have the +**Microsoft.PowerShell.SecretManagement** module install and have a registered vault containing the +stored secret. The format of the secret must match the requirements of the repository. + +```powershell +$parameters = @{ + Name = "PoshTestGallery" + Uri = "c:/code/testdir" + CredentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ('SecretStore', 'TestSecret') +} +Set-PSResourceRepository @parameters -PassThru | Select-Object * -ExpandProperty CredentialInfo +``` + +```Output +Name : PoshTestGallery +Uri : file:///c:/code/testdir +Trusted : False +Priority : 50 +CredentialInfo : Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo +VaultName : SecretStore +SecretName : TestSecret +Credential : +``` ## PARAMETERS +### -CredentialInfo + +A **PSCredentialInfo** object that includes the name of a vault and a secret that is stored in a +**Microsoft.PowerShell.SecretManagement** store. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo +Parameter Sets: NameParameterSet +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Name -Specifies the name of the repository to be set. + +Specifies the name of the repository to be modified. + +> [!NOTE] +> The **Uri** value of the default **PSGallery** repository can't be changed. + ```yaml Type: System.String @@ -87,30 +176,35 @@ Aliases: Required: True Position: 0 Default value: None -Accept pipeline input: True (ByValue) +Accept pipeline input: True (ByValue, ByPropertyName) Accept wildcard characters: False ``` -### -Priority -Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). +### -PassThru + +When specified, displays the successfully registered repository and its information. ```yaml -Type: System.Int32 +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Trusted -Specifies whether the repository should be trusted. +### -Priority + +Specifies the priority ranking of the repository. Valid priority values range from 0 to 50. Lower +values have a higher priority ranking. The default value is `50`. + +Repositories are searched in priority order (highest first). ```yaml -Type: System.Management.Automation.SwitchParameter +Type: System.Int32 Parameter Sets: NameParameterSet Aliases: @@ -121,46 +215,54 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Uri -Specifies the location of the repository to be set. +### -Repository + +Specifies an array of hashtables that contain repository information. Use this parameter to register +multiple repositories at once. Each hashtable can only have keys associated with parameters for +the **NameParameterSet**. ```yaml -Type: String -Parameter Sets: NameParameterSet +Type: System.Collections.Hashtable[] +Parameter Sets: RepositoriesParameterSet Aliases: -Required: False +Required: True Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` -### -CredentialInfo -Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. -Takes a PSCredentialInfo Objects which takes in a vault name and secret name. -This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. -`New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` +### -Trusted + +Specifies whether the repository should be trusted. ```yaml -Type: PSCredentialInfo +Type: System.Management.Automation.SwitchParameter Parameter Sets: NameParameterSet Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -PassThru -When specified, displays the succcessfully registered repository and its information +### -Uri + +Specifies the location of the repository to be registered. The value must use one of the following +URI schemas: + +- `https://` +- `http://` +- `ftp://` +- `file://` ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: (All) -Aliases: cf +Type: System.String +Parameter Sets: NameParameterSet +Aliases: Required: False Position: Named @@ -170,6 +272,7 @@ Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml @@ -179,14 +282,14 @@ Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml Type: System.Management.Automation.SwitchParameter @@ -195,13 +298,17 @@ Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS @@ -211,8 +318,13 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## OUTPUTS -### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo + +By default, the cmdlet produces no output. When you use the **PassThru** parameter, the cmdlet +returns a **PSRepositoryInfo** object. ## NOTES ## RELATED LINKS + +[Microsoft.PowerShell.SecretManagement](/powershell/utility-modules/secretmanagement/overview) diff --git a/help/Test-PSScriptFileInfo.md b/help/Test-PSScriptFileInfo.md index fb906a964..d05281d09 100644 --- a/help/Test-PSScriptFileInfo.md +++ b/help/Test-PSScriptFileInfo.md @@ -1,91 +1,56 @@ --- external help file: PowerShellGet-help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- - # Test-PSScriptFileInfo ## SYNOPSIS - -Tests a .ps1 file at the specified path to ensure it is valid. +Tests the comment-based metadata in a `.ps1` file to ensure it's valid for publication. ## SYNTAX -### AllParameterSets +### __AllParameterSets ``` -Test-PSScriptFileInfo [-FilePath] [] +Test-PSScriptFileInfo [-FilePath] [] ``` ## DESCRIPTION -The Test-PSScriptFileInfo cmdlet tests a .ps1 file at the specified path to ensure it is valid. +This cmdlet tests the comment-based metadata in a `.ps1` file to ensure it's valid for publication +to a repository. ## EXAMPLES ### Example 1: Test a valid script -``` -PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Description "this is a test script" -PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -True -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" -<#PSScriptInfo - -.VERSION 1.0.0.0 - -.GUID 6ec3934e-a2e0-495b-9a9c-480e555ad1d1 - -.AUTHOR johndoe - -.COMPANYNAME - -.COPYRIGHT - -.TAGS - -.LICENSEURI - -.PROJECTURI - -.ICONURI - -.EXTERNALMODULEDEPENDENCIES - -.REQUIREDSCRIPTS - -.EXTERNALSCRIPTDEPENDENCIES - -.RELEASENOTES - - -.PRIVATEDATA - - -#> - -<# - -.DESCRIPTION -this is a test script - - -#> +This example creates a new script file then runs `Test-PSScriptFileInfo` to validate the metadata +in the script. +```powershell +New-PSScriptFileInfo -FilePath "C:\MyScripts\test_script.ps1" -Description "this is a test script" +Test-PSScriptFileInfo -FilePath "C:\MyScripts\test_script.ps1" +True ``` -Assume that the script file specified was created by the New-PSScriptFileInfo cmdlet prior to this example and is valid. This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is a valid script the cmdlet outputs "True". To see what this valid script looks like we can see the contents of the file. - ### Example 2: Test an invalid script (missing Author) +This example runs the `Test-PSScriptFileInfo` cmdlet against a script file. The script is missing +the required **Author** metadata. The cmdlet writes a warning message and returns `$false`. +`Get-Content` is used to view the contents of the script file. + +```powershell +Test-PSScriptFileInfo -FilePath "C:\MyScripts\invalid_test_script.ps1" +Get-Content "C:\MyScripts\invalid_test_script.ps1" ``` -PS C:\> Test-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\invalid_test_script.ps1" -WARNING: The .ps1 script file passed in was not valid due to: PSScript file is missing the required Author property -False -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" +```Output +WARNING: The .ps1 script file passed in was not valid due to: PSScript file is missing the required +Author property +False <#PSScriptInfo .VERSION 1.0.0.0 @@ -106,18 +71,16 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .ICONURI -.EXTERNALMODULEDEPENDENCIES +.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS +.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES +.EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES - .PRIVATEDATA - #> <# @@ -125,48 +88,44 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .DESCRIPTION this is a test script - #> - ``` -This example runs the Test-PSScriptFileInfo cmdlet against a script located at the path provided to the 'FilePath' parameter. Since the script is not a valid script and is missing the required Author metadata property, the cmdlet writes an informative warning message and outputs "False". To see what this invalid script looks like we can see the contents of the file. - - ## PARAMETERS ### -FilePath -The path that the .ps1 script info file which is to be tested is located at. +The path to `.ps1` script file. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: True Position: 0 -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ### None - - ## OUTPUTS -## NOTES +### System.Boolean +## NOTES ## RELATED LINKS +[New-PSScriptFileInfo](New-PSScriptFileInfo.md) diff --git a/help/Uninstall-PSResource.md b/help/Uninstall-PSResource.md index ba8b0073a..466f70ae8 100644 --- a/help/Uninstall-PSResource.md +++ b/help/Uninstall-PSResource.md @@ -1,6 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet +ms.date: 08/03/2022 online version: schema: 2.0.0 --- @@ -8,68 +9,115 @@ schema: 2.0.0 # Uninstall-PSResource ## SYNOPSIS -Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. +Uninstalls a resource that was installed using **PowerShellGet**. ## SYNTAX -### NameParameterSet +### NameParameterSet (Default) + ``` -Uninstall-PSResource [-Name] [-Version ] [-Scope ] [-SkipDependencyCheck] [-WhatIf] [] +Uninstall-PSResource [-Name] [-Version ] [-Prerelease] [-SkipDependencyCheck] + [-Scope ] [-WhatIf] [-Confirm] [] ``` ### InputObjectParameterSet + ``` -Uninstall-PSResource [-InputObject] [-SkipDependencyCheck] [-WhatIf] [] +Uninstall-PSResource [-InputObject] [-Prerelease] [-SkipDependencyCheck] + [-Scope ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. -It uninstalls a package found in a module or script installation path based on the -Name parameter argument. -It does not return an object. -Other parameters allow the returned results to be further filtered. + +This cmdlet combines the functionality of the `Uninstall-Module` and `Uninstall-Script` cmdlets from +**PowerShellGet** v2. The cmdlet searches the package installation paths for resources that have the +**PowerShellGet** XML metadata file. Matching resources are uninstalled from the system. + +By default, the cmdlet checks to see whether the resource being removed is a dependency for another +resource. ## EXAMPLES ### Example 1 + +Uninstall the latest version of the **Az** module. + ```powershell -PS C:\> Uninstall-PSResource Az +Uninstall-PSResource Az ``` -Uninstalls the latest version of the Az module. - ### Example 2 + +Uninstall a specific version of the **Az** module. + ```powershell -PS C:\> Uninstall-PSResource -name Az -version "1.0.0" +Uninstall-PSResource -name Az -version "5.0.0" ``` -Uninstalls version 1.0.0 of the Az module. - ### Example 3 + +Uninstalls all versions of the **Az** module within the specified version range. + ```powershell -PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" +Uninstall-PSResource -name Az -version "(5.0.0, 7.5.0)" ``` -Uninstalls all versions within the specified version range. - ### Example 4 + +This example assumes that the following versions of **Az** module are already installed: + +- 4.0.1-preview +- 4.1.0 +- 4.0.2-preview + +The `Uninstall-PSResource` cmdlet removes stable and prerelease version that fall within the version +range specified. Per NuGetVersion rules, a prerelease version is less than a stable version, so +4.0.1-preview is actually less than the 4.0.1 version in the specified range. Therefore, +4.0.1-preview isn't removed. Versions 4.1.0 and 4.0.2-preview are removed because they fall within +the range. + ```powershell -PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" +Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" ``` -Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. +### Example 5 + +This example assumes that the following versions of **Az** module are already installed: + +- 4.0.1-preview +- 4.1.0 +- 4.0.2-preview + +This is the same as the previous example except the **Prerelease** parameter means that only +prerelease versions are removed. Only version 4.0.2-preview is removed because version 4.0.1-preview +is outside the range and version 4.1.0 isn't a prerelease version. -### Example 4 ```powershell -PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease +Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease ``` -Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. +## PARAMETERS +### -InputObject -## PARAMETERS +Used for pipeline input. + +```yaml +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Parameter Sets: InputObjectParameterSet +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` ### -Name -Name of a resource or resources that has been installed. Accepts wild card characters. + +Name of a resource or resources to remove. Wildcards are supported but NuGet only accepts the `*` +character. ```yaml Type: System.String[] @@ -83,22 +131,24 @@ Accept pipeline input: True (ByValue) Accept wildcard characters: True ``` -### -Version -Specifies the version of the resource to be uninstalled. +### -Prerelease + +Indicates that only prerelease version resources should be removed. ```yaml -Type: System.String -Parameter Sets: NameParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None -Accept pipeline input: True +Accept pipeline input: False Accept wildcard characters: False ``` ### -Scope + Specifies the scope of the resource to uninstall. ```yaml @@ -115,13 +165,40 @@ Accept wildcard characters: False ``` ### -SkipDependencyCheck -Skips check to see if other resources are dependent on the resource being uninstalled. + +By default, the cmdlet checks to see whether the resource being removed is a dependency for another +resource. Using this parameter skips the dependency test. ```yaml Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Version + +Specifies the version of the resource to be removed. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see +[Package versioning](/nuget/concepts/package-versioning#version-ranges). + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum +inclusive range). Instead, the value is considered to be the required version. To search for a +minimum inclusive range, use `[1.0.0.0, ]` as the version range. + +```yaml +Type: System.String +Parameter Sets: NameParameterSet +Aliases: + Required: False Position: Named Default value: None @@ -129,13 +206,14 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -InputObject -Used for pipeline input. +### -Confirm + +Prompts you for confirmation before running the cmdlet. ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: wi +Aliases: cf Required: False Position: Named @@ -145,8 +223,8 @@ Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml Type: System.Management.Automation.SwitchParameter @@ -155,14 +233,26 @@ Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS ## NOTES ## RELATED LINKS + +[Package versioning](/nuget/concepts/package-versioning#version-ranges) + +[Install-PSResource](Install-PSResource.md) diff --git a/help/Unregister-PSResourceRepository.md b/help/Unregister-PSResourceRepository.md index d20f31944..c207918da 100644 --- a/help/Unregister-PSResourceRepository.md +++ b/help/Unregister-PSResourceRepository.md @@ -1,64 +1,95 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- # Unregister-PSResourceRepository ## SYNOPSIS -Un-registers a repository from the repository store. +Removes a registered repository from the local machine. ## SYNTAX -### NameParameterSet +### __AllParameterSets + ``` -Unregister-PSResourceRepository [-Name] [-PassThru][-WhatIf] [-Confirm] [] +Unregister-PSResourceRepository [-Name] [-PassThru] [-WhatIf] [-Confirm] + [] ``` ## DESCRIPTION -The Unregister-PSResourceRepository cmdlet unregisters a repository. + +The cmdlet removes a registered repository from the the local machine. ## EXAMPLES ### Example 1 + +In this example removes the `PSGv3` repository from the local machine. + +```powershell +Get-PSResourceRepository ``` -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" -PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" -PS C:\> +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 10 +Local file:///D:/PSRepoLocal/ True 20 +PSGv3 https://www.powershellgallery.com/api/v3 True 50 ``` -In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. +```powershell +Unregister-PSResourceRepository -Name PSGv3 +Get-PSResourceRepository +``` + +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 10 +Local file:///D:/PSRepoLocal/ True 20 +``` ### Example 2 + +This example shows how to remove multiple registered repositories in a single command. The **Name** +parameter accepts an array containing the names of the repositories to remove. + +```powershell +Get-PSResourceRepository ``` -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir True 50 - -PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 +psgettestlocal file:///c:/code/testdir True 50 ``` -In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. +```powershell +Unregister-PSResourceRepository -Name PoshTestGallery, psgettestlocal +Get-PSResourceRepository +``` + +```Output +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +``` ## PARAMETERS ### -Name -This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + +The name of one or more repositories to remove. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) Aliases: @@ -70,10 +101,11 @@ Accept wildcard characters: False ``` ### -PassThru -Passes the resource installed to the console. + +When specified, outputs a **PSRepositoryInfo** object for each repository that is removed. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: @@ -85,10 +117,11 @@ Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: cf @@ -100,11 +133,11 @@ Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: wi @@ -116,12 +149,25 @@ Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ### System.String[] +## OUTPUTS + +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo + +By default, the cmdlet doesn't return any objects. When the **PassThru** parameter is used, the +cmdlet outputs a **PSRepositoryInfo** object for each repository that is removed. + ## NOTES ## RELATED LINKS + +[Register-PSResourceRepository](Register-PSResourceRepository.md) diff --git a/help/Update-ModuleManifest.md b/help/Update-ModuleManifest.md index 034e7a881..fa92c8339 100644 --- a/help/Update-ModuleManifest.md +++ b/help/Update-ModuleManifest.md @@ -1,6 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet +ms.date: 08/03/2022 online version: schema: 2.0.0 --- @@ -12,73 +13,82 @@ Updates a module manifest file. ## SYNTAX -### NameParameterSet (Default) +### __AllParameterSets + ``` -Update-ModuleManifest [-Path] [-NestedModules ] [-Guid ] [-Author ] - [-CompanyName ] [-Copyright ] [-RootModule ] [-ModuleVersion ] - [-Description ] [-ProcessorArchitecture ] [-CompatiblePSEditions ] - [-PowerShellVersion ] [-ClrVersion ] [-DotNetFrameworkVersion ] - [-PowerShellHostName ] [-PowerShellHostVersion ] [-RequiredModules ] - [-TypesToProcess ] [-FormatsToProcess ] [-ScriptsToProcess ] - [-RequiredAssemblies ] [-FileList ] [-ModuleList ] [-FunctionsToExport ] - [-AliasesToExport ] [-VariablesToExport ] [-CmdletsToExport ] - [-DscResourcesToExport ] [-PrivateData ] [-Tags ] [-ProjectUri ] - [-LicenseUri ] [-IconUri ] [-ReleaseNotes ] [-Prerelease ] [-HelpInfoUri ] - [-DefaultCommandPrefix ] [-ExternalModuleDependencies ] [-RequireLicenseAcceptance] - [] +Update-ModuleManifest [-Path] [-NestedModules ] [-Guid ] + [-Author ] [-CompanyName ] [-Copyright ] [-RootModule ] + [-ModuleVersion ] [-Description ] [-ProcessorArchitecture ] + [-CompatiblePSEditions ] [-PowerShellVersion ] [-ClrVersion ] + [-DotNetFrameworkVersion ] [-PowerShellHostName ] + [-PowerShellHostVersion ] [-RequiredModules ] [-TypesToProcess ] + [-FormatsToProcess ] [-ScriptsToProcess ] [-RequiredAssemblies ] + [-FileList ] [-ModuleList ] [-FunctionsToExport ] + [-AliasesToExport ] [-VariablesToExport ] [-CmdletsToExport ] + [-DscResourcesToExport ] [-Tags ] [-ProjectUri ] [-LicenseUri ] + [-IconUri ] [-ReleaseNotes ] [-Prerelease ] [-HelpInfoUri ] [-PassThru] + [-DefaultCommandPrefix ] [-ExternalModuleDependencies ] + [-RequireLicenseAcceptance] [-PrivateData ] [] ``` ## DESCRIPTION -The Update-ModuleManifest cmdlet replaces the Update-ModuleManifest cmdlet from V2. -It updates a module manifest based on the `-Path` parameter argument. -It does not return an object. Other parameters allow specific properties of the manifest to be updated. + +This cmdlet updates the data stored in a module manifest file. The parameters allow you to specify +which properties get updated. `Update-ModuleManifest` overwrites any existing values in the module +manifest. + +The cmdlet doesn't return an object. ## EXAMPLES ### Example 1 + +This example changes the **Author** property in the module manifest to `New Author`. + ```powershell -PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" +Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" ``` -In this example the author property in the module manifest will be updated to "New Author". ### Example 2 +This example changes the **Prerelease** property to `beta2`. + ```powershell -PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" +Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" ``` -In this example the prerelease property will be updated to "beta2" ### Example 3 +This example updates multiple properties. + ```powershell -PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." +Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." ``` -In this example the tags and description will be updated to the passed in values. ## PARAMETERS -### -Path -Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. +### -AliasesToExport + +Specifies the aliases that the module exports. Wildcards are permitted. ```yaml -Type: String +Type: System.String[] Parameter Sets: (All) Aliases: -Required: True -Position: 0 +Required: False +Position: Named Default value: None -Accept pipeline input: True -Accept wildcard characters: False +Accept pipeline input: False +Accept wildcard characters: True ``` -### -NestedModules -Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. +### -Author -Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. +Specifies the module author. ```yaml -Type: Object[] +Type: System.String Parameter Sets: (All) Aliases: @@ -89,11 +99,13 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Guid -Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. +### -ClrVersion + +Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework +required by the module. ```yaml -Type: System.Guid +Type: System.Version Parameter Sets: (All) Aliases: @@ -104,11 +116,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Author -Specifies the module author. +### -CmdletsToExport + +Specifies the cmdlets that the module exports. Wildcards are permitted. ```yaml -Type: String +Type: System.String[] Parameter Sets: (All) Aliases: @@ -116,14 +129,15 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### -CompanyName -Specifies the company or vendor who created the module. + +Specifies the company or vendor who created the module. ```yaml -Type: String +Type: System.String Parameter Sets: (All) Aliases: @@ -134,13 +148,16 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Copyright -Specifies a copyright statement for the module. +### -CompatiblePSEditions + +Specifies the compatible **PSEditions** of the module. For information about **PSEdition**, see +[Modules with compatible PowerShell Editions](/powershell/scripting/gallery/concepts/module-psedition-support). ```yaml -Type: String +Type: System.String[] Parameter Sets: (All) Aliases: +Accepted values: Desktop, Core Required: False Position: Named @@ -149,12 +166,9 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -RootModule -Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. - -If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). +### -Copyright -To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. +Specifies a copyright statement for the module. ```yaml Type: System.String @@ -168,11 +182,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ModuleVersion -Specifies the version of the module. +### -DefaultCommandPrefix + +Specifies the default command prefix. ```yaml -Type: System.Version +Type: System.String Parameter Sets: (All) Aliases: @@ -184,6 +199,7 @@ Accept wildcard characters: False ``` ### -Description + Specifies a description of the module. ```yaml @@ -198,22 +214,14 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ProcessorArchitecture -Specifies the processor architecture that the module requires. - -The acceptable values for this parameter are: +### -DotNetFrameworkVersion -* Amd64 -* Arm -* IA64 -* MSIL -* None (unknown or unspecified) -* X86 +Specifies the minimum version of the Microsoft .NET Framework required by the module. ```yaml -Type: System.Reflection.ProcessorArchitecture +Type: System.Version Parameter Sets: (All) -Aliases: +Aliases: Required: False Position: Named @@ -222,27 +230,29 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -CompatiblePSEditions -Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support +### -DscResourcesToExport + +Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are +permitted. ```yaml Type: System.String[] Parameter Sets: (All) Aliases: -Accepted Values: Desktop, Core Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` -### -PowerShellVersion -Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. +### -ExternalModuleDependencies + +Specifies an array of external module dependencies. ```yaml -Type: System.Version +Type: System.String[] Parameter Sets: (All) Aliases: @@ -253,11 +263,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ClrVersion -Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. +### -FileList + +Specifies all items that are included in the module. ```yaml -Type: System.Version +Type: System.String[] Parameter Sets: (All) Aliases: @@ -268,11 +279,15 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -DotNetFrameworkVersion -Specifies the minimum version of the Microsoft .NET Framework that the module requires. +### -FormatsToProcess + +Specifies the formatting files (`.ps1xml`) that are processed when the module is imported. + +When you import a module, PowerShell runs the `Update-FormatData` cmdlet with the specified files. +Because formatting files aren't scoped, they affect all session states in the session. ```yaml -Type: System.Version +Type: System.String[] Parameter Sets: (All) Aliases: @@ -283,13 +298,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -PowerShellHostName -Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. +### -FunctionsToExport -To find the name of a host program, in the program, type $Host.Name. +Specifies the functions that the module exports. Wildcards are permitted. ```yaml -Type: System.String +Type: System.String[] Parameter Sets: (All) Aliases: @@ -297,14 +311,16 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` -### -PowerShellHostVersion -Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. +### -Guid + +Specifies a unique identifier for the module. The **GUID** is used to distinguish between modules +with the same name. ```yaml -Type: System.Version +Type: System.Guid Parameter Sets: (All) Aliases: @@ -315,11 +331,16 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -RequiredModules -Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. +### -HelpInfoUri + +Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource +Identifier (URI) that begins with `http:` or `https:`. + +For more information, see +[Updatable Help](/powershell/module/microsoft.powershell.core/about/about_updatable_help). ```yaml -Type: System.Object[] +Type: System.Uri Parameter Sets: (All) Aliases: @@ -330,13 +351,13 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -TypesToProcess -Specifies the type files (.ps1xml) that run when the module is imported. +### -IconUri -When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. +Specifies the URI of an icon for the module. The specified icon is displayed on the gallery web page +for the module. ```yaml -Type: System.String[] +Type: System.Uri Parameter Sets: (All) Aliases: @@ -347,14 +368,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -FormatsToProcess -Specifies the formatting files (.ps1xml) that run when the module is imported. - -When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. +### -LicenseUri +Specifies the URL of licensing terms for the module. ```yaml -Type: System.String[] +Type: System.Uri Parameter Sets: (All) Aliases: @@ -365,13 +384,18 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ScriptsToProcess -Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. +### -ModuleList -To specify scripts that run in the module's session state, use the NestedModules key. +Specifies an array of modules that are included in the module. + +Enter each module name as a string or as a hashtable with **ModuleName** and **ModuleVersion** keys. +The hashtable can also have an optional **GUID** key. You can combine strings and hashtables in the +parameter value. + +This key is designed to act as a module inventory. ```yaml -Type: System.String[] +Type: System.Object[] Parameter Sets: (All) Aliases: @@ -382,13 +406,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -RequiredAssemblies -Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. +### -ModuleVersion -Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. +Specifies the version of the module. ```yaml -Type: System.String[] +Type: System.Version Parameter Sets: (All) Aliases: @@ -399,11 +422,17 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -FileList -Specifies all items that are included in the module. - +### -NestedModules + +Specifies script modules (`.psm1`) and binary modules (`.dll`) that are imported into the module's +session state. The files in the **NestedModules** key run in the order in which they're listed. + +Enter each module name as a string or as a hashtable with **ModuleName** and **ModuleVersion** keys. +The hashtable can also have an optional **GUID** key. You can combine strings and hashtables in the +parameter value. + ```yaml -Type: System.String[] +Type: System.Object[] Parameter Sets: (All) Aliases: @@ -414,15 +443,10 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ModuleList -Specifies an array of modules that are included in the module. - -Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. +### -PassThru -This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. - ```yaml -Type: System.String[] +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: @@ -433,30 +457,32 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -FunctionsToExport -Specifies the functions that the module exports. Wildcards are permitted. +### -Path + +Specifies the path and filename of the module manifest. Enter filename with a `.psd1` file +extension. -Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. - ```yaml -Type: System.String[] +Type: System.String Parameter Sets: (All) Aliases: -Required: False -Position: Named +Required: True +Position: 0 Default value: None Accept pipeline input: False -Accept wildcard characters: True +Accept wildcard characters: False ``` -### -AliasesToExport -Specifies the aliases that the module exports. Wildcards are permitted. +### -PowerShellHostName + +Specifies the name of the PowerShell host program that the module requires. Enter the name of the +host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + +The name of a host program is stored in `$Host.Name`. -Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. - ```yaml -Type: System.String[] +Type: System.String Parameter Sets: (All) Aliases: @@ -464,16 +490,16 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: True +Accept wildcard characters: False ``` -### -VariablesToExport -Specifies the variables that the module exports. Wildcards are permitted. +### -PowerShellHostVersion + +Specifies the minimum version of the PowerShell host program that works with the module. Enter a +version number, such as 1.1. -Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. - ```yaml -Type: System.String[] +Type: System.Version Parameter Sets: (All) Aliases: @@ -481,16 +507,16 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: True +Accept wildcard characters: False ``` -### -CmdletsToExport -Specifies the cmdlets that the module exports. Wildcards are permitted. +### -PowerShellVersion + +Specifies the minimum version of PowerShell that works with this module. For example, you can +specify versions such as `5.1` or `7.2`. -Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. - ```yaml -Type: System.String[] +Type: System.Version Parameter Sets: (All) Aliases: @@ -498,14 +524,17 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: True +Accept wildcard characters: False ``` -### -DscResourcesToExport -Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. - +### -Prerelease + +Specifies the prerelease value that is appended to the module version. For example, if +**Prerelease** is `preview` and the **ModuleVersion** is `1.0.0`, the version of the module is +`1.0.0-preview`. + ```yaml -Type: System.String[] +Type: System.String Parameter Sets: (All) Aliases: @@ -513,14 +542,16 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: True +Accept wildcard characters: False ``` ### -PrivateData -Specifies data that is passed to the module when it's imported. - + +Specifies data that is passed to the module when it's imported. This can be any arbitrary values +stored in a hashtable. + ```yaml -Type: Hashtable +Type: System.Collections.Hashtable Parameter Sets: (All) Aliases: @@ -531,11 +562,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Tags -Specifies an array of tags. - +### -ProcessorArchitecture + +Specifies the processor architecture that the module requires. + +The acceptable values for this parameter are: + +- `Amd64` +- `Arm` +- `IA64` +- `MSIL` +- `None` (unknown or unspecified) +- `X86` + ```yaml -Type: System.String[] +Type: System.Reflection.ProcessorArchitecture Parameter Sets: (All) Aliases: @@ -547,10 +588,11 @@ Accept wildcard characters: False ``` ### -ProjectUri -Specifies the URL of a web page about this project. - + +Specifies the URI of a web page about this project. + ```yaml -Type: Uri +Type: System.Uri Parameter Sets: (All) Aliases: @@ -561,11 +603,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -LicenseUri -Specifies the URL of licensing terms for the module. - +### -ReleaseNotes + +Specifies a string that contains release notes or comments for the module. + ```yaml -Type: Uri +Type: System.String Parameter Sets: (All) Aliases: @@ -576,11 +619,18 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -IconUri -Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. - +### -RequiredAssemblies + +Specifies the assembly (`.dll`) files required by the module. PowerShell loads the specified +assemblies before updating types or formats, importing nested modules, or importing the module file +specified in the **RootModule** key. + +Use **RequiredAssemblies** for assemblies that must be loaded to update any formatting or type files +that are listed in the **FormatsToProcess** or **TypesToProcess** keys, even if those assemblies are +also listed in the **NestedModules** key. + ```yaml -Type: Uri +Type: System.String[] Parameter Sets: (All) Aliases: @@ -591,11 +641,24 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ReleaseNotes -Specifies a string array that contains release notes or comments that you want available for this version of the script. - +### -RequiredModules + +Specifies modules that must be in the global session state. If the required modules aren't in the +global session state, PowerShell imports them. If the required modules aren't available, the +`Import-Module` command fails. + +The value can be an array containing module names or module specifications. A module specification +is a hashtable that has the following keys. + +- **ModuleName** - Required Specifies the module name. +- **GUID** - Optional Specifies the GUID of the module. +- One of these three version key is Required. These keys can't be used together. + - **ModuleVersion** - Specifies a minimum acceptable version of the module. + - **RequiredVersion** - Specifies an exact, required version of the module. + - **MaximumVersion** - Specifies the maximum acceptable version of the module. + ```yaml -Type: System.String[] +Type: System.Object[] Parameter Sets: (All) Aliases: @@ -606,8 +669,35 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Prerelease -Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". +### -RequireLicenseAcceptance + +Specifies that a license acceptance is required for the module. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -RootModule + +Specifies the primary or root file of the module. Enter the file name of a script (`.ps1`), a script +module (`.psm1`), a module manifest (`.psd1`), an assembly (`.dll`), or a cmdlet definition XML file +(`.cdxml`). When the module is imported, the members exported from the root module are imported into +the caller's session state. + +If a module has a manifest file and no file is specified in the **RootModule** key, the manifest +becomes the primary file for the module. The module is known as a manifest module (**ModuleType** = +`Manifest`). + +To export members from `.psm1` or `.dll` files, the names of those files must be specified in the +values of the **RootModule** or **NestedModules** keys in the manifest. ```yaml Type: System.String @@ -621,15 +711,15 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -HelpInfoUri -Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. +### -ScriptsToProcess -The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. +Specifies script (`.ps1`) files that run in the caller's session state when the module is imported. +You can use these scripts to prepare an environment, just as you might use a login script. -For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. +To specify scripts that run in the module's session state, use the **NestedModules** key. ```yaml -Type: Uri +Type: System.String[] Parameter Sets: (All) Aliases: @@ -640,11 +730,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -DefaultCommandPrefix -Specifies the default command prefix. +### -Tags + +Specifies an array of tags. ```yaml -Type: System.String +Type: System.String[] Parameter Sets: (All) Aliases: @@ -655,8 +746,12 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -ExternalModuleDependencies -Specifies an array of external module dependencies. +### -TypesToProcess + +Specifies the type files (`.ps1xml`) that run when the module is imported. + +When you import the module, PowerShell runs the `Update-TypeData` cmdlet with the specified files. +Because type files aren't scoped, they affect all session states in the session. ```yaml Type: System.String[] @@ -670,11 +765,14 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -RequireLicenseAcceptance -Specifies that a license acceptance is required for the module. +### -VariablesToExport + +Specifies the variables that the module exports. Wildcards are permitted. + +Use this parameter to restrict which variables that are exported by the module. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: System.String[] Parameter Sets: (All) Aliases: @@ -682,11 +780,15 @@ Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS @@ -696,4 +798,9 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## NOTES +For a full description of the module manifest file, see +[about_Module_Manifests](/powershell/module/microsoft.powershell.core/about/about_module_manifests). + ## RELATED LINKS + +[New-ModuleManifest](/powershell/module/microsoft.powershell.core/new-modulemanifest) diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index 1471e002a..bdfa732ad 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -1,6 +1,7 @@ --- external help file: PowerShellGet.dll-Help.xml Module Name: PowerShellGet +ms.date: 08/03/2022 online version: schema: 2.0.0 --- @@ -8,46 +9,63 @@ schema: 2.0.0 # Update-PSResource ## SYNOPSIS -Updates a package already installed on the user's machine. +Downloads and installs the newest version of a package already installed on the local machine. ## SYNTAX -### NameParameterSet (Default) +### __AllParameterSets + ``` -Update-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-AuthenticodeCheck] [-SkipDependencyCheck] [-WhatIf] [-Confirm] [] +Update-PSResource [[-Name] ] [-Version ] [-Prerelease] [-Repository ] + [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] + [-Force] [-PassThru] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] + [] ``` ## DESCRIPTION -The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. -It updates an already installed package based on the `-Name` parameter argument. -It does not return an object. Other parameters allow the package to be updated to be further filtered. + +`Update-PSResource` downloads and installs the newest version of a package already installed on the +local machine. This cmdlet replaces the `Update-Module` and `Update-Script` cmdlets from +**PowerShellGet** v2. The new version of the resource is installed side-by-side with previous +versions in a new versioned folder. + +By default, `Update-PSResource` installs the latest version of the package and any of its +dependencies without deleting the older versions installed. ## EXAMPLES ### Example 1 -```powershell -PS C:\> Update-PSResource -Name "TestModule" - Name Version Prerelease Description - ---- ------- ---------- ----------- - TestModule 1.2.0 test -PS C:\> Update-PSResource -Name "TestModule" +In this example, the user already has the **TestModule** package installed and they update the +package. -PS C:\> Update-PSResource -Name "TestModule" - Name Version Prerelease Description - ---- ------- ---------- ----------- - TestModule 1.3.0 test - TestModule 1.2.0 test +```powershell +Get-PSResource -Name "TestModule" +``` +```Output +Name Version Prerelease Description +---- ------- ---------- ----------- +TestModule 1.2.0 test ``` -In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. +```powershell +Update-PSResource -Name "TestModule" +``` + +```Output +Name Version Prerelease Description +---- ------- ---------- ----------- +TestModule 1.3.0 test +TestModule 1.2.0 test +``` ## PARAMETERS ### -AcceptLicense -For resources that require a license, AcceptLicense automatically accepts the license agreement during the update. + +For resources that require a license, **AcceptLicense** automatically accepts the license agreement +during the update. ```yaml Type: System.Management.Automation.SwitchParameter @@ -56,47 +74,34 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Credential -Specifies optional credentials to be used when accessing a private repository. +### -AuthenticodeCheck + +Validates signed files and catalog files on Windows. ```yaml -Type: System.Management.Automation.PSCredential -Parameter Sets: NameParameterSet +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Name -Specifies name of a resource or resources to update. - -```yaml -Type: System.String[] -Parameter Sets: NameParameterSet -Aliases: - -Required: True -Position: 0 -Default value: "*" -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: True -``` +### -Credential -### -Prerelease -When specified, allows updating to a prerelease version. +Specifies optional credentials used when accessing a private repository. ```yaml -Type: System.Management.Automation.SwitchParameter -Parameter Sets: NameParameterSet +Type: System.Management.Automation.PSCredential +Parameter Sets: (All) Aliases: Required: False @@ -106,8 +111,10 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Quiet -Supresses progress information. +### -Force + +When specified, bypasses checks for **TrustRepository** and **AcceptLicense** and updates the +package. ```yaml Type: System.Management.Automation.SwitchParameter @@ -116,45 +123,64 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Repository -Specifies one or more repository names to update packages from. -If not specified, search for packages to update will include all currently registered repositories in order of highest priority. +### -Name + +Specifies the name of one or more resources to update. Wildcards are supported but NuGet only +accepts the `*` character. NuGet does not support wildcard searches of local (file-based) +repositories. ```yaml Type: System.String[] -Parameter Sets: NameParameterSet +Parameter Sets: (All) +Aliases: + +Required: False +Position: 0 +Default value: "*" +Accept pipeline input: True (ByPropertyName, ByValue) +Accept wildcard characters: True +``` + +### -PassThru + +When specified, outputs a **PSResourceInfo** object for the saved resource. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Scope -Specifies the scope of the resource to update. +### -Prerelease + +When specified, allows updating to a prerelease version. ```yaml -Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) Aliases: -Accepted values: CurrentUser, AllUsers Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -TrustRepository -Specifies optional credentials to be used when accessing a private repository. +### -Quiet + +Supresses progress information. ```yaml Type: System.Management.Automation.SwitchParameter @@ -163,42 +189,46 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -Version -Specifies the version of the resource to be updated to. The value can be an exact version or a version -range using the NuGet versioning syntax. +### -Repository -For more information about NuGet version ranges, see [Package versioning](/nuget/concepts/package-versioning#version-ranges) +Specifies one or more repository names to search. Wildcards are supported. -PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range -documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher -(minimum inclusive range). Instead, the values is considered as the required version and yields -version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as -the version range. +If not specified, search includes all registered repositories, in priority order (highest first), +until a repository is found that contains the package. + +Lower **Priority** values have a higher precedence. ```yaml -Type: System.String -Parameter Sets: NameParameterSet +Type: System.String[] +Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False -Accept wildcard characters: False +Accept wildcard characters: True ``` -### -Force -When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. +### -Scope + +Specifies the installation scope. Accepted values are: + +- `CurrentUser` +- `AllUsers` + +The default scope is `CurrentUser`, which doesn't require elevation. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType Parameter Sets: (All) -Aliases: +Aliases: +Accepted values: CurrentUser, AllUsers Required: False Position: Named @@ -207,8 +237,9 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -PassThru -Passes the resource updated to the console. +### -SkipDependencyCheck + +Skips the check for resource dependencies. This means that only named resources are updated. ```yaml Type: System.Management.Automation.SwitchParameter @@ -217,30 +248,43 @@ Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -AuthenticodeCheck -Does a check to to validate signed files and catalog files on Windows. + +### -TrustRepository + +Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository +isn't configured as trusted. ```yaml Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: +Aliases: Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` -### -SkipdependencyCheck -Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. +### -Version + +Specifies the version of the resource to be returned. The value can be an exact version or a version +range using the NuGet versioning syntax. + +For more information about NuGet version ranges, see +[Package versioning](/nuget/concepts/package-versioning#version-ranges). + +PowerShellGet supports all but the _minimum inclusive version_ listed in the NuGet version range +documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum +inclusive range). Instead, the value is considered to be the required version. To search for a +minimum inclusive range, use `[1.0.0.0, ]` as the version range. ```yaml -Type: System.Management.Automation.SwitchParameter +Type: System.String Parameter Sets: (All) Aliases: @@ -252,6 +296,7 @@ Accept wildcard characters: False ``` ### -Confirm + Prompts you for confirmation before running the cmdlet. ```yaml @@ -261,14 +306,14 @@ Aliases: cf Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf -Shows what would happen if the cmdlet runs. -The cmdlet is not run. + +Shows what would happen if the cmdlet runs. The cmdlet isn't run. ```yaml Type: System.Management.Automation.SwitchParameter @@ -277,13 +322,17 @@ Aliases: wi Required: False Position: Named -Default value: None +Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS @@ -291,8 +340,13 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## OUTPUTS +### Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + +By default, the cmdlet doesn't return any objects. When the **PassThru** parameter is used, the +cmdlet outputs a **PSResourceInfo** object for the saved resource. + ## NOTES ## RELATED LINKS -[]() +[Install-PSResource](Install-PSResource.md) diff --git a/help/Update-PSScriptFileInfo.md b/help/Update-PSScriptFileInfo.md index 28fa2957e..e2ea6848c 100644 --- a/help/Update-PSScriptFileInfo.md +++ b/help/Update-PSScriptFileInfo.md @@ -1,36 +1,49 @@ --- external help file: PowerShellGet-help.xml Module Name: PowerShellGet -online version: +ms.date: 08/03/2022 +online version: schema: 2.0.0 --- # Update-PSScriptFileInfo ## SYNOPSIS - -Updates an existing .ps1 file with requested properties and ensures it's valid +This cmdlet updates the comment-based metadata in an existing script `.ps1` file. ## SYNTAX ### __AllParameterSets ``` -Update-PSScriptFileInfo [-FilePath] [-Author ] [-CompanyName ] [-Copyright ] [-Description ] [-ExternalModuleDependencies ] [-ExternalScriptDependencies ] [-Guid ] [-IconUri ] [-LicenseUri ] [-PrivateData ] [-ProjectUri ] [-ReleaseNotes ] [-RemoveSignature] [-RequiredModules ] [-RequiredScripts ] [-Tags ] [-Version ] [] +Update-PSScriptFileInfo [-FilePath] [-Author ] [-CompanyName ] + [-Copyright ] [-Description ] [-ExternalModuleDependencies ] + [-ExternalScriptDependencies ] [-Guid ] [-IconUri ] + [-LicenseUri ] [-PrivateData ] [-ProjectUri ] [-ReleaseNotes ] + [-RemoveSignature] [-RequiredModules ] [-RequiredScripts ] + [-Tags ] [-Version ] [] ``` ## DESCRIPTION -The Update-PSScriptFileInfo cmdlet updates an existing .ps1 file with requested properties and ensures it's valid. +This cmdlet updates the comment-based metadata in an existing script `.ps1` file. This is similar to +`Update-ModuleManifest`. ## EXAMPLES ### Example 1: Update the version of a script +In this example, a script is created with **Version** set to `1.0.0.0`. `Update-PSScriptFileInfo` +changes the **Version**' to `2.0.0.0`. The `Get-Content` cmdlet shows the updated contents of the +script. + +```powershell +New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" +Update-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" +Get-Content "C:\Users\johndoe\MyScripts\test_script.ps1" ``` -PS C:\> New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" -PS C:\> Update-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" -PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" + +```Output <#PSScriptInfo .VERSION 2.0.0.0 @@ -51,18 +64,17 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .ICONURI -.EXTERNALMODULEDEPENDENCIES +.EXTERNALMODULEDEPENDENCIES -.REQUIREDSCRIPTS +.REQUIREDSCRIPTS -.EXTERNALSCRIPTDEPENDENCIES +.EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA - #> <# @@ -70,28 +82,24 @@ PS C:\> cat "C:\Users\johndoe\MyScripts\test_script.ps1" .DESCRIPTION this is a test script - #> ``` -In this example a script is created by running the New-PSScriptFileInfo cmdlet with version specified as 1.0.0.0. To update the script's version to 2.0.0.0, the Update-PSScriptFileInfo cmdlet is run with 'Version' specified as "2.0.0.0". Given that the cmdlet completed running without errors and by looking at the contents of the updated file we see the version was updated to 2.0.0.0. - ## PARAMETERS ### -Author -The author of the script. +The name of the author of the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -101,14 +109,13 @@ Accept wildcard characters: False The name of the company owning the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -118,14 +125,13 @@ Accept wildcard characters: False The copyright information for the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -135,14 +141,13 @@ Accept wildcard characters: False The description of the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -152,14 +157,13 @@ Accept wildcard characters: False The list of external module dependencies taken by this script. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -169,82 +173,77 @@ Accept wildcard characters: False The list of external script dependencies taken by this script. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -FilePath -The path the .ps1 script info file will be created at. +The filename and location of the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: True Position: 0 -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Guid -The GUID for the script. +The unique identifier for the script in GUID format. ```yaml -Type: Guid +Type: System.Guid Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -IconUri -The Uri for the icon associated with the script. +A Uniform Resource Identifier (URI) pointing to the icon associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -LicenseUri -The Uri for the license associated with the script. +The URI pointing to the license agreement file associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -254,31 +253,29 @@ Accept wildcard characters: False The private data associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ProjectUri -The Uri for the project associated with the script. +The URI pointing to the project site associated with the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -288,48 +285,54 @@ Accept wildcard characters: False The release notes for the script. ```yaml -Type: String[] +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -RemoveSignature -Remove signature from signed .ps1 (if present) thereby allowing update of script to happen. User should re-sign the updated script afterwards. +Removes the signature from a signed `.ps1` file, allowing you to update the script. You should +re-sign the after updating the file. ```yaml -Type: SwitchParameter +Type: System.Management.Automation.SwitchParameter Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -RequiredModules -The list of modules required by the script. +The parameter takes an array of module specification hashtables. A module specification is a +hashtable that has the following keys. + +- **ModuleName** - Required Specifies the module name. +- **GUID** - Optional Specifies the GUID of the module. +- One of these three version key is Required. These keys can't be used together. + - **ModuleVersion** - Specifies a minimum acceptable version of the module. + - **RequiredVersion** - Specifies an exact, required version of the module. + - **MaximumVersion** - Specifies the maximum acceptable version of the module. ```yaml -Type: Hashtable[] +Type: System.Collections.Hashtable[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -339,31 +342,30 @@ Accept wildcard characters: False The list of scripts required by the script. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Tags -The tags associated with the script. +The tags associated with the script. Tag values are strings that should not contain spaces. For more +information, see [Tag details][1]. ```yaml -Type: String[] +Type: System.String[] Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` @@ -373,34 +375,42 @@ Accept wildcard characters: False The version of the script. ```yaml -Type: String +Type: System.String Parameter Sets: (All) -Aliases: -Accepted values: +Aliases: Required: False Position: Named -Default value: +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` - ### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, +-WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ### None +## OUTPUTS +### System.Object -## OUTPUTS +## NOTES -### None +## RELATED LINKS +[PowerShellGallery Publishing Guidelines and Best Practices][2] +[Package manifest values that impact the PowerShell Gallery UI][3] -## NOTES + +[1]: /powershell/scripting/gallery/concepts/package-manifest-affecting-ui#tag-details +[2]: /powershell/scripting/gallery/concepts/publishing-guidelines +[3]: /powershell/scripting/gallery/concepts/package-manifest-affecting-ui From 7613874ed605c9359136a6993bd28abb353f1920 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Thu, 11 Aug 2022 17:52:01 -0400 Subject: [PATCH 238/276] Check Uri before setting the new value --- src/code/RepositorySettings.cs | 39 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index cfb74594f..ef550b629 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -168,30 +168,33 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // determine if existing repository node (which we wish to update) had Url or Uri attribute Uri thisUrl = null; - if (urlAttributeExists) { - if (repoUri != null) { - node.Attribute("Url").Value = repoUri.AbsoluteUri; - } - if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) + if (urlAttributeExists) + { + Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl); + + if (repoUri != null) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); - } + if (!Uri.TryCreate(repoUri.AbsoluteUri, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); + } + node.Attribute("Url").Value = thisUrl.AbsoluteUri; + } } - else { - if (repoUri != null) { - node.Attribute("Uri").Value = repoUri.AbsoluteUri; - } - if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) + else + { + Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl); + + if (repoUri != null) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); + if (!Uri.TryCreate(repoUri.AbsoluteUri, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); + } + node.Attribute("Uri").Value = thisUrl.AbsoluteUri; } } - - - - - // A negative Priority value passed in signifies the Priority value was not attempted to be set. // So only set Priority attribute if non-null value passed in for repoPriority if (repoPriority >= 0) From 1d174092099caa97789c306b389bc895fb92e6e7 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Fri, 12 Aug 2022 10:37:56 -0400 Subject: [PATCH 239/276] refactor updating user uri --- src/code/RepositorySettings.cs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index ef550b629..e3ee97b07 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -168,30 +168,29 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // determine if existing repository node (which we wish to update) had Url or Uri attribute Uri thisUrl = null; - if (urlAttributeExists) + if (repoUri != null) { - Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl); - - if (repoUri != null) - { - if (!Uri.TryCreate(repoUri.AbsoluteUri, UriKind.Absolute, out thisUrl)) + if (!Uri.TryCreate(repoUri.AbsoluteUri, UriKind.Absolute, out thisUrl)) { throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); } + + if (urlAttributeExists) + { node.Attribute("Url").Value = thisUrl.AbsoluteUri; - } + } + else{ + node.Attribute("Uri").Value = thisUrl.AbsoluteUri; + } } else { - Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl); - - if (repoUri != null) + if (urlAttributeExists) { - if (!Uri.TryCreate(repoUri.AbsoluteUri, UriKind.Absolute, out thisUrl)) - { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); - } - node.Attribute("Uri").Value = thisUrl.AbsoluteUri; + Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl); + } + else{ + Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl); } } From 5c8ee8cba2ed4fda98c30484ec21f3d39c12a3d0 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Fri, 12 Aug 2022 15:13:41 -0700 Subject: [PATCH 240/276] Update priority range for PSResourceRepository to 0-100 (#741) --- help/Register-PSResourceRepository.md | 4 ++-- help/en-US/PowerShellGet.dll-Help.xml | 8 ++++---- src/code/PSRepositoryInfo.cs | 2 +- src/code/RegisterPSResourceRepository.cs | 18 +++++++++--------- src/code/RepositorySettings.cs | 6 +++--- src/code/SetPSResourceRepository.cs | 4 ++-- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/help/Register-PSResourceRepository.md b/help/Register-PSResourceRepository.md index a0b52ae53..308be06ec 100644 --- a/help/Register-PSResourceRepository.md +++ b/help/Register-PSResourceRepository.md @@ -178,8 +178,8 @@ Accept wildcard characters: False ### -Priority -Specifies the priority ranking of the repository. Valid priority values range from 0 to 50. Lower -values have a higher priority ranking. The default value is `50`. +Specifies the priority ranking of the repository. Valid priority values range from 0 to 100. Lower +values have a higher priority ranking. The default value is `100`. Repositories are searched in priority order (highest first). diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index f251ef402..0afb8205c 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -1933,7 +1933,7 @@ Priority - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. Int32 @@ -2788,7 +2788,7 @@ PS C:\> Get-PSResourceRepository Priority - Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). System.Int32 @@ -2884,7 +2884,7 @@ PS C:\> Get-PSResourceRepository Priority - Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). System.Int32 @@ -3026,7 +3026,7 @@ PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -Pas ---- --- ------- -------- PSGallery https://www.powershellgallery.com/api/v2 True 25 - This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 50 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. + This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 100 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. diff --git a/src/code/PSRepositoryInfo.cs b/src/code/PSRepositoryInfo.cs index d5fbebb25..39b42aadd 100644 --- a/src/code/PSRepositoryInfo.cs +++ b/src/code/PSRepositoryInfo.cs @@ -44,7 +44,7 @@ public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCred /// /// the priority of the repository /// - [ValidateRange(0, 50)] + [ValidateRange(0, 100)] public int Priority { get; } /// diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index d6857837a..8f0c16a2a 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -29,8 +29,8 @@ class RegisterPSResourceRepository : PSCmdlet private readonly string PSGalleryRepoName = "PSGallery"; private readonly string PSGalleryRepoUri = "https://www.powershellgallery.com/api/v2"; - private const int defaultPriority = 50; - private const bool defaultTrusted = false; + private const int DefaultPriority = 50; + private const bool DefaultTrusted = false; private const string NameParameterSet = "NameParameterSet"; private const string PSGalleryParameterSet = "PSGalleryParameterSet"; private const string RepositoriesParameterSet = "RepositoriesParameterSet"; @@ -77,13 +77,13 @@ class RegisterPSResourceRepository : PSCmdlet /// /// Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched /// before a lower ranking priority one, when searching for a repository item across multiple registered repositories. - /// Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds + /// Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds /// to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. /// [Parameter(ParameterSetName = NameParameterSet)] [Parameter(ParameterSetName = PSGalleryParameterSet)] - [ValidateRange(0, 50)] - public int Priority { get; set; } = defaultPriority; + [ValidateRange(0, 100)] + public int Priority { get; set; } = DefaultPriority; /// /// Specifies vault and secret names as PSCredentialInfo for the repository. @@ -289,8 +289,8 @@ private List RepositoriesParameterSetHelper() { WriteVerbose("(RepositoriesParameterSet): on repo: PSGallery. Registers PSGallery repository"); reposAddedFromHashTable.Add(PSGalleryParameterSetHelper( - repo.ContainsKey("Priority") ? (int)repo["Priority"] : defaultPriority, - repo.ContainsKey("Trusted") ? (bool)repo["Trusted"] : defaultTrusted)); + repo.ContainsKey("Priority") ? (int)repo["Priority"] : DefaultPriority, + repo.ContainsKey("Trusted") ? (bool)repo["Trusted"] : DefaultTrusted)); } catch (Exception e) { @@ -371,8 +371,8 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) WriteVerbose(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); return NameParameterSetHelper(repo["Name"].ToString(), repoUri, - repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : defaultPriority, - repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : defaultTrusted, + repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, + repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : DefaultTrusted, repoCredentialInfo); } catch (Exception e) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index dec5d2d15..76e68a27e 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -24,8 +24,8 @@ internal static class RepositorySettings // The repository store file's location is currently only at '%LOCALAPPDATA%\PowerShellGet' for the user account. private const string PSGalleryRepoName = "PSGallery"; private const string PSGalleryRepoUri = "https://www.powershellgallery.com/api/v2"; - private const int defaultPriority = 50; - private const bool defaultTrusted = false; + private const int DefaultPriority = 50; + private const bool DefaultTrusted = false; private const string RepositoryFileName = "PSResourceRepository.xml"; private static readonly string RepositoryPath = Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData), "PowerShellGet"); @@ -60,7 +60,7 @@ public static void CheckRepositoryStore() // Add PSGallery to the newly created store Uri psGalleryUri = new Uri(PSGalleryRepoUri); - Add(PSGalleryRepoName, psGalleryUri, defaultPriority, defaultTrusted, repoCredentialInfo: null); + Add(PSGalleryRepoName, psGalleryUri, DefaultPriority, DefaultTrusted, repoCredentialInfo: null); } // Open file (which should exist now), if cannot/is corrupted then throw error diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index c1a71a05e..8963b76b7 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -74,12 +74,12 @@ public SwitchParameter Trusted /// /// Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched /// before a lower ranking priority one, when searching for a repository item across multiple registered repositories. - /// Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds + /// Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds /// to a higher priority ranking than a higher numeric value (i.e 40). /// [Parameter(ParameterSetName = NameParameterSet)] [ValidateNotNullOrEmpty] - [ValidateRange(0, 50)] + [ValidateRange(0, 100)] public int Priority { get; set; } = DefaultPriority; /// From 934e36d98b9fee7056b3dc2282ef672dbf1669d0 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Sun, 14 Aug 2022 13:07:28 -0700 Subject: [PATCH 241/276] Add -Force param to Register-PSResourceRepository and Set-PSResourceRepository (#717) --- src/code/PublishPSResource.cs | 16 +- src/code/RegisterPSResourceRepository.cs | 120 ++++++------- src/code/RepositorySettings.cs | 190 ++++++++++++++++++-- src/code/SetPSResourceRepository.cs | 111 ++++-------- test/RegisterPSResourceRepository.Tests.ps1 | 98 +++++++++- test/SetPSResourceRepository.Tests.ps1 | 21 ++- 6 files changed, 380 insertions(+), 176 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 2854da350..752255eae 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -236,6 +236,7 @@ protected override void EndProcessing() try { Utils.ValidateModuleManifest(resourceFilePath, out errorMsgs); + } finally { if (errorMsgs.Length > 0) @@ -884,17 +885,9 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam FindHelper findHelper = new FindHelper(_cancellationToken, this); bool depPrerelease = depVersion.Contains("-"); - var foundDependencies = findHelper.FindByResourceName( - name: depName, - type: ResourceType.Module, - version: depVersion, - prerelease: depPrerelease, - tag: null, - repository: new[] { repositoryName }, - credential: Credential, - includeDependencies: false); - - if (foundDependencies.Count is 0) + var repository = new[] { repositoryName }; + var dependencyFound = findHelper.FindByResourceName(depName, ResourceType.Module, depVersion, depPrerelease, null, repository, Credential, false); + if (dependencyFound == null || !dependencyFound.Any()) { var message = String.Format("Dependency '{0}' was not found in repository '{1}'. Make sure the dependency is published to the repository before publishing this module.", dependency, repositoryName); var ex = new ArgumentException(message); @@ -904,7 +897,6 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam return false; } } - return true; } diff --git a/src/code/RegisterPSResourceRepository.cs b/src/code/RegisterPSResourceRepository.cs index 8f0c16a2a..871be13e3 100644 --- a/src/code/RegisterPSResourceRepository.cs +++ b/src/code/RegisterPSResourceRepository.cs @@ -105,10 +105,16 @@ class RegisterPSResourceRepository : PSCmdlet public PSCredential ProxyCredential { get; set; } /// - /// When specified, displays the succcessfully registered repository and its information + /// When specified, displays the succcessfully registered repository and its information. /// [Parameter] public SwitchParameter PassThru { get; set; } + + /// + /// When specified, will overwrite information for any existing repository with the same name. + /// + [Parameter] + public SwitchParameter Force { get; set; } #endregion @@ -144,7 +150,16 @@ protected override void ProcessRecord() try { - items.Add(NameParameterSetHelper(Name, _uri, Priority, Trusted, CredentialInfo)); + items.Add(RepositorySettings.AddRepository(Name, _uri, Priority, Trusted, CredentialInfo, Force, this, out string errorMsg)); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorInNameParameterSet", + ErrorCategory.InvalidArgument, + this)); + } } catch (Exception e) { @@ -201,71 +216,30 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo AddToRepositoryStoreHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) - { - // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition - repoName = repoName.Trim(' '); - if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) - { - throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); - } - - if (repoUri == null || !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) - { - throw new ArgumentException("Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); - } - - if (repoCredentialInfo != null) - { - bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, this); - - if (repoCredentialInfo.Credential != null) - { - if (!isSecretManagementModuleAvailable) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException($"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."), - "RepositoryCredentialSecretManagementUnavailableModule", - ErrorCategory.ResourceUnavailable, - this)); - } - else - { - Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, this); - } - } - - if (!isSecretManagementModuleAvailable) - { - WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); - } - } - - WriteVerbose("All required values to add to repository provided, calling internal Add() API now"); - if (!ShouldProcess(repoName, "Register repository to repository store")) - { - return null; - } - - return RepositorySettings.Add(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); - } - - private PSRepositoryInfo NameParameterSetHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) - { - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) - { - WriteVerbose("Provided Name (NameParameterSet) but with invalid value of PSGallery"); - throw new ArgumentException("Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"); - } - - return AddToRepositoryStoreHelper(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo); - } private PSRepositoryInfo PSGalleryParameterSetHelper(int repoPriority, bool repoTrusted) { Uri psGalleryUri = new Uri(PSGalleryRepoUri); WriteVerbose("(PSGallerySet) internal name and uri values for Add() API are hardcoded and validated, priority and trusted values, if passed in, also validated"); - return AddToRepositoryStoreHelper(PSGalleryRepoName, psGalleryUri, repoPriority, repoTrusted, repoCredentialInfo: null); + var addedRepo = RepositorySettings.AddToRepositoryStore(PSGalleryRepoName, + psGalleryUri, + repoPriority, + repoTrusted, + repoCredentialInfo: null, + Force, + this, + out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "RepositoryCredentialSecretManagementUnavailableModule", + ErrorCategory.ResourceUnavailable, + this)); + } + + return addedRepo; } private List RepositoriesParameterSetHelper() @@ -316,7 +290,7 @@ private List RepositoriesParameterSetHelper() private PSRepositoryInfo RepoValidationHelper(Hashtable repo) { - if (!repo.ContainsKey("Name") || String.IsNullOrEmpty(repo["Name"].ToString())) + if (!repo.ContainsKey("Name") || repo["Name"] == null || String.IsNullOrWhiteSpace(repo["Name"].ToString())) { WriteError(new ErrorRecord( new PSInvalidOperationException("Repository name cannot be null"), @@ -336,7 +310,7 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) return null; } - if (!repo.ContainsKey("Uri") || String.IsNullOrEmpty(repo["Uri"].ToString())) + if (!repo.ContainsKey("Uri") || repo["Uri"] == null || String.IsNullOrEmpty(repo["Uri"].ToString())) { WriteError(new ErrorRecord( new PSInvalidOperationException("Repository Uri cannot be null"), @@ -369,11 +343,25 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) try { WriteVerbose(String.Format("(RepositoriesParameterSet): on repo: {0}. Registers Name based repository", repo["Name"])); - return NameParameterSetHelper(repo["Name"].ToString(), + var addedRepo = RepositorySettings.AddRepository(repo["Name"].ToString(), repoUri, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, repo.ContainsKey("Trusted") ? Convert.ToBoolean(repo["Trusted"].ToString()) : DefaultTrusted, - repoCredentialInfo); + repoCredentialInfo, + Force, + this, + out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "RegisterRepositoryError", + ErrorCategory.ResourceUnavailable, + this)); + } + + return addedRepo; } catch (Exception e) { diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 76e68a27e..47c6185d5 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -60,7 +60,7 @@ public static void CheckRepositoryStore() // Add PSGallery to the newly created store Uri psGalleryUri = new Uri(PSGalleryRepoUri); - Add(PSGalleryRepoName, psGalleryUri, DefaultPriority, DefaultTrusted, repoCredentialInfo: null); + Add(PSGalleryRepoName, psGalleryUri, DefaultPriority, DefaultTrusted, repoCredentialInfo: null, force: false); } // Open file (which should exist now), if cannot/is corrupted then throw error @@ -74,12 +74,159 @@ public static void CheckRepositoryStore() } } + public static PSRepositoryInfo AddRepository(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force, PSCmdlet cmdletPassedIn, out string errorMsg) + { + errorMsg = String.Empty; + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) + { + errorMsg = "Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"; + return null; + } + + return AddToRepositoryStore(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo, force, cmdletPassedIn, out errorMsg); + } + + + public static PSRepositoryInfo AddToRepositoryStore(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force, PSCmdlet cmdletPassedIn, out string errorMsg) + { + errorMsg = string.Empty; + // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition + repoName = repoName.Trim(' '); + if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) + { + throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); + } + + if (repoUri == null || !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) + { + errorMsg = "Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"; + return null; + } + + if (repoCredentialInfo != null) + { + bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, cmdletPassedIn); + + if (repoCredentialInfo.Credential != null) + { + if (!isSecretManagementModuleAvailable) + { + errorMsg = $"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."; + return null; + } + else + { + Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, cmdletPassedIn); + } + } + + if (!isSecretManagementModuleAvailable) + { + cmdletPassedIn.WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); + } + } + + if (!cmdletPassedIn.ShouldProcess(repoName, "Register repository to repository store")) + { + return null; + } + + if (!string.IsNullOrEmpty(errorMsg)) + { + return null; + } + + var repo = RepositorySettings.Add(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo, force); + + return repo; + } + + + public static PSRepositoryInfo UpdateRepositoryStore(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, bool isSet, int defaultPriority, PSCredentialInfo repoCredentialInfo, PSCmdlet cmdletPassedIn, out string errorMsg) + { + errorMsg = string.Empty; + if (repoUri != null && !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) + { + errorMsg = "Invalid Uri, Uri must be one of the following schemes: HTTPS, HTTP, FTP, File Based"; + return null; + } + + // check repoName can't contain * or just be whitespace + // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition + repoName = repoName.Trim(); + if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) + { + errorMsg = "Name cannot be null or empty, or contain wildcards"; + return null; + } + + // check PSGallery Uri is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUri != null) + { + errorMsg = "The PSGallery repository has a predefined Uri. Setting the -Uri parameter for this repository is not allowed. Please run 'Register-PSResourceRepository -PSGallery' to register the PowerShell Gallery."; + return null; + } + + // check PSGallery CredentialInfo is not trying to be set + if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) + { + errorMsg = "Setting the -CredentialInfo parameter for PSGallery is not allowed. Run 'Register-PSResourceRepository -PSGallery' to register the PowerShell Gallery."; + return null; + } + + // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) + bool? _trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); + + if (repoCredentialInfo != null) + { + bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, cmdletPassedIn); + + if (repoCredentialInfo.Credential != null) + { + if (!isSecretManagementModuleAvailable) + { + errorMsg = $"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."; + return null; + } + else + { + Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, cmdletPassedIn); + } + } + + if (!isSecretManagementModuleAvailable) + { + cmdletPassedIn.WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); + } + } + + // determine if either 1 of 4 values are attempting to be set: Uri, Priority, Trusted, CredentialInfo. + // if none are (i.e only Name parameter was provided, write error) + if (repoUri == null && repoPriority == defaultPriority && _trustedNullable == null && repoCredentialInfo == null) + { + errorMsg = "Must set Uri, Priority, Trusted or CredentialInfo parameter"; + return null; + } + + if (!cmdletPassedIn.ShouldProcess(repoName, "Set repository's value(s) in repository store")) + { + return null; + } + + if (!string.IsNullOrEmpty(errorMsg)) + { + return null; + } + + return Update(repoName, repoUri, repoPriority, _trustedNullable, repoCredentialInfo, cmdletPassedIn, out errorMsg); + } + /// /// Add a repository to the store /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store /// /// - public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) + public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force) { try { @@ -87,7 +234,22 @@ public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriorit XDocument doc = LoadXDocument(FullRepositoryPath); if (FindRepositoryElement(doc, repoName) != null) { - throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); + if (!force) + { + throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); + } + + // Delete the existing repository before overwriting it (otherwire multiple repos with the same name will be added) + List removedRepositories = RepositorySettings.Remove(new string[] { repoName }, out string[] errorList); + + // Need to load the document again because of changes after removing + doc = LoadXDocument(FullRepositoryPath); + + if (errorList.Count() > 0) + { + throw new PSInvalidOperationException($"The PSResource Repository '{repoName}' cannot be overwritten: ${errorList.FirstOrDefault()}"); + } + } // Else, keep going @@ -126,8 +288,9 @@ public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriorit /// Updates a repository name, Uri, priority, installation policy, or credential information /// Returns: void /// - public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo) + public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool? repoTrusted, PSCredentialInfo repoCredentialInfo, PSCmdlet cmdletPassedIn, out string errorMsg) { + errorMsg = string.Empty; PSRepositoryInfo updatedRepo; try { @@ -136,7 +299,9 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio XElement node = FindRepositoryElement(doc, repoName); if (node == null) { - throw new ArgumentException("Cannot find the repository because it does not exist. Try registering the repository using 'Register-PSResourceRepository'"); + bool repoIsTrusted = !(repoTrusted == null || repoTrusted == false); + repoPriority = repoPriority < 0 ? DefaultPriority : repoPriority; + return AddToRepositoryStore(repoName, repoUri, repoPriority, repoIsTrusted, repoCredentialInfo, force:true, cmdletPassedIn, out errorMsg); } // Check that repository node we are attempting to update has all required attributes: Name, Url (or Uri), Priority, Trusted. @@ -144,19 +309,22 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio if (node.Attribute("Priority") == null) { - throw new ArgumentException("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + errorMsg = $"Repository element does not contain neccessary 'Priority' attribute, in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; + return null; } if (node.Attribute("Trusted") == null) { - throw new ArgumentException("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + errorMsg = $"Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; + return null; } bool urlAttributeExists = node.Attribute("Url") != null; bool uriAttributeExists = node.Attribute("Uri") != null; if (!urlAttributeExists && !uriAttributeExists) { - throw new ArgumentException("Repository element does not contain neccessary 'Url' attribute (or alternatively 'Uri' attribute), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath); + errorMsg = $"Repository element does not contain neccessary 'Url' attribute (or alternatively 'Uri' attribute), in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; + return null; } // Else, keep going @@ -176,7 +344,8 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); + errorMsg = $"Unable to read incorrectly formatted Url for repo {repoName}"; + return null; } } else @@ -185,7 +354,8 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio node.Attribute("Uri").Value = repoUri.AbsoluteUri; if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) { - throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); + errorMsg = $"Unable to read incorrectly formatted Uri for repo {repoName}"; + return null; } } } diff --git a/src/code/SetPSResourceRepository.cs b/src/code/SetPSResourceRepository.cs index 8963b76b7..7f874a56e 100644 --- a/src/code/SetPSResourceRepository.cs +++ b/src/code/SetPSResourceRepository.cs @@ -89,7 +89,7 @@ public SwitchParameter Trusted public PSCredentialInfo CredentialInfo { get; set; } /// - /// When specified, displays the successfully registered repository and its information + /// When specified, displays the successfully registered repository and its information. /// [Parameter] public SwitchParameter PassThru { get; set; } @@ -121,7 +121,24 @@ protected override void ProcessRecord() case NameParameterSet: try { - items.Add(UpdateRepositoryStoreHelper(Name, _uri, Priority, Trusted, CredentialInfo)); + items.Add(RepositorySettings.UpdateRepositoryStore(Name, + _uri, + Priority, + Trusted, + isSet, + DefaultPriority, + CredentialInfo, + this, + out string errorMsg)); + + if (!string.IsNullOrEmpty(errorMsg)) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorInNameParameterSet", + ErrorCategory.InvalidArgument, + this)); + } } catch (Exception e) { @@ -162,77 +179,6 @@ protected override void ProcessRecord() } } - private PSRepositoryInfo UpdateRepositoryStoreHelper(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) - { - if (repoUri != null && !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) - { - throw new ArgumentException("Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"); - } - - // check repoName can't contain * or just be whitespace - // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition - repoName = repoName.Trim(); - if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) - { - throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); - } - - // check PSGallery Uri is not trying to be set - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUri != null) - { - throw new ArgumentException("The PSGallery repository has a pre-defined Uri. Setting the -Uri parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); - } - - // check PSGallery CredentialInfo is not trying to be set - if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) - { - throw new ArgumentException("The PSGallery repository does not require authentication. Setting the -CredentialInfo parameter for this repository is not allowed, instead try running 'Register-PSResourceRepository -PSGallery'."); - } - - // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) - bool? _trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); - - if (repoCredentialInfo != null) - { - bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, this); - - if (repoCredentialInfo.Credential != null) - { - if (!isSecretManagementModuleAvailable) - { - ThrowTerminatingError(new ErrorRecord( - new PSInvalidOperationException($"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."), - "RepositoryCredentialSecretManagementUnavailableModule", - ErrorCategory.ResourceUnavailable, - this)); - } - else - { - Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, this); - } - } - - if (!isSecretManagementModuleAvailable) - { - WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); - } - } - - // determine if either 1 of 4 values are attempting to be set: Uri, Priority, Trusted, CredentialInfo. - // if none are (i.e only Name parameter was provided, write error) - if (repoUri == null && repoPriority == DefaultPriority && _trustedNullable == null && repoCredentialInfo == null) - { - throw new ArgumentException("Either Uri, Priority, Trusted or CredentialInfo parameters must be requested to be set"); - } - - WriteVerbose("All required values to set repository provided, calling internal Update() API now"); - if (!ShouldProcess(repoName, "Set repository's value(s) in repository store")) - { - return null; - } - return RepositorySettings.Update(repoName, repoUri, repoPriority, _trustedNullable, repoCredentialInfo); - } - private List RepositoriesParameterSetHelper() { List reposUpdatedFromHashtable = new List(); @@ -305,11 +251,26 @@ private PSRepositoryInfo RepoValidationHelper(Hashtable repo) try { - return UpdateRepositoryStoreHelper(repo["Name"].ToString(), + var updatedRepo = RepositorySettings.UpdateRepositoryStore(repo["Name"].ToString(), repoUri, repo.ContainsKey("Priority") ? Convert.ToInt32(repo["Priority"].ToString()) : DefaultPriority, repoTrusted, - repoCredentialInfo); + isSet, + DefaultPriority, + repoCredentialInfo, + this, + out string errorMsg); + + if (!string.IsNullOrEmpty(errorMsg)) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException(errorMsg), + "ErrorSettingRepository", + ErrorCategory.InvalidData, + this)); + } + + return updatedRepo; } catch (Exception e) { diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index acaeca848..4853495ac 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -234,23 +234,94 @@ Describe "Test Register-PSResourceRepository" { $res3.Name | Should -Be $TestRepoName3 } - $testCases2 = @{Type = "-Name is not specified"; IncorrectHashTable = @{Uri = $tmpDir1Path}; ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Name is PSGallery"; IncorrectHashTable = @{Name = $PSGalleryName; Uri = $tmpDir1Path}; ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Uri not specified"; IncorrectHashTable = @{Name = $TestRepoName1}; ErrorId = "NullUriForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"}, - @{Type = "-Uri is not valid scheme"; IncorrectHashTable = @{Name = $TestRepoName1; Uri="www.google.com"}; ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository"} + It "not register incorrectly formatted -Name type repo among correct ones, where incorrect one is missing -Name" { + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Uri = $tmpDir1Path}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "NullNameForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId + + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 + + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 + + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.Priority | Should -Be 30 + } + + It "not register incorrectly formatted -Name type repo among correct ones, where incorrect type has -Name of PSGallery" { + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Name = $PSGalleryName; Uri = $tmpDir1Path}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "PSGalleryProvidedAsNameRepoPSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId + + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 + + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 - It "not register incorrectly formatted Name type repo among correct ones when incorrect type is " -TestCases $testCases2 { - param($Type, $IncorrectHashTable, $ErrorId) + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.Priority | Should -Be 30 + } + It "not register incorrectly formatted Name type repo among correct ones when incorrect type is -Uri not specified" { $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Name = $TestRepoName1}; $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 Unregister-PSResourceRepository -Name $PSGalleryName Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "NullUriForRepositoriesParameterSetRegistration,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly $ErrorId + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId + + $res = Get-PSResourceRepository -Name $TestRepoName2 + $res.Name | Should -Be $TestRepoName2 + + $res2 = Get-PSResourceRepository -Name $TestRepoName3 + $res2.Name | Should -Be $TestRepoName3 + + $res3 = Get-PSResourceRepository -Name $PSGalleryName + $res3.Name | Should -Be $PSGalleryName + $res3.Priority | Should -Be 30 + } + + It "not register incorrectly formatted Name type repo among correct ones when incorrect type is -Uri is not valid scheme" { + $correctHashtable1 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} + $correctHashtable2 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} + $correctHashtable3 = @{PSGallery = $True; Priority = 30}; + $IncorrectHashTable = @{Name = $TestRepoName1; Uri="www.google.com"}; + + $arrayOfHashtables = $correctHashtable1, $correctHashtable2, $IncorrectHashTable, $correctHashtable3 + Unregister-PSResourceRepository -Name $PSGalleryName + Register-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue + + $ErrorId = "InvalidUri,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -Be $ErrorId $res = Get-PSResourceRepository -Name $TestRepoName2 $res.Name | Should -Be $TestRepoName2 @@ -273,6 +344,17 @@ Describe "Test Register-PSResourceRepository" { $res.Priority | Should -Be 50 } + It "should update a repository if -Force is used" { + Register-PSResourceRepository -Name $TestRepoName1 -Uri "./" + Register-PSResourceRepository -Name $TestRepoName1 -Uri "./" -Priority 3 -Force + $res = Get-PSResourceRepository -Name $TestRepoName1 + + $res.Name | Should -Be $TestRepoName1 + $Res.Uri.LocalPath | Should -Contain $relativeCurrentPath + $res.Trusted | Should -Be False + $res.Priority | Should -Be 3 + } + It "should register local file share NuGet based repository" { Register-PSResourceRepository -Name "localFileShareTestRepo" -Uri "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" $res = Get-PSResourceRepository -Name "localFileShareTestRepo" @@ -290,7 +372,7 @@ Describe "Test Register-PSResourceRepository" { } It "throws error if CredentialInfo is passed in with Credential property without SecretManagement module setup" { - { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -Trusted -Priority 20 -CredentialInfo $credentialInfo2 } | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.RegisterPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore $res | Should -BeNullOrEmpty diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index d3d15a9a9..cc8661258 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -109,8 +109,8 @@ Describe "Test Set-PSResourceRepository" { {Set-PSResourceRepository -Name $Name -Priority 25 -ErrorAction Stop} | Should -Throw -ErrorId "$ErrorId,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" } - $testCases2 = @{Type = "contains *"; Name = "test*Repository2"; ErrorId = "ErrorSettingIndividualRepoFromRepositories"}, - @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorSettingIndividualRepoFromRepositories"}, + $testCases2 = @{Type = "contains *"; Name = "test*Repository2"; ErrorId = "ErrorSettingRepository"}, + @{Type = "is whitespace"; Name = " "; ErrorId = "ErrorSettingRepository"}, @{Type = "is null"; Name = $null; ErrorId = "NullNameForRepositoriesParameterSetRepo"} It "not set repository and write error given Name (RepositoriesParameterSet)" -TestCases $testCases2 { param($Type, $Name, $ErrorId) @@ -205,7 +205,7 @@ Describe "Test Set-PSResourceRepository" { Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingRepository,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 $Res.Uri.LocalPath | Should -Contain $tmpDir1Path @@ -235,7 +235,7 @@ Describe "Test Set-PSResourceRepository" { Set-PSResourceRepository -Repository $arrayOfHashtables -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingIndividualRepoFromRepositories,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" + $err[0].FullyQualifiedErrorId | Should -BeExactly "ErrorSettingRepository,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 $Res.Uri.LocalPath | Should -Contain $tmpDir1Path @@ -252,6 +252,17 @@ Describe "Test Set-PSResourceRepository" { $Res.Uri.LocalPath | Should -Contain "\\hcgg.rest.of.domain.name\test\ITxx\team\NuGet\" } + It "set repository should register repository if it does not already exist" { + $testRepoName = "NewForceTestRepo" + Set-PSResourceRepository -Name $testRepoName -Uri $tmpDir1Path -PassThru + + $res = Get-PSResourceRepository -Name $testRepoName + $res.Name | Should -Be $testRepoName + $Res.Uri.LocalPath | Should -Contain $tmpDir1Path + $res.Priority | Should -Be 50 + $res.Trusted | Should -Be False + } + It "set repository and see updated repository with -PassThru" { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path $res = Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir2Path -PassThru @@ -274,7 +285,7 @@ Describe "Test Set-PSResourceRepository" { { Register-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path Set-PSResourceRepository -Name $TestRepoName1 -Uri $tmpDir1Path -CredentialInfo $credentialInfo2 - } | Should -Throw -ErrorId "RepositoryCredentialSecretManagementUnavailableModule" + } | Should -Throw -ErrorId "ErrorInNameParameterSet,Microsoft.PowerShell.PowerShellGet.Cmdlets.SetPSResourceRepository" $res = Get-PSResourceRepository -Name $TestRepoName1 -ErrorAction Ignore $res.CredentialInfo | Should -BeNullOrEmpty From 115343118fb9eb794b927bb78aa20c031768d900 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 15 Aug 2022 11:39:35 -0700 Subject: [PATCH 242/276] Bug fix in Publish-PSResource when creating nuspec (#693) --- src/code/PublishPSResource.cs | 63 ++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 752255eae..482f116fa 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -493,10 +493,45 @@ private string CreateNuspec( { if (privateData["PSData"] is Hashtable psData) { - if (psData.ContainsKey("Prerelease") && psData["Prerelease"] is string preReleaseVersion) + if (psData.ContainsKey("prerelease") && psData["prerelease"] is string preReleaseVersion) { version = string.Format(@"{0}-{1}", version, preReleaseVersion); } + + if (psData.ContainsKey("licenseuri") && psData["licenseuri"] is string licenseUri) + + { + metadataElementsDictionary.Add("license", licenseUri.Trim()); + } + + if (psData.ContainsKey("projecturi") && psData["projecturi"] is string projectUri) + { + metadataElementsDictionary.Add("projectUrl", projectUri.Trim()); + } + + if (psData.ContainsKey("iconuri") && psData["iconuri"] is string iconUri) + { + metadataElementsDictionary.Add("iconUrl", iconUri.Trim()); + } + + if (psData.ContainsKey("releasenotes")) + { + if (psData["releasenotes"] is string releaseNotes) + { + metadataElementsDictionary.Add("releaseNotes", releaseNotes.Trim()); + } + else if (psData["releasenotes"] is string[] releaseNotesArr) + { + metadataElementsDictionary.Add("releaseNotes", string.Join("\n", releaseNotesArr)); + } + } + + // defaults to false + string requireLicenseAcceptance = psData.ContainsKey("requirelicenseacceptance") ? psData["requirelicenseacceptance"].ToString() : "false"; + + metadataElementsDictionary.Add("requireLicenseAcceptance", requireLicenseAcceptance); + + if (psData.ContainsKey("Tags") && psData["Tags"] is Array manifestTags) { var tagArr = new List(); @@ -525,21 +560,11 @@ private string CreateNuspec( metadataElementsDictionary.Add("owners", parsedMetadataHash["companyname"].ToString().Trim()); } - // defaults to false - var requireLicenseAcceptance = parsedMetadataHash.ContainsKey("requirelicenseacceptance") ? parsedMetadataHash["requirelicenseacceptance"].ToString().ToLower().Trim() - : "false"; - metadataElementsDictionary.Add("requireLicenseAcceptance", requireLicenseAcceptance); - if (parsedMetadataHash.ContainsKey("description")) { metadataElementsDictionary.Add("description", parsedMetadataHash["description"].ToString().Trim()); } - if (parsedMetadataHash.ContainsKey("releasenotes")) - { - metadataElementsDictionary.Add("releaseNotes", parsedMetadataHash["releasenotes"].ToString().Trim()); - } - if (parsedMetadataHash.ContainsKey("copyright")) { metadataElementsDictionary.Add("copyright", parsedMetadataHash["copyright"].ToString().Trim()); @@ -555,20 +580,6 @@ private string CreateNuspec( } metadataElementsDictionary.Add("tags", tags); - if (parsedMetadataHash.ContainsKey("licenseurl")) - { - metadataElementsDictionary.Add("licenseUrl", parsedMetadataHash["licenseurl"].ToString().Trim()); - } - - if (parsedMetadataHash.ContainsKey("projecturl")) - { - metadataElementsDictionary.Add("projectUrl", parsedMetadataHash["projecturl"].ToString().Trim()); - } - - if (parsedMetadataHash.ContainsKey("iconurl")) - { - metadataElementsDictionary.Add("iconUrl", parsedMetadataHash["iconurl"].ToString().Trim()); - } // Example nuspec: /* @@ -581,7 +592,7 @@ private string CreateNuspec( Microsoft,PowerShell false MIT - https://licenses.nuget.org/MIT + https://licenses.nuget.org/MIT Powershell_black_64.png https://github.com/PowerShell/PowerShell Example description here From fc233f6c8fe226e6161cc6167200ddbcde1df432 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 15 Aug 2022 18:48:45 -0400 Subject: [PATCH 243/276] add error for failure of Uri creation --- src/code/RepositorySettings.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index 3be8aac72..bad34404a 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -356,11 +356,17 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio { if (urlAttributeExists) { - Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl); + if(!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Current 'Url' for repo {0} is an invalid Uri. Fix this so the file is not corrupted.", repoName)); + } } else { - Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl); + if(!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) + { + throw new PSInvalidOperationException(String.Format("Current 'Uri' for repo {0} is an invalid Uri. Fix this so the file is not corrupted.", repoName)); + } } } From 38acaa1d22e63c0b029daad4602bfb171e690b41 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 15 Aug 2022 19:16:12 -0400 Subject: [PATCH 244/276] add temporary path parameter to save --- src/code/InstallHelper.cs | 5 ++++- src/code/SavePSResource.cs | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 75f6d54f2..0db4da8c8 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -53,6 +53,7 @@ internal class InstallHelper : PSCmdlet private bool _savePkg; List _pathsToSearch; List _pkgNamesToInstall; + private string _tmpPath; #endregion @@ -82,7 +83,8 @@ public List InstallPackages( bool skipDependencyCheck, bool authenticodeCheck, bool savePkg, - List pathsToInstallPkg) + List pathsToInstallPkg, + string tmpPath) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXml '{10}'; SavePackage '{11}'", @@ -113,6 +115,7 @@ public List InstallPackages( _includeXml = includeXml; _savePkg = savePkg; _pathsToInstallPkg = pathsToInstallPkg; + _tmpPath = tmpPath; // Create list of installation paths to search. _pathsToSearch = new List(); diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 3f2b2ce26..db1cffced 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -109,6 +109,32 @@ public string Path } private string _path; + public string TemporaryPath + { + get + { return _tmpPath; } + + set + { + string resolvedPath; + if (string.IsNullOrEmpty(value)) + { + // If the user does not specify a path to save to, use the user's default temporary directory + resolvedPath = System.IO.Path.GetTempPath(); + } + else { + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + } + + // Path where resource is saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _tmpPath = resolvedPath; + } + } + } + private string _tmpPath; + /// /// Suppresses being prompted for untrusted sources. /// @@ -266,7 +292,8 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p skipDependencyCheck: SkipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: true, - pathsToInstallPkg: new List { _path }); + pathsToInstallPkg: new List { _path }, + tmpPath: _tmpPath); if (PassThru) { From 65b68378a3f6766eb6ddfe629db23a7024a9b3a3 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 15 Aug 2022 19:22:35 -0400 Subject: [PATCH 245/276] Change error message --- src/code/RepositorySettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code/RepositorySettings.cs b/src/code/RepositorySettings.cs index bad34404a..e5a7cd16b 100644 --- a/src/code/RepositorySettings.cs +++ b/src/code/RepositorySettings.cs @@ -358,14 +358,14 @@ public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPrio { if(!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) { - throw new PSInvalidOperationException(String.Format("Current 'Url' for repo {0} is an invalid Uri. Fix this so the file is not corrupted.", repoName)); + throw new PSInvalidOperationException(String.Format("The 'Url' for repository {0} is invalid and the repository cannot be used. Please update the Url field or remove the repository entry.", repoName)); } } else { if(!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) { - throw new PSInvalidOperationException(String.Format("Current 'Uri' for repo {0} is an invalid Uri. Fix this so the file is not corrupted.", repoName)); + throw new PSInvalidOperationException(String.Format("The 'Url' for repository {0} is invalid and the repository cannot be used. Please update the Url field or remove the repository entry.", repoName)); } } } From a0370c36a72fa24528e8fd8938aa4bda02314b2d Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 16 Aug 2022 11:54:58 -0400 Subject: [PATCH 246/276] add TemporaryPath parameter to Install and Update --- src/code/InstallHelper.cs | 9 +++++---- src/code/InstallPSResource.cs | 28 +++++++++++++++++++++++++++- src/code/SavePSResource.cs | 23 +++++++++++------------ src/code/UpdatePSResource.cs | 29 ++++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 0db4da8c8..b1ca33ee8 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -87,7 +87,7 @@ public List InstallPackages( string tmpPath) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + - "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXml '{10}'; SavePackage '{11}'", + "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; AsNupkg: '{9}'; IncludeXml '{10}'; SavePackage '{11}'; TemporaryPath '{12}'", string.Join(",", names), versionRange != null ? (versionRange.OriginalString != null ? versionRange.OriginalString : string.Empty) : string.Empty, prerelease.ToString(), @@ -99,7 +99,8 @@ public List InstallPackages( noClobber.ToString(), asNupkg.ToString(), includeXml.ToString(), - savePkg.ToString())); + savePkg.ToString(), + tmpPath != null ? tmpPath.ToString() : string.Empty)); _versionRange = versionRange; _prerelease = prerelease; @@ -115,7 +116,7 @@ public List InstallPackages( _includeXml = includeXml; _savePkg = savePkg; _pathsToInstallPkg = pathsToInstallPkg; - _tmpPath = tmpPath; + _tmpPath = tmpPath ?? Path.GetTempPath(); // Create list of installation paths to search. _pathsToSearch = new List(); @@ -330,7 +331,7 @@ private List InstallPackage( foreach (PSResourceInfo pkg in pkgsToInstall) { currentInstalledPkgCount++; - var tempInstallPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + var tempInstallPath = Path.Combine(_tmpPath, Guid.NewGuid().ToString()); try { // Create a temp directory to install to diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 4149a2ba5..25746c606 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -67,6 +67,31 @@ class InstallPSResource : PSCmdlet [Parameter] public ScopeType Scope { get; set; } + /// + /// The destination where the resource is to be temporarily installed + /// + [Parameter] + public string TemporaryPath + { + get + { return _tmpPath; } + + set + { + if (!string.IsNullOrEmpty(value)) + { + string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + + // Path where resource is temporarily saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _tmpPath = resolvedPath; + } + } + } + } + private string _tmpPath; + /// /// Suppresses being prompted for untrusted sources. /// @@ -528,7 +553,8 @@ private void ProcessInstallHelper(string[] pkgNames, VersionRange pkgVersion, bo skipDependencyCheck: SkipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: false, - pathsToInstallPkg: _pathsToInstallPkg); + pathsToInstallPkg: _pathsToInstallPkg, + tmpPath: _tmpPath); if (PassThru) { diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index db1cffced..7b863614d 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -109,6 +109,10 @@ public string Path } private string _path; + /// + /// The destination where the resource is to be temporarily installed + /// + [Parameter] public string TemporaryPath { get @@ -116,20 +120,15 @@ public string TemporaryPath set { - string resolvedPath; - if (string.IsNullOrEmpty(value)) + if (!string.IsNullOrEmpty(value)) { - // If the user does not specify a path to save to, use the user's default temporary directory - resolvedPath = System.IO.Path.GetTempPath(); - } - else { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } + string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - // Path where resource is saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _tmpPath = resolvedPath; + // Path where resource is temporarily saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _tmpPath = resolvedPath; + } } } } diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index bce9ed295..327dab49f 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -5,6 +5,7 @@ using NuGet.Versioning; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Management.Automation; using System.Threading; @@ -68,6 +69,31 @@ public sealed class UpdatePSResource : PSCmdlet [Parameter] public ScopeType Scope { get; set; } + /// + /// The destination where the resource is to be temporarily installed + /// + [Parameter] + public string TemporaryPath + { + get + { return _tmpPath; } + + set + { + if (!string.IsNullOrEmpty(value)) + { + string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; + + // Path where resource is temporarily saved must be a directory + if (Directory.Exists(resolvedPath)) + { + _tmpPath = resolvedPath; + } + } + } + } + private string _tmpPath; + /// /// When specified, suppresses prompting for untrusted sources. /// @@ -187,7 +213,8 @@ protected override void ProcessRecord() skipDependencyCheck: SkipDependencyCheck, authenticodeCheck: AuthenticodeCheck, savePkg: false, - pathsToInstallPkg: _pathsToInstallPkg); + pathsToInstallPkg: _pathsToInstallPkg, + tmpPath: _tmpPath); if (PassThru) { From 865969509c7c079286780cce77e21325afd295d6 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 16 Aug 2022 12:38:22 -0400 Subject: [PATCH 247/276] add parameter attribute --- src/code/InstallPSResource.cs | 2 ++ src/code/SavePSResource.cs | 1 + src/code/UpdatePSResource.cs | 1 + 3 files changed, 4 insertions(+) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 25746c606..1ff4bb836 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -65,12 +65,14 @@ class InstallPSResource : PSCmdlet /// Specifies the scope of installation. /// [Parameter] + [ValidateNotNullOrEmpty] public ScopeType Scope { get; set; } /// /// The destination where the resource is to be temporarily installed /// [Parameter] + [ValidateNotNullOrEmpty] public string TemporaryPath { get diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 7b863614d..de588af86 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -113,6 +113,7 @@ public string Path /// The destination where the resource is to be temporarily installed /// [Parameter] + [ValidateNotNullOrEmpty] public string TemporaryPath { get diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 327dab49f..05c4b5def 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -73,6 +73,7 @@ public sealed class UpdatePSResource : PSCmdlet /// The destination where the resource is to be temporarily installed /// [Parameter] + [ValidateNotNullOrEmpty] public string TemporaryPath { get From 374af5dafe2861dc950623046bd3c57695d41b57 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 16 Aug 2022 13:55:15 -0400 Subject: [PATCH 248/276] revert unintendded change --- src/code/InstallPSResource.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index 1ff4bb836..d646a8c58 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -65,7 +65,6 @@ class InstallPSResource : PSCmdlet /// Specifies the scope of installation. /// [Parameter] - [ValidateNotNullOrEmpty] public ScopeType Scope { get; set; } /// From 0bc8494c23714b03511b894c0d36b42629b704da Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 16 Aug 2022 15:59:29 -0400 Subject: [PATCH 249/276] rename FilePath parameter to Path --- src/code/NewPSScriptFileInfo.cs | 12 ++++++------ src/code/TestPSScriptFileInfo.cs | 12 ++++++------ src/code/UpdatePSScriptFileInfo.cs | 24 ++++++++++++------------ 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/code/NewPSScriptFileInfo.cs b/src/code/NewPSScriptFileInfo.cs index 0e1bf0031..8083383b5 100644 --- a/src/code/NewPSScriptFileInfo.cs +++ b/src/code/NewPSScriptFileInfo.cs @@ -23,7 +23,7 @@ public sealed class NewPSScriptFileInfo : PSCmdlet /// [Parameter(Position = 0, Mandatory = true)] [ValidateNotNullOrEmpty] - public string FilePath { get; set; } + public string Path { get; set; } /// /// The version of the script. @@ -177,7 +177,7 @@ protected override void EndProcessing() ThrowTerminatingError(iconErrorRecord); } - if (!FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + if (!Path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) { var exMessage = "Path needs to end with a .ps1 file. Example: C:/Users/john/x/MyScript.ps1"; var ex = new ArgumentException(exMessage); @@ -185,8 +185,8 @@ protected override void EndProcessing() ThrowTerminatingError(InvalidPathError); } - var resolvedFilePath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(FilePath); - if (String.IsNullOrEmpty(resolvedFilePath)) + var resolvedPath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(Path); + if (String.IsNullOrEmpty(resolvedPath)) { var exMessage = "Error: Could not resolve provided Path argument into a single path."; var ex = new PSArgumentException(exMessage); @@ -194,7 +194,7 @@ protected override void EndProcessing() ThrowTerminatingError(InvalidPathArgumentError); } - if (File.Exists(resolvedFilePath) && !Force) + if (File.Exists(resolvedPath) && !Force) { // .ps1 file at specified location already exists and Force parameter isn't used to rewrite the file var exMessage = ".ps1 file at specified path already exists. Specify a different location or use -Force parameter to overwrite the .ps1 file."; @@ -250,7 +250,7 @@ protected override void EndProcessing() return; } - File.WriteAllLines(resolvedFilePath, psScriptFileContents); + File.WriteAllLines(resolvedPath, psScriptFileContents); } #endregion diff --git a/src/code/TestPSScriptFileInfo.cs b/src/code/TestPSScriptFileInfo.cs index 931d04c7c..9272b1307 100644 --- a/src/code/TestPSScriptFileInfo.cs +++ b/src/code/TestPSScriptFileInfo.cs @@ -23,7 +23,7 @@ public sealed class TestPSScriptFileInfo : PSCmdlet /// [Parameter(Position = 0, Mandatory = true)] [ValidateNotNullOrEmpty] - public string FilePath { get; set; } + public string Path { get; set; } #endregion @@ -31,7 +31,7 @@ public sealed class TestPSScriptFileInfo : PSCmdlet protected override void EndProcessing() { - if (!FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + if (!Path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) { var exMessage = "Path needs to end with a .ps1 file. Example: C:/Users/john/x/MyScript.ps1"; var ex = new ArgumentException(exMessage); @@ -39,7 +39,7 @@ protected override void EndProcessing() ThrowTerminatingError(InvalidPathError); } - var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(FilePath); + var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(Path); if (resolvedPaths.Count != 1) { var exMessage = "Error: Could not resolve provided Path argument into a single path."; @@ -48,9 +48,9 @@ protected override void EndProcessing() ThrowTerminatingError(InvalidPathArgumentError); } - var resolvedFilePath = resolvedPaths[0].Path; + var resolvedPath = resolvedPaths[0].Path; - if (!File.Exists(resolvedFilePath)) + if (!File.Exists(resolvedPath)) { var exMessage = "A .ps1 file does not exist at the location specified."; var ex = new ArgumentException(exMessage); @@ -59,7 +59,7 @@ protected override void EndProcessing() } bool isValidScript = PSScriptFileInfo.TryTestPSScriptFile( - scriptFileInfoPath: resolvedFilePath, + scriptFileInfoPath: resolvedPath, parsedScript: out PSScriptFileInfo _, errors: out ErrorRecord[] errors, out string[] verboseMsgs); diff --git a/src/code/UpdatePSScriptFileInfo.cs b/src/code/UpdatePSScriptFileInfo.cs index 8803873d7..f6a3337c9 100644 --- a/src/code/UpdatePSScriptFileInfo.cs +++ b/src/code/UpdatePSScriptFileInfo.cs @@ -86,7 +86,7 @@ public sealed class UpdatePSScriptFileInfo : PSCmdlet /// [Parameter(Position = 0, Mandatory = true)] [ValidateNotNullOrEmpty] - public string FilePath { get; set; } + public string Path { get; set; } /// /// The private data associated with the script. @@ -177,7 +177,7 @@ protected override void EndProcessing() ThrowTerminatingError(iconErrorRecord); } - if (!FilePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) + if (!Path.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase)) { var exMessage = "File path needs to end with a .ps1 extension. Example: C:/Users/john/x/MyScript.ps1"; var ex = new ArgumentException(exMessage); @@ -185,7 +185,7 @@ protected override void EndProcessing() ThrowTerminatingError(InvalidOrNonExistantPathError); } - var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(FilePath); + var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(Path); if (resolvedPaths.Count != 1) { var exMessage = "Error: Could not resolve provided Path argument into a single path."; @@ -194,9 +194,9 @@ protected override void EndProcessing() ThrowTerminatingError(InvalidPathArgumentError); } - string resolvedFilePath = resolvedPaths[0].Path; + string resolvedPath = resolvedPaths[0].Path; - if (!File.Exists(resolvedFilePath)) + if (!File.Exists(resolvedPath)) { var exMessage = "A script file does not exist at the location specified"; var ex = new ArgumentException(exMessage); @@ -222,7 +222,7 @@ protected override void EndProcessing() } if (!PSScriptFileInfo.TryTestPSScriptFile( - scriptFileInfoPath: resolvedFilePath, + scriptFileInfoPath: resolvedPath, parsedScript: out PSScriptFileInfo parsedScriptInfo, errors: out ErrorRecord[] errors, out string[] verboseMsgs)) @@ -284,13 +284,13 @@ protected override void EndProcessing() return; } - string tempScriptFilePath = null; + string tempScriptPath = null; try { - tempScriptFilePath = Path.GetTempFileName(); + tempScriptPath = System.IO.Path.GetTempFileName(); - File.WriteAllLines(tempScriptFilePath, updatedPSScriptFileContents); - File.Copy(tempScriptFilePath, resolvedFilePath, overwrite: true); + File.WriteAllLines(tempScriptPath, updatedPSScriptFileContents); + File.Copy(tempScriptPath, resolvedPath, overwrite: true); } catch(Exception e) { @@ -302,9 +302,9 @@ protected override void EndProcessing() } finally { - if (tempScriptFilePath != null) + if (tempScriptPath != null) { - File.Delete(tempScriptFilePath); + File.Delete(tempScriptPath); } } From 7281f9b5e7214602036bc50eef758a2818725aa7 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 16 Aug 2022 16:22:23 -0400 Subject: [PATCH 250/276] update .md files to Path instead of FilePath --- help/New-PSScriptFileInfo.md | 10 +++++----- help/Test-PSScriptFileInfo.md | 10 +++++----- help/Update-PSScriptFileInfo.md | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/help/New-PSScriptFileInfo.md b/help/New-PSScriptFileInfo.md index d21f2db2c..c50a0b164 100644 --- a/help/New-PSScriptFileInfo.md +++ b/help/New-PSScriptFileInfo.md @@ -16,7 +16,7 @@ The cmdlet creates a new script file, including metadata about the script. ### __AllParameterSets ``` -New-PSScriptFileInfo [-FilePath] -Description [-Version ] +New-PSScriptFileInfo [-Path] -Description [-Version ] [-Author ] [-Guid ] [-CompanyName ] [-Copyright ] [-RequiredModules ] [-ExternalModuleDependencies ] [-RequiredScripts ] [-ExternalScriptDependencies ] [-Tags ] @@ -33,12 +33,12 @@ package. ### Example 1: Creating an empty script with minimal information -This example runs the cmdlet using only required parameters. The **FilePath** parameter specifies +This example runs the cmdlet using only required parameters. The **Path** parameter specifies the nane and location of the script. The **Description** parameter provide the description used in the comment-based help for the script. ```powershell -New-PSScriptFileInfo -FilePath ./test_script.ps1 -Description "This is a test script." +New-PSScriptFileInfo -Path ./test_script.ps1 -Description "This is a test script." Get-Content ./test_script.ps1 ``` @@ -96,7 +96,7 @@ of hashtables. The **ModuleName** key in the hashtable is required. You can also ```powershell $parameters = @{ - FilePath = './test_script2.ps1' + Path = './test_script2.ps1' Description = 'This is a test script.' Version = '2.0.0.0' Author = 'janedoe' @@ -255,7 +255,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -FilePath +### -Path The filename and location where the script is created. diff --git a/help/Test-PSScriptFileInfo.md b/help/Test-PSScriptFileInfo.md index d05281d09..a9dbe266e 100644 --- a/help/Test-PSScriptFileInfo.md +++ b/help/Test-PSScriptFileInfo.md @@ -15,7 +15,7 @@ Tests the comment-based metadata in a `.ps1` file to ensure it's valid for publi ### __AllParameterSets ``` -Test-PSScriptFileInfo [-FilePath] [] +Test-PSScriptFileInfo [-Path] [] ``` ## DESCRIPTION @@ -31,8 +31,8 @@ This example creates a new script file then runs `Test-PSScriptFileInfo` to vali in the script. ```powershell -New-PSScriptFileInfo -FilePath "C:\MyScripts\test_script.ps1" -Description "this is a test script" -Test-PSScriptFileInfo -FilePath "C:\MyScripts\test_script.ps1" +New-PSScriptFileInfo -Path "C:\MyScripts\test_script.ps1" -Description "this is a test script" +Test-PSScriptFileInfo -Path "C:\MyScripts\test_script.ps1" True ``` @@ -43,7 +43,7 @@ the required **Author** metadata. The cmdlet writes a warning message and return `Get-Content` is used to view the contents of the script file. ```powershell -Test-PSScriptFileInfo -FilePath "C:\MyScripts\invalid_test_script.ps1" +Test-PSScriptFileInfo -Path "C:\MyScripts\invalid_test_script.ps1" Get-Content "C:\MyScripts\invalid_test_script.ps1" ``` @@ -93,7 +93,7 @@ this is a test script ## PARAMETERS -### -FilePath +### -Path The path to `.ps1` script file. diff --git a/help/Update-PSScriptFileInfo.md b/help/Update-PSScriptFileInfo.md index e2ea6848c..37d0d2c21 100644 --- a/help/Update-PSScriptFileInfo.md +++ b/help/Update-PSScriptFileInfo.md @@ -16,7 +16,7 @@ This cmdlet updates the comment-based metadata in an existing script `.ps1` file ### __AllParameterSets ``` -Update-PSScriptFileInfo [-FilePath] [-Author ] [-CompanyName ] +Update-PSScriptFileInfo [-Path] [-Author ] [-CompanyName ] [-Copyright ] [-Description ] [-ExternalModuleDependencies ] [-ExternalScriptDependencies ] [-Guid ] [-IconUri ] [-LicenseUri ] [-PrivateData ] [-ProjectUri ] [-ReleaseNotes ] @@ -38,8 +38,8 @@ changes the **Version**' to `2.0.0.0`. The `Get-Content` cmdlet shows the update script. ```powershell -New-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" -Update-PSScriptFileInfo -FilePath "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" +New-PSScriptFileInfo -Path "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" +Update-PSScriptFileInfo -Path "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" Get-Content "C:\Users\johndoe\MyScripts\test_script.ps1" ``` @@ -184,7 +184,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -FilePath +### -Path The filename and location of the script. From c4a08a167e8843d93c4dab74b7b08f640634faa4 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 16 Aug 2022 16:32:42 -0400 Subject: [PATCH 251/276] update test files to use Path instead of FilePath --- test/NewPSScriptFileInfo.Tests.ps1 | 40 +++++++++---------- test/TestPSScriptFileInfo.Tests.ps1 | 2 +- test/UpdatePSScriptFileInfo.Tests.ps1 | 56 +++++++++++++-------------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/test/NewPSScriptFileInfo.Tests.ps1 b/test/NewPSScriptFileInfo.Tests.ps1 index 4b48ccd57..45f72055c 100644 --- a/test/NewPSScriptFileInfo.Tests.ps1 +++ b/test/NewPSScriptFileInfo.Tests.ps1 @@ -22,8 +22,8 @@ Describe "Test New-PSScriptFileInfo" { It "Create .ps1 file with minimal required fields" { $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $description - Test-PSScriptFileInfo -FilePath $script:testScriptFilePath | Should -BeTrue + New-PSScriptFileInfo -Path $script:testScriptFilePath -Description $description + Test-PSScriptFileInfo -Path $script:testScriptFilePath | Should -BeTrue } It "Create .ps1 file with relative path" { @@ -31,9 +31,9 @@ Describe "Test New-PSScriptFileInfo" { $scriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:PSScriptInfoName.ps1" $description = "Test description" - New-PSScriptFileInfo -FilePath $scriptFilePath -Description $description + New-PSScriptFileInfo -Path $scriptFilePath -Description $description - Test-PSScriptFileInfo -FilePath $scriptFilePath | Should -BeTrue + Test-PSScriptFileInfo -Path $scriptFilePath | Should -BeTrue Remove-Item -Path $scriptFilePath } @@ -41,7 +41,7 @@ Describe "Test New-PSScriptFileInfo" { $version = "2.0.0.0" $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version $version -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -Version $version -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -53,7 +53,7 @@ Describe "Test New-PSScriptFileInfo" { $guid = [guid]::NewGuid() $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Guid $guid -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -Guid $guid -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -65,7 +65,7 @@ Describe "Test New-PSScriptFileInfo" { $author = "Test Author" $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Author $author -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -Author $author -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -76,7 +76,7 @@ Describe "Test New-PSScriptFileInfo" { It "Create new .ps1 given Description parameter" { $description = "PowerShellGet test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -88,7 +88,7 @@ Describe "Test New-PSScriptFileInfo" { $companyName = "Microsoft" $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -CompanyName $companyName -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -CompanyName $companyName -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -100,7 +100,7 @@ Describe "Test New-PSScriptFileInfo" { $copyright = "(c) Test Corporation" $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Copyright $copyright -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -Copyright $copyright -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -115,7 +115,7 @@ Describe "Test New-PSScriptFileInfo" { $description = "Test description" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredModules $RequiredModules -Description $Description + New-PSScriptFileInfo -Path $script:testScriptFilePath -RequiredModules $RequiredModules -Description $Description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -128,7 +128,7 @@ Describe "Test New-PSScriptFileInfo" { $description = "Test Description" $releaseNotes = "Release notes for script." - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ReleaseNotes $releaseNotes -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -ReleaseNotes $releaseNotes -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -141,7 +141,7 @@ Describe "Test New-PSScriptFileInfo" { $tag1 = "tag1" $tag2 = "tag2" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Tags $tag1, $tag2 -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -Tags $tag1, $tag2 -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -154,7 +154,7 @@ Describe "Test New-PSScriptFileInfo" { $description = "Test Description" $projectUri = "https://www.testprojecturi.com/" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ProjectUri $projectUri -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -ProjectUri $projectUri -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -166,7 +166,7 @@ Describe "Test New-PSScriptFileInfo" { $description = "Test Description" $licenseUri = "https://www.testlicenseuri.com/" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -LicenseUri $licenseUri -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -LicenseUri $licenseUri -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -178,7 +178,7 @@ Describe "Test New-PSScriptFileInfo" { $description = "Test Description" $iconUri = "https://www.testiconuri.com/" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -IconUri $iconUri -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -IconUri $iconUri -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -191,7 +191,7 @@ Describe "Test New-PSScriptFileInfo" { $externalModuleDep1 = "ExternalModuleDep1" $externalModuleDep2 = "ExternalModuleDep2" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalModuleDependencies $externalModuleDep1, $externalModuleDep2 -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -ExternalModuleDependencies $externalModuleDep1, $externalModuleDep2 -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -205,7 +205,7 @@ Describe "Test New-PSScriptFileInfo" { $requiredScript1 = "RequiredScript1" $requiredScript2 = "RequiredScript2" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredScripts $requiredScript1, $requiredScript2 -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -RequiredScripts $requiredScript1, $requiredScript2 -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -219,7 +219,7 @@ Describe "Test New-PSScriptFileInfo" { $externalScriptDep1 = "ExternalScriptDep1" $externalScriptDep2 = "ExternalScriptDep2" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalScriptDependencies $externalScriptDep1, $externalScriptDep2 -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -ExternalScriptDependencies $externalScriptDep1, $externalScriptDep2 -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw @@ -231,7 +231,7 @@ Describe "Test New-PSScriptFileInfo" { It "Create new .ps1 given PrivateData parameter" { $description = "Test Description" $privateData = @{"PrivateDataEntry1" = "PrivateDataValue1"} - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -PrivateData $privateData -Description $description + New-PSScriptFileInfo -Path $script:testScriptFilePath -PrivateData $privateData -Description $description Test-Path -Path $script:testScriptFilePath | Should -BeTrue $results = Get-Content -Path $script:testScriptFilePath -Raw diff --git a/test/TestPSScriptFileInfo.Tests.ps1 b/test/TestPSScriptFileInfo.Tests.ps1 index eb1079c22..df837d51f 100644 --- a/test/TestPSScriptFileInfo.Tests.ps1 +++ b/test/TestPSScriptFileInfo.Tests.ps1 @@ -19,7 +19,7 @@ Describe "Test Test-PSScriptFileInfo" { It "determine script file with minimal required fields as valid" { $scriptFilePath = Join-Path -Path $tmpDir1Path -ChildPath "testscript.ps1" $scriptDescription = "this is a test script" - New-PSScriptFileInfo -FilePath $scriptFilePath -Description $scriptDescription + New-PSScriptFileInfo -Path $scriptFilePath -Description $scriptDescription Test-PSScriptFileInfo $scriptFilePath | Should -Be $true } diff --git a/test/UpdatePSScriptFileInfo.Tests.ps1 b/test/UpdatePSScriptFileInfo.Tests.ps1 index 6eac2d1d0..49bd700d8 100644 --- a/test/UpdatePSScriptFileInfo.Tests.ps1 +++ b/test/UpdatePSScriptFileInfo.Tests.ps1 @@ -22,7 +22,7 @@ Describe "Test Update-PSScriptFileInfo" { $script:psScriptInfoName = "test_script" $scriptDescription = "this is a test script" $script:testScriptFilePath = Join-Path -Path $tmpDir1Path -ChildPath "$script:psScriptInfoName.ps1" - New-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $scriptDescription + New-PSScriptFileInfo -Path $script:testScriptFilePath -Description $scriptDescription } AfterEach { @@ -37,10 +37,10 @@ Describe "Test Update-PSScriptFileInfo" { $scriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:psScriptInfoName.ps1" $oldDescription = "Old description for test script" $newDescription = "New description for test script" - New-PSScriptFileInfo -FilePath $scriptFilePath -Description $oldDescription + New-PSScriptFileInfo -Path $scriptFilePath -Description $oldDescription - Update-PSScriptFileInfo -FilePath $scriptFilePath -Description $newDescription - Test-PSScriptFileInfo -FilePath $scriptFilePath | Should -BeTrue + Update-PSScriptFileInfo -Path $scriptFilePath -Description $newDescription + Test-PSScriptFileInfo -Path $scriptFilePath | Should -BeTrue Test-Path -Path $scriptFilePath | Should -BeTrue $results = Get-Content -Path $scriptFilePath -Raw @@ -60,10 +60,10 @@ Describe "Test Update-PSScriptFileInfo" { $relativeCurrentPath = Get-Location $scriptFilePath = Join-Path -Path $relativeCurrentPath -ChildPath "$script:psScriptInfoName.ps1" - New-PSScriptFileInfo -FilePath $scriptFilePath -Description $description -Version $version -Author $author -ProjectUri $projectUri - Update-PSScriptFileInfo -FilePath $scriptFilePath -Author $newAuthor + New-PSScriptFileInfo -Path $scriptFilePath -Description $description -Version $version -Author $author -ProjectUri $projectUri + Update-PSScriptFileInfo -Path $scriptFilePath -Author $newAuthor - Test-PSScriptFileInfo -FilePath $scriptFilePath | Should -BeTrue + Test-PSScriptFileInfo -Path $scriptFilePath | Should -BeTrue $results = Get-Content -Path $scriptFilePath -Raw $results.Contains($newAuthor) | Should -BeTrue $results.Contains(".AUTHOR $newAuthor") | Should -BeTrue @@ -83,7 +83,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file Author property" { $author = "New Author" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Author $author + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Author $author Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -94,7 +94,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file Version property" { $version = "2.0.0.0" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version $version + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Version $version Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -105,7 +105,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file Version property with prerelease version" { $version = "3.0.0-alpha" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version $version + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Version $version Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -115,14 +115,14 @@ Describe "Test Update-PSScriptFileInfo" { } It "not update script file with invalid version" { - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Version "4.0.0.0.0" -ErrorVariable err -ErrorAction SilentlyContinue + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Version "4.0.0.0.0" -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 $err[0].FullyQualifiedErrorId | Should -BeExactly "VersionParseIntoNuGetVersion,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" } It "update script file Description property" { $description = "this is an updated test script" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Description $description + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Description $description Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -133,7 +133,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file Guid property" { $guid = [Guid]::NewGuid(); - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Guid $guid + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Guid $guid Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -144,7 +144,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file CompanyName property" { $companyName = "New Corporation" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -CompanyName $companyName + Update-PSScriptFileInfo -Path $script:testScriptFilePath -CompanyName $companyName Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -155,7 +155,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file Copyright property" { $copyright = "(c) 2022 New Corporation. All rights reserved" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Copyright $copyright + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Copyright $copyright Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -167,7 +167,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file ExternalModuleDependencies property" { $externalModuleDep1 = "ExternalModuleDep1" $externalModuleDep2 = "ExternalModuleDep2" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalModuleDependencies $externalModuleDep1,$externalModuleDep2 + Update-PSScriptFileInfo -Path $script:testScriptFilePath -ExternalModuleDependencies $externalModuleDep1,$externalModuleDep2 Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -180,7 +180,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file ExternalScriptDependencies property" { $externalScriptDep1 = "ExternalScriptDep1" $externalScriptDep2 = "ExternalScriptDep2" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ExternalScriptDependencies $externalScriptDep1,$externalScriptDep2 + Update-PSScriptFileInfo -Path $script:testScriptFilePath -ExternalScriptDependencies $externalScriptDep1,$externalScriptDep2 Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -192,7 +192,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file IconUri property" { $iconUri = "https://testscript.com/icon" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -IconUri $iconUri + Update-PSScriptFileInfo -Path $script:testScriptFilePath -IconUri $iconUri Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -203,7 +203,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file LicenseUri property" { $licenseUri = "https://testscript.com/license" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -LicenseUri $licenseUri + Update-PSScriptFileInfo -Path $script:testScriptFilePath -LicenseUri $licenseUri Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -214,7 +214,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file ProjectUri property" { $projectUri = "https://testscript.com/" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ProjectUri $projectUri + Update-PSScriptFileInfo -Path $script:testScriptFilePath -ProjectUri $projectUri Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -225,7 +225,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file PrivateData property" { $privateData = "this is some private data" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -PrivateData $privateData + Update-PSScriptFileInfo -Path $script:testScriptFilePath -PrivateData $privateData Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -236,7 +236,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file ReleaseNotes property" { $releaseNotes = "Release notes for script." - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -ReleaseNotes $releaseNotes + Update-PSScriptFileInfo -Path $script:testScriptFilePath -ReleaseNotes $releaseNotes Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -252,7 +252,7 @@ Describe "Test Update-PSScriptFileInfo" { $hashtable4 = @{ModuleName = "RequiredModule4"; ModuleVersion = "1.1.0.0"; MaximumVersion = "2.0.0.0"} $requiredModules = $hashtable1, $hashtable2, $hashtable3, $hashtable4 - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredModules $requiredModules + Update-PSScriptFileInfo -Path $script:testScriptFilePath -RequiredModules $requiredModules Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -264,7 +264,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file RequiredScripts property" { $requiredScript1 = "RequiredScript1" $requiredScript2 = "RequiredScript2" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -RequiredScripts $requiredScript1, $requiredScript2 + Update-PSScriptFileInfo -Path $script:testScriptFilePath -RequiredScripts $requiredScript1, $requiredScript2 Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -277,7 +277,7 @@ Describe "Test Update-PSScriptFileInfo" { It "update script file Tags property" { $tag1 = "tag1" $tag2 = "tag2" - Update-PSScriptFileInfo -FilePath $script:testScriptFilePath -Tags $tag1, $tag2 + Update-PSScriptFileInfo -Path $script:testScriptFilePath -Tags $tag1, $tag2 Test-PSScriptFileInfo $script:testScriptFilePath | Should -Be $true Test-Path -Path $script:testScriptFilePath | Should -BeTrue @@ -297,7 +297,7 @@ Describe "Test Update-PSScriptFileInfo" { $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName - { Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" } | Should -Throw -ErrorId "ScriptToBeUpdatedContainsSignature,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" + { Update-PSScriptFileInfo -Path $tmpScriptFilePath -Version "2.0.0.0" } | Should -Throw -ErrorId "ScriptToBeUpdatedContainsSignature,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSScriptFileInfo" } It "update signed script when using RemoveSignature parameter" { @@ -308,7 +308,7 @@ Describe "Test Update-PSScriptFileInfo" { $null = Copy-Item -Path $scriptFilePath -Destination $TestDrive $tmpScriptFilePath = Join-Path -Path $TestDrive -ChildPath $scriptName - Update-PSScriptFileInfo -FilePath $tmpScriptFilePath -Version "2.0.0.0" -RemoveSignature - Test-PSScriptFileInfo -FilePath $tmpScriptFilePath | Should -Be $true + Update-PSScriptFileInfo -Path $tmpScriptFilePath -Version "2.0.0.0" -RemoveSignature + Test-PSScriptFileInfo -Path $tmpScriptFilePath | Should -Be $true } } From 5f2cf6cf764e04b0ad935781570f8ee3c8d07ecd Mon Sep 17 00:00:00 2001 From: Alyssa Vu <49544763+alyssa1303@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:19:35 -0400 Subject: [PATCH 252/276] Change wording Co-authored-by: Anam Navied --- src/code/SavePSResource.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index de588af86..e0b6c19c7 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -110,7 +110,8 @@ public string Path private string _path; /// - /// The destination where the resource is to be temporarily installed + /// The destination where the resource is to be temporarily saved to. + /// [Parameter] [ValidateNotNullOrEmpty] From aadaed3180cfdd5d56792f0961f1a27f3c4efb74 Mon Sep 17 00:00:00 2001 From: Alyssa Vu <49544763+alyssa1303@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:19:50 -0400 Subject: [PATCH 253/276] Change wording Co-authored-by: Anam Navied --- src/code/UpdatePSResource.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 05c4b5def..27a62eaa1 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -70,7 +70,8 @@ public sealed class UpdatePSResource : PSCmdlet public ScopeType Scope { get; set; } /// - /// The destination where the resource is to be temporarily installed + /// The destination where the resource is to be temporarily installed to while updating. + /// [Parameter] [ValidateNotNullOrEmpty] From 01c791d41699e354e790c10687ed3af483dc3e65 Mon Sep 17 00:00:00 2001 From: Alyssa Vu <49544763+alyssa1303@users.noreply.github.com> Date: Wed, 17 Aug 2022 14:19:35 -0400 Subject: [PATCH 254/276] remove toString() Co-authored-by: Paul Higinbotham --- src/code/InstallHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index b1ca33ee8..dfa0c66cb 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -100,7 +100,8 @@ public List InstallPackages( asNupkg.ToString(), includeXml.ToString(), savePkg.ToString(), - tmpPath != null ? tmpPath.ToString() : string.Empty)); + tmpPath ?? string.Empty)); + _versionRange = versionRange; _prerelease = prerelease; From 74faf4a441e9133dd081cf3a0a485fd4ecad3aac Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Wed, 17 Aug 2022 18:25:51 -0400 Subject: [PATCH 255/276] throw error for wildcard usage and unresolved path --- src/code/InstallPSResource.cs | 17 +++++++---------- src/code/SavePSResource.cs | 17 +++++++---------- src/code/UpdatePSResource.cs | 17 +++++++---------- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index d646a8c58..b27b48093 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -79,16 +79,13 @@ public string TemporaryPath set { - if (!string.IsNullOrEmpty(value)) - { - string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - - // Path where resource is temporarily saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _tmpPath = resolvedPath; - } - } + if (WildcardPattern.ContainsWildcardCharacters(value)) + { + throw new PSArgumentException("Wildcard characters are not allowed in the temporary path."); + } + + // This will throw if path cannot be resolved + _tmpPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } } private string _tmpPath; diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index e0b6c19c7..9c92a261f 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -122,16 +122,13 @@ public string TemporaryPath set { - if (!string.IsNullOrEmpty(value)) - { - string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - - // Path where resource is temporarily saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _tmpPath = resolvedPath; - } - } + if (WildcardPattern.ContainsWildcardCharacters(value)) + { + throw new PSArgumentException("Wildcard characters are not allowed in the temporary path."); + } + + // This will throw if path cannot be resolved + _tmpPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } } private string _tmpPath; diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index 27a62eaa1..c670c0afe 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -82,16 +82,13 @@ public string TemporaryPath set { - if (!string.IsNullOrEmpty(value)) - { - string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - - // Path where resource is temporarily saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _tmpPath = resolvedPath; - } - } + if (WildcardPattern.ContainsWildcardCharacters(value)) + { + throw new PSArgumentException("Wildcard characters are not allowed in the temporary path."); + } + + // This will throw if path cannot be resolved + _tmpPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } } private string _tmpPath; From 806622fef9c6b2aa54035c3f09697d0891f5e265 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Wed, 17 Aug 2022 18:45:08 -0400 Subject: [PATCH 256/276] update .md files to add a new parameter --- help/Install-PSResource.md | 18 +++++++++++++++++- help/Save-PSResource.md | 18 +++++++++++++++++- help/Update-PSResource.md | 18 +++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/help/Install-PSResource.md b/help/Install-PSResource.md index 28eb45d6f..eb12f1aae 100644 --- a/help/Install-PSResource.md +++ b/help/Install-PSResource.md @@ -17,7 +17,7 @@ Installs resources from a registered repository. ``` Install-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-Scope ] [-TrustRepository] [-Reinstall] [-Quiet] + [-Credential ] [-Scope ] [-TemporaryPath ] [-TrustRepository] [-Reinstall] [-Quiet] [-AcceptLicense] [-NoClobber] [-SkipDependencyCheck] [-AuthenticodeCheck] [-PassThru] [-WhatIf] [-Confirm] [] ``` @@ -224,6 +224,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -TemporaryPath + +Specifies the path to temporarily install the resource before actual installation. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Prerelease When specified, includes prerelease versions in search results returned. diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index 2029fb6d4..e98cf87b3 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -17,7 +17,7 @@ Saves resources (modules and scripts) from a registered repository onto the mach ``` Save-PSResource [-Name] [-Version ] [-Prerelease] [-Repository ] - [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TrustRepository] + [-Credential ] [-AsNupkg] [-IncludeXML] [-Path ] [-TemporaryPath ] [-TrustRepository] [-PassThru] [-SkipDependencyCheck] [-AuthenticodeCheck] [-Quiet] [-WhatIf] [-Confirm] [] ``` @@ -207,6 +207,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -TemporaryPath + +Specifies the path to temporarily install the resource before saving. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Prerelease When specified, includes prerelease versions in search results returned. diff --git a/help/Update-PSResource.md b/help/Update-PSResource.md index bdfa732ad..d527d3611 100644 --- a/help/Update-PSResource.md +++ b/help/Update-PSResource.md @@ -17,7 +17,7 @@ Downloads and installs the newest version of a package already installed on the ``` Update-PSResource [[-Name] ] [-Version ] [-Prerelease] [-Repository ] - [-Scope ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] + [-Scope ] [-TemporaryPath ] [-TrustRepository] [-Credential ] [-Quiet] [-AcceptLicense] [-Force] [-PassThru] [-SkipDependencyCheck] [-AuthenticodeCheck] [-WhatIf] [-Confirm] [] ``` @@ -162,6 +162,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -TemporaryPath + +Specifies the path to temporarily install the resource before actual installatoin. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Prerelease When specified, allows updating to a prerelease version. From faab902ca44ef30011eb57c42422620ca1a676ff Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 18 Aug 2022 15:34:57 -0700 Subject: [PATCH 257/276] Add String and SecureString to acceptable credential types in PSCredentialInfo (#764) --- src/code/PSCredentialInfo.cs | 17 ++++++++++++++++- test/PSCredentialInfo.Tests.ps1 | 34 ++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/code/PSCredentialInfo.cs b/src/code/PSCredentialInfo.cs index 11ec0f198..e6155a3fe 100644 --- a/src/code/PSCredentialInfo.cs +++ b/src/code/PSCredentialInfo.cs @@ -3,6 +3,8 @@ using System; using System.Management.Automation; +using System.Net; +using System.Security; namespace Microsoft.PowerShell.PowerShellGet.UtilClasses { @@ -43,7 +45,20 @@ public PSCredentialInfo(PSObject psObject) VaultName = (string) psObject.Properties[PSCredentialInfo.VaultNameAttribute]?.Value; SecretName = (string) psObject.Properties[PSCredentialInfo.SecretNameAttribute]?.Value; - Credential = (PSCredential) psObject.Properties[PSCredentialInfo.CredentialAttribute]?.Value; + + var credentialAttr = psObject.Properties[PSCredentialInfo.CredentialAttribute]?.Value; + if (credentialAttr is string credStr) + { + Credential = new PSCredential("PSGetUser", new NetworkCredential("", credStr).SecurePassword); + } + else if ((credentialAttr as PSObject)?.BaseObject is SecureString credSS) + { + Credential = new PSCredential("PSGetUser", credSS); + } + else if (credentialAttr is PSCredential psCred) + { + Credential = psCred; + } } #endregion diff --git a/test/PSCredentialInfo.Tests.ps1 b/test/PSCredentialInfo.Tests.ps1 index 18775ef03..5ae827ddb 100644 --- a/test/PSCredentialInfo.Tests.ps1 +++ b/test/PSCredentialInfo.Tests.ps1 @@ -23,7 +23,7 @@ Describe "Create PSCredentialInfo with VaultName and SecretName" -tags 'CI' { Describe "Create PSCredentialInfo with VaultName, SecretName, and Credential" -tags 'CI' { It "Creates PSCredentialInfo successfully if Credential is null" { - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $null) + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") $credentialInfo.VaultName | Should -Be "testvault" $credentialInfo.SecretName | Should -Be "testsecret" @@ -63,7 +63,7 @@ Describe "Create PSCredentialInfo from a PSObject" -tags 'CI' { $credentialInfo.SecretName | Should -Be "testsecret" } - It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and Credential" { + It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and PSCredential Credential" { $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString "password" -AsPlainText -Force)) $properties = [PSCustomObject]@{ VaultName = "testvault" @@ -77,6 +77,34 @@ Describe "Create PSCredentialInfo from a PSObject" -tags 'CI' { $credentialInfo.SecretName | Should -Be "testsecret" $credentialInfo.Credential.UserName | Should -Be "username" $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" - + } + + It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and string Credential" { + $properties = [PSCustomObject]@{ + VaultName = "testvault" + SecretName = "testsecret" + Credential = "password" + } + + $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties + + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" + } + + It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and SecureString Credential" { + $secureString = ConvertTo-SecureString "password" -AsPlainText -Force + $properties = [PSCustomObject]@{ + VaultName = "testvault" + SecretName = "testsecret" + Credential = $secureString + } + + $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties + + $credentialInfo.VaultName | Should -Be "testvault" + $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" } } From 961fc7d591cce6cd6fbb28803c3425328cf68f7c Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Thu, 18 Aug 2022 15:43:28 -0700 Subject: [PATCH 258/276] Expand acceptable Path arguments for Publish-PSResource (#704) --- src/code/PublishPSResource.cs | 187 ++++++++++++++++++++----------- src/code/Utils.cs | 18 +-- test/PublishPSResource.Tests.ps1 | 49 ++++++++ 3 files changed, 179 insertions(+), 75 deletions(-) diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 482f116fa..31c3d85f9 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -115,7 +115,7 @@ public PSCredential ProxyCredential { #region Members - private string _path; + private string resolvedPath; private CancellationToken _cancellationToken; private NuGetVersion _pkgVersion; private string _pkgName; @@ -123,6 +123,10 @@ public PSCredential ProxyCredential { public const string PSDataFileExt = ".psd1"; public const string PSScriptFileExt = ".ps1"; private const string PSScriptInfoCommentString = "<#PSScriptInfo"; + private string pathToScriptFileToPublish = string.Empty; + private string pathToModuleManifestToPublish = string.Empty; + private string pathToModuleDirToPublish = string.Empty; + private ResourceType resourceType = ResourceType.None; #endregion @@ -136,22 +140,49 @@ protected override void BeginProcessing() // This is to create a better experience for those who have just installed v3 and want to get up and running quickly RepositorySettings.CheckRepositoryStore(); - string resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path).First().Path; - - if (Directory.Exists(resolvedPath) || - (File.Exists(resolvedPath) && resolvedPath.EndsWith(PSScriptFileExt, StringComparison.OrdinalIgnoreCase))) + try { - // condition 1: we point to a folder when publishing a module - // condition 2: we point to a .ps1 file directly when publishing a script, but not to .psd1 file (for publishing a module) - _path = resolvedPath; + resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(Path).First().Path; } - else + catch (MethodInvocationException) + { + // path does not exist + ThrowTerminatingError( + new ErrorRecord( + new ArgumentException( + "The path to the resource to publish does not exist, point to an existing path or file of the module or script to publish."), + "SourcePathDoesNotExist", + ErrorCategory.InvalidArgument, + this)); + } + + // Condition 1: path is to the root directory of the module to be published + // Condition 2: path is to the .psd1 or .ps1 of the module/script to be published + if (string.IsNullOrEmpty(resolvedPath)) { // unsupported file path - var exMessage = string.Format("Either the path to the resource to publish does not exist or is not in the correct format, for scripts point to .ps1 file and for modules point to folder containing .psd1"); - var ex = new ArgumentException(exMessage); - var InvalidSourcePathError = new ErrorRecord(ex, "InvalidSourcePath", ErrorCategory.InvalidArgument, null); - ThrowTerminatingError(InvalidSourcePathError); + ThrowTerminatingError( + new ErrorRecord( + new ArgumentException( + "The path to the resource to publish is not in the correct format, point to a path or file of the module or script to publish."), + "InvalidSourcePath", + ErrorCategory.InvalidArgument, + this)); + } + else if (Directory.Exists(resolvedPath)) + { + pathToModuleDirToPublish = resolvedPath; + resourceType = ResourceType.Module; + } + else if (resolvedPath.EndsWith(PSDataFileExt, StringComparison.OrdinalIgnoreCase)) + { + pathToModuleManifestToPublish = resolvedPath; + resourceType = ResourceType.Module; + } + else if (resolvedPath.EndsWith(PSScriptFileExt, StringComparison.OrdinalIgnoreCase)) + { + pathToScriptFileToPublish = resolvedPath; + resourceType = ResourceType.Script; } if (!String.IsNullOrEmpty(DestinationPath)) @@ -182,25 +213,19 @@ protected override void BeginProcessing() protected override void EndProcessing() { // Returns the name of the file or the name of the directory, depending on path - var pkgFileOrDir = new DirectoryInfo(_path); - bool isScript = _path.EndsWith(PSScriptFileExt, StringComparison.OrdinalIgnoreCase); - - if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine", _path))) + if (!ShouldProcess(string.Format("Publish resource '{0}' from the machine", resolvedPath))) { WriteVerbose("ShouldProcess is set to false."); return; } - string resourceFilePath; Hashtable parsedMetadata; - if (isScript) + if (resourceType == ResourceType.Script) { - resourceFilePath = pkgFileOrDir.FullName; - // Check that script metadata is valid if (!TryParseScriptMetadata( out parsedMetadata, - resourceFilePath, + pathToScriptFileToPublish, out ErrorRecord[] errors)) { foreach (ErrorRecord err in errors) @@ -211,19 +236,38 @@ protected override void EndProcessing() return; } - // remove '.ps1' extension from file name - _pkgName = pkgFileOrDir.Name.Remove(pkgFileOrDir.Name.Length - 4); + _pkgName = System.IO.Path.GetFileNameWithoutExtension(pathToScriptFileToPublish); } else { - _pkgName = pkgFileOrDir.Name; - resourceFilePath = System.IO.Path.Combine(_path, _pkgName + PSDataFileExt); + // parsedMetadata needs to be initialized for modules, will later be passed in to create nuspec parsedMetadata = new Hashtable(); + if (!string.IsNullOrEmpty(pathToModuleManifestToPublish)) + { + _pkgName = System.IO.Path.GetFileNameWithoutExtension(pathToModuleManifestToPublish); + } + else { + // directory + // search for module manifest + List childFiles = new DirectoryInfo(pathToModuleDirToPublish).EnumerateFiles().ToList(); + + foreach (FileInfo file in childFiles) + { + if (file.Name.EndsWith(PSDataFileExt, StringComparison.OrdinalIgnoreCase)) + { + pathToModuleManifestToPublish = file.FullName; + _pkgName = System.IO.Path.GetFileNameWithoutExtension(file.Name); + + break; + } + } + } // Validate that there's a module manifest - if (!File.Exists(resourceFilePath)) + if (!File.Exists(pathToModuleManifestToPublish)) { - var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", resourceFilePath); + var message = String.Format("No file with a .psd1 extension was found in {0}. Please specify a path to a valid modulemanifest.", pathToModuleManifestToPublish); + var ex = new ArgumentException(message); var moduleManifestNotFound = new ErrorRecord(ex, "moduleManifestNotFound", ErrorCategory.ObjectNotFound, null); WriteError(moduleManifestNotFound); @@ -235,7 +279,7 @@ protected override void EndProcessing() string[] errorMsgs = null; try { - Utils.ValidateModuleManifest(resourceFilePath, out errorMsgs); + Utils.ValidateModuleManifest(pathToModuleManifestToPublish, out errorMsgs); } finally { @@ -252,22 +296,19 @@ protected override void EndProcessing() // Create a temp folder to push the nupkg to and delete it later string outputDir = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString()); - if (!Directory.Exists(outputDir)) + try { - try - { - Directory.CreateDirectory(outputDir); - } - catch (Exception e) - { - var ex = new ArgumentException(e.Message); - var ErrorCreatingTempDir = new ErrorRecord(ex, "ErrorCreatingTempDir", ErrorCategory.InvalidData, null); - WriteError(ErrorCreatingTempDir); - - return; - } + Directory.CreateDirectory(outputDir); } + catch (Exception e) + { + var ex = new ArgumentException(e.Message); + var ErrorCreatingTempDir = new ErrorRecord(ex, "ErrorCreatingTempDir", ErrorCategory.InvalidData, null); + WriteError(ErrorCreatingTempDir); + return; + } + try { // Create a nuspec @@ -278,8 +319,7 @@ protected override void EndProcessing() { nuspec = CreateNuspec( outputDir: outputDir, - filePath: resourceFilePath, - isScript: isScript, + filePath: (resourceType == ResourceType.Script) ? pathToScriptFileToPublish : pathToModuleManifestToPublish, parsedMetadataHash: parsedMetadata, requiredModules: out dependencies); } @@ -334,33 +374,50 @@ protected override void EndProcessing() } } - if (isScript) + if (resourceType == ResourceType.Script) { // copy the script file to the temp directory - File.Copy(_path, System.IO.Path.Combine(outputDir, _pkgName + PSScriptFileExt), true); + File.Copy(pathToScriptFileToPublish, System.IO.Path.Combine(outputDir, _pkgName + PSScriptFileExt), true); + } else { - // Create subdirectory structure in temp folder - foreach (string dir in System.IO.Directory.GetDirectories(_path, "*", System.IO.SearchOption.AllDirectories)) + try { - var dirName = dir.Substring(_path.Length).Trim(_PathSeparators); - System.IO.Directory.CreateDirectory(System.IO.Path.Combine(outputDir, dirName)); - } + // If path is pointing to a file, get the parent directory, otherwise assumption is that path is pointing to the root directory + string rootModuleDir = !string.IsNullOrEmpty(pathToModuleManifestToPublish) ? System.IO.Path.GetDirectoryName(pathToModuleManifestToPublish) : pathToModuleDirToPublish; - // Copy files over to temp folder - foreach (string fileNamePath in System.IO.Directory.GetFiles(_path, "*", System.IO.SearchOption.AllDirectories)) - { - var fileName = fileNamePath.Substring(_path.Length).Trim(_PathSeparators); + // Create subdirectory structure in temp folder + foreach (string dir in System.IO.Directory.GetDirectories(rootModuleDir, "*", System.IO.SearchOption.AllDirectories)) + { + DirectoryInfo dirInfo = new DirectoryInfo(dir); + System.IO.Directory.CreateDirectory(System.IO.Path.Combine(outputDir, dirInfo.Name)); + } - // The user may have a .nuspec defined in the module directory - // If that's the case, we will not use that file and use the .nuspec that is generated via PSGet - // The .nuspec that is already in in the output directory is the one that was generated via the CreateNuspec method - var newFilePath = System.IO.Path.Combine(outputDir, fileName); - if (!File.Exists(newFilePath)) + // Copy files over to temp folder + foreach (string fileNamePath in System.IO.Directory.GetFiles(rootModuleDir, "*", System.IO.SearchOption.AllDirectories)) { - System.IO.File.Copy(fileNamePath, newFilePath); + FileInfo fileInfo = new FileInfo(fileNamePath); + + var newFilePath = System.IO.Path.Combine(outputDir, fileInfo.Name); + // The user may have a .nuspec defined in the module directory + // If that's the case, we will not use that file and use the .nuspec that is generated via PSGet + // The .nuspec that is already in in the output directory is the one that was generated via the CreateNuspec method + if (!File.Exists(newFilePath)) + { + System.IO.File.Copy(fileNamePath, newFilePath); + } } + + + } + catch (Exception e) + { + ThrowTerminatingError(new ErrorRecord( + new ArgumentException("Error occured while creating directory to publish: " + e.Message), + "ErrorCreatingDirectoryToPublish", + ErrorCategory.InvalidOperation, + this)); } } @@ -419,7 +476,6 @@ protected override void EndProcessing() private string CreateNuspec( string outputDir, string filePath, - bool isScript, Hashtable parsedMetadataHash, out Hashtable requiredModules) { @@ -428,7 +484,7 @@ private string CreateNuspec( // A script will already have the metadata parsed into the parsedMetadatahash, // a module will still need the module manifest to be parsed. - if (!isScript) + if (resourceType == ResourceType.Module) { // Use the parsed module manifest data as 'parsedMetadataHash' instead of the passed-in data. if (!Utils.TryReadManifestFile( @@ -570,7 +626,7 @@ private string CreateNuspec( metadataElementsDictionary.Add("copyright", parsedMetadataHash["copyright"].ToString().Trim()); } - string tags = isScript ? "PSScript" : "PSModule"; + string tags = (resourceType == ResourceType.Script) ? "PSScript" : "PSModule"; if (parsedMetadataHash.ContainsKey("tags")) { if (parsedMetadataHash["tags"] != null) @@ -972,7 +1028,6 @@ private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, o string publishLocation = repoUri.EndsWith("/v2", StringComparison.OrdinalIgnoreCase) ? repoUri + "/package" : repoUri; var settings = NuGet.Configuration.Settings.LoadDefaultSettings(null, null, null); - ILogger log = new NuGetLogger(); var success = false; try { @@ -989,7 +1044,7 @@ private bool PushNupkg(string outputNupkgDir, string repoName, string repoUri, o noSymbols: false, noServiceEndpoint: false, // enable server endpoint skipDuplicate: false, // if true-- if a package and version already exists, skip it and continue with the next package in the push, if any. - logger: log // nuget logger + logger: NullLogger.Instance // nuget logger ).GetAwaiter().GetResult(); } catch (HttpRequestException e) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 66beebdf5..1ddbdb226 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -614,16 +614,16 @@ public static string GetInstalledPackageName(string pkgPath) // expecting the full version module path // ex: ./PowerShell/Modules/TestModule/1.0.0 return new DirectoryInfo(pkgPath).Parent.Name; - } - - // Find all potential resource paths + } + + // Find all potential resource paths public static List GetPathsFromEnvVarAndScope( PSCmdlet psCmdlet, ScopeType? scope) - { - GetStandardPlatformPaths( - psCmdlet, - out string myDocumentsPath, + { + GetStandardPlatformPaths( + psCmdlet, + out string myDocumentsPath, out string programFilesPath); List resourcePaths = new List(); @@ -653,7 +653,7 @@ public static List GetPathsFromEnvVarAndScope( public static List GetAllResourcePaths( PSCmdlet psCmdlet, ScopeType? scope = null) - { + { List resourcePaths = GetPathsFromEnvVarAndScope(psCmdlet, scope); // resourcePaths should now contain, eg: @@ -703,7 +703,7 @@ public static List GetAllResourcePaths( public static List GetAllInstallationPaths( PSCmdlet psCmdlet, ScopeType? scope) - { + { List installationPaths = GetPathsFromEnvVarAndScope(psCmdlet, scope); installationPaths = installationPaths.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index f2368978c..f1b1baf22 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -67,6 +67,9 @@ Describe "Test Publish-PSResource" { $pkgsToDelete = Join-Path -Path "$script:repositoryPath2" -ChildPath "*" Remove-Item $pkgsToDelete -Recurse + + $pkgsToDelete = Join-Path -Path $script:PublishModuleBase -ChildPath "*" + Remove-Item $pkgsToDelete -Recurse -ErrorAction SilentlyContinue } It "Publish a module with -Path to the highest priority repo" { @@ -89,6 +92,52 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath } + It "Publish a module with -Path pointing to a module directory (parent directory has same name)" { + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } + + It "Publish a module with -Path pointing to a module directory (parent directory has different name)" { + $version = "1.0.0" + $newModuleRoot = Join-Path -Path $script:PublishModuleBase -ChildPath "NewTestParentDirectory" + New-Item -Path $newModuleRoot -ItemType Directory + New-ModuleManifest -Path (Join-Path -Path $newModuleRoot -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $newModuleRoot -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } + + It "Publish a module with -Path pointing to a .psd1 (parent directory has same name)" { + $version = "1.0.0" + $manifestPath = Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1" + New-ModuleManifest -Path $manifestPath -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $manifestPath -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } + + It "Publish a module with -Path pointing to a .psd1 (parent directory has different name)" { + $version = "1.0.0" + $newModuleRoot = Join-Path -Path $script:PublishModuleBase -ChildPath "NewTestParentDirectory" + New-Item -Path $newModuleRoot -ItemType Directory + $manifestPath = Join-Path -Path $newModuleRoot -ChildPath "$script:PublishModuleName.psd1" + New-ModuleManifest -Path $manifestPath -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $manifestPath -Repository $testRepository2 + + $expectedPath = Join-Path -Path $script:repositoryPath2 -ChildPath "$script:PublishModuleName.$version.nupkg" + (Get-ChildItem $script:repositoryPath2).FullName | Should -Be $expectedPath + } + It "Publish a module with dependencies" { # Create dependency module $dependencyVersion = "2.0.0" From 233f2c884d0687f0b1d1ef68e32ef75484629e17 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 22 Aug 2022 11:03:27 -0400 Subject: [PATCH 259/276] remove inheritance and fix test --- src/code/InstallHelper.cs | 6 +++--- test/InstallPSResource.Tests.ps1 | 27 +++++++++++++++++++++------ test/SavePSResource.Tests.ps1 | 27 +++++++++++++++++++++------ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 75f6d54f2..cabfbeae1 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -27,7 +27,7 @@ namespace Microsoft.PowerShell.PowerShellGet.Cmdlets /// /// Install helper class /// - internal class InstallHelper : PSCmdlet + internal class InstallHelper { #region Members @@ -507,7 +507,7 @@ private List InstallPackage( _cmdletPassedIn, out ErrorRecord errorRecord)) { - ThrowTerminatingError(errorRecord); + _cmdletPassedIn.ThrowTerminatingError(errorRecord); } if (isModule) @@ -529,7 +529,7 @@ private List InstallPackage( manifestInfo: out Hashtable parsedMetadataHashtable, error: out Exception manifestReadError)) { - WriteError( + _cmdletPassedIn.WriteError( new ErrorRecord( exception: manifestReadError, errorId: "ManifestFileReadParseError", diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index bef8111ae..cf21a7872 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -461,14 +461,24 @@ Describe 'Test Install-PSResource for Module' { # Install module that is not authenticode signed # Should FAIL to install the module It "Install module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + try { + Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } + # Install 1.4.4.1 (with incorrect catalog file) # Should FAIL to install the module It "Install module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + try + { + Install-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } # Install script that is signed @@ -484,8 +494,13 @@ Describe 'Test Install-PSResource for Module' { # Install script that is not signed # Should throw It "Install script that is not signed" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + try + { + Install-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } } diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 2d5e2e27f..9b19fd3db 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -257,15 +257,25 @@ Describe 'Test Save-PSResource for PSResources' { # Save module that is not authenticode signed # Should FAIL to save the module It "Save module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { - Save-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + try + { + Save-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } # Save 1.4.4.1 (with incorrect catalog file) # Should FAIL to save the module It "Save module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { - Save-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + try + { + Save-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } # Save script that is signed @@ -282,8 +292,13 @@ Describe 'Test Save-PSResource for PSResources' { # Save script that is not signed # Should throw It "Save script that is not signed" -Skip:(!(Get-IsWindows)) { - Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + try + { + Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } <# From dc18766e937260b39c0e8a7797001dfcc6c17166 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 22 Aug 2022 11:22:35 -0400 Subject: [PATCH 260/276] fix code style --- test/InstallPSResource.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index cf21a7872..6ad4b94f1 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -461,7 +461,8 @@ Describe 'Test Install-PSResource for Module' { # Install module that is not authenticode signed # Should FAIL to install the module It "Install module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { - try { + try + { Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue } catch From c1e3b3f06a6a6c1233a2615c832f1764314a165f Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 22 Aug 2022 12:06:53 -0400 Subject: [PATCH 261/276] fix test for UpdatePSResource --- test/UpdatePSResource.Tests.ps1 | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 901a5a0bc..129825c1f 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -351,9 +351,14 @@ Describe 'Test Update-PSResource' { # Update to module 1.4.4.1 (with incorrect catalog file) # Should FAIL to update the module It "Update module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" + try + { + Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" } # Update script that is signed @@ -370,8 +375,13 @@ Describe 'Test Update-PSResource' { # Update script that is not signed # Should throw It "Update script that is not signed" -Skip:(!(Get-IsWindows)) { - Install-PSResource -Name "TestTestScript" -Version "1.0" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - $Error[0].FullyQualifiedErrorId | Should -be "InstallPackageFailed,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" + try + { + Install-PSResource -Name "TestTestScript" -Version "1.0" -Repository $PSGalleryName -TrustRepository + Update-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + } + catch + {} + $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" } } From 49cb40dc7eff5efb4196d4136cd0b994612c9b8c Mon Sep 17 00:00:00 2001 From: Alyssa Vu <49544763+alyssa1303@users.noreply.github.com> Date: Mon, 22 Aug 2022 12:39:38 -0400 Subject: [PATCH 262/276] Update test/InstallPSResource.Tests.ps1 Co-authored-by: Paul Higinbotham --- test/InstallPSResource.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index 6ad4b94f1..c14ff018d 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -463,7 +463,8 @@ Describe 'Test Install-PSResource for Module' { It "Install module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { try { - Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue + { Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId 'GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource' + } catch {} From 4aebaf2e4a0fff340a657a3bfb2ddbcd036460d4 Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Mon, 22 Aug 2022 13:28:18 -0400 Subject: [PATCH 263/276] use should throw instead of try/catch --- test/InstallPSResource.Tests.ps1 | 25 +++---------------------- test/SavePSResource.Tests.ps1 | 24 +++--------------------- test/UpdatePSResource.Tests.ps1 | 20 ++++---------------- 3 files changed, 10 insertions(+), 59 deletions(-) diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index c14ff018d..b9ab10495 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -461,26 +461,13 @@ Describe 'Test Install-PSResource for Module' { # Install module that is not authenticode signed # Should FAIL to install the module It "Install module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { - try - { - { Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId 'GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource' - - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + { Install-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } # Install 1.4.4.1 (with incorrect catalog file) # Should FAIL to install the module It "Install module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { - try - { - Install-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + { Install-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } # Install script that is signed @@ -496,13 +483,7 @@ Describe 'Test Install-PSResource for Module' { # Install script that is not signed # Should throw It "Install script that is not signed" -Skip:(!(Get-IsWindows)) { - try - { - Install-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" + { Install-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.InstallPSResource" } } diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 9b19fd3db..3366cdec5 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -257,25 +257,13 @@ Describe 'Test Save-PSResource for PSResources' { # Save module that is not authenticode signed # Should FAIL to save the module It "Save module that is not authenticode signed" -Skip:(!(Get-IsWindows)) { - try - { - Save-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + { Save-PSResource -Name $testModuleName -Version "5.0.0" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir } | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } # Save 1.4.4.1 (with incorrect catalog file) # Should FAIL to save the module It "Save module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { - try - { - Save-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + { Save-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir } | Should -Throw -ErrorId "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } # Save script that is signed @@ -292,13 +280,7 @@ Describe 'Test Save-PSResource for PSResources' { # Save script that is not signed # Should throw It "Save script that is not signed" -Skip:(!(Get-IsWindows)) { - try - { - Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + { Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } <# diff --git a/test/UpdatePSResource.Tests.ps1 b/test/UpdatePSResource.Tests.ps1 index 129825c1f..b0c45c17d 100644 --- a/test/UpdatePSResource.Tests.ps1 +++ b/test/UpdatePSResource.Tests.ps1 @@ -351,14 +351,8 @@ Describe 'Test Update-PSResource' { # Update to module 1.4.4.1 (with incorrect catalog file) # Should FAIL to update the module It "Update module with incorrect catalog file" -Skip:(!(Get-IsWindows)) { - try - { - Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" + Install-PSResource -Name $PackageManagement -Version "1.4.2" -Repository $PSGalleryName -TrustRepository + { Update-PSResource -Name $PackageManagement -Version "1.4.4.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "TestFileCatalogError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" } # Update script that is signed @@ -375,13 +369,7 @@ Describe 'Test Update-PSResource' { # Update script that is not signed # Should throw It "Update script that is not signed" -Skip:(!(Get-IsWindows)) { - try - { - Install-PSResource -Name "TestTestScript" -Version "1.0" -Repository $PSGalleryName -TrustRepository - Update-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -ErrorAction SilentlyContinue - } - catch - {} - $Error[0].FullyQualifiedErrorId | Should -be "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" + Install-PSResource -Name "TestTestScript" -Version "1.0" -Repository $PSGalleryName -TrustRepository + { Update-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.UpdatePSResource" } } From e2ae6486a83f1ed7465e8865714d1a0de0e85f40 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Mon, 22 Aug 2022 15:56:24 -0500 Subject: [PATCH 264/276] Fix RequireModules description & add Find example (#769) --- help/Find-PSResource.md | 26 ++++++++++++++++++++++++++ help/New-PSScriptFileInfo.md | 19 +++++++++---------- help/Update-ModuleManifest.md | 13 +++++++------ help/Update-PSScriptFileInfo.md | 25 ++++++++++++++++--------- 4 files changed, 58 insertions(+), 25 deletions(-) diff --git a/help/Find-PSResource.md b/help/Find-PSResource.md index 67db70601..96d322ff9 100644 --- a/help/Find-PSResource.md +++ b/help/Find-PSResource.md @@ -172,6 +172,32 @@ Computer_RenameComputerInDomain_Config 1.0.0.0 PSGallerySc Computer_RenameComputerInWorkgroup_Config 1.0.0.0 PSGalleryScripts This example will set the machin… ``` +### Example 8 + +This example shows how to find modules by a tag. The `CrescendoBuilt` value is a tag that is +automatically added to modules created using the **Microsoft.PowerShell.Crescendo** module. + +```powershell +Find-PSResource -Tag CrescendoBuilt +``` + +```Output +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +Foil 0.1.0.0 PSGallery A PowerShell Crescendo wrapper for Chocolatey +Cobalt 0.3.1.0 PSGallery A PowerShell Crescendo wrapper for WinGet +SysInternals 1.1.0.0 PSGallery PowerShell cmdlets for SysInternal tools +Croze 0.0.4.0 PSGallery A PowerShell Crescendo wrapper for Homebrew +AptPackage 0.0.2.0 PSGallery PowerShell Crescendo-generated Module to query APT-Package Information +RoboCopy 1.0.1.0 PSGallery PowerShell cmdlet for the official RoboCopy.exe +TShark 1.0.2.0 PSGallery PowerShell cmdlet for tshark.exe +Image2Text 1.0.2.0 PSGallery PowerShell Images into ASCII art +SpeedTestCLI 1.0.0.0 PSGallery PowerShell cmdlets speedtest-cli +SpeedTest-CLI 1.0.0.0 PSGallery PowerShell cmdlets for Internet Speed Test +Quser.Crescendo 0.1.1.0 PSGallery This module displays session information of users logged onto a local or… +Takeown 1.0.2.0 PSGallery Crescendo Powershell wrapper of takeown.exe +``` + ## PARAMETERS ### -CommandName diff --git a/help/New-PSScriptFileInfo.md b/help/New-PSScriptFileInfo.md index c50a0b164..70c56e15e 100644 --- a/help/New-PSScriptFileInfo.md +++ b/help/New-PSScriptFileInfo.md @@ -89,10 +89,8 @@ This is a test script. ### Example 2: Creating a script with required modules -This example runs the cmdlet with additional parameters, including **RequiredModules**. The -**RequiredModules** parameter describes modules required by the script. The parameter takes an array -of hashtables. The **ModuleName** key in the hashtable is required. You can also include -**ModuleVersion**, **RequiredVersion**, **MaximumVersion**, or **MinimumVersion** keys. +This example runs the cmdlet with additional parameters, including **RequiredModules**. +**RequiredModules** is an array of module specifications. ```powershell $parameters = @{ @@ -389,12 +387,13 @@ Accept wildcard characters: False The parameter takes an array of module specification hashtables. A module specification is a hashtable that has the following keys. -- **ModuleName** - Required Specifies the module name. -- **GUID** - Optional Specifies the GUID of the module. -- One of these three version key is Required. These keys can't be used together. - - **ModuleVersion** - Specifies a minimum acceptable version of the module. - - **RequiredVersion** - Specifies an exact, required version of the module. - - **MaximumVersion** - Specifies the maximum acceptable version of the module. +- `ModuleName` - **Required** Specifies the module name. +- `GUID` - **Optional** Specifies the GUID of the module. +- It's also **Required** to specify at least one of the three below keys. + - `ModuleVersion` - Specifies a minimum acceptable version of the module. + - `MaximumVersion` - Specifies the maximum acceptable version of the module. + - `RequiredVersion` - Specifies an exact, required version of the module. This can't be used with + the other Version keys. ```yaml Type: System.Collections.Hashtable[] diff --git a/help/Update-ModuleManifest.md b/help/Update-ModuleManifest.md index fa92c8339..ffbf4b297 100644 --- a/help/Update-ModuleManifest.md +++ b/help/Update-ModuleManifest.md @@ -650,12 +650,13 @@ global session state, PowerShell imports them. If the required modules aren't av The value can be an array containing module names or module specifications. A module specification is a hashtable that has the following keys. -- **ModuleName** - Required Specifies the module name. -- **GUID** - Optional Specifies the GUID of the module. -- One of these three version key is Required. These keys can't be used together. - - **ModuleVersion** - Specifies a minimum acceptable version of the module. - - **RequiredVersion** - Specifies an exact, required version of the module. - - **MaximumVersion** - Specifies the maximum acceptable version of the module. +- `ModuleName` - **Required** Specifies the module name. +- `GUID` - **Optional** Specifies the GUID of the module. +- It's also **Required** to specify at least one of the three below keys. + - `ModuleVersion` - Specifies a minimum acceptable version of the module. + - `MaximumVersion` - Specifies the maximum acceptable version of the module. + - `RequiredVersion` - Specifies an exact, required version of the module. This can't be used with + the other Version keys. ```yaml Type: System.Object[] diff --git a/help/Update-PSScriptFileInfo.md b/help/Update-PSScriptFileInfo.md index 37d0d2c21..0e143779d 100644 --- a/help/Update-PSScriptFileInfo.md +++ b/help/Update-PSScriptFileInfo.md @@ -38,9 +38,15 @@ changes the **Version**' to `2.0.0.0`. The `Get-Content` cmdlet shows the update script. ```powershell -New-PSScriptFileInfo -Path "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "1.0.0.0" -Description "this is a test script" -Update-PSScriptFileInfo -Path "C:\Users\johndoe\MyScripts\test_script.ps1" -Version "2.0.0.0" -Get-Content "C:\Users\johndoe\MyScripts\test_script.ps1" +$parameters = @{ + FilePath = "C:\Users\johndoe\MyScripts\test_script.ps1" + Version = "1.0.0.0" + Description = "this is a test script" +} +New-PSScriptFileInfo @parameters +$parameters.Version = "2.0.0.0" +Update-PSScriptFileInfo @parameters +Get-Content $parameters.FilePath ``` ```Output @@ -318,12 +324,13 @@ Accept wildcard characters: False The parameter takes an array of module specification hashtables. A module specification is a hashtable that has the following keys. -- **ModuleName** - Required Specifies the module name. -- **GUID** - Optional Specifies the GUID of the module. -- One of these three version key is Required. These keys can't be used together. - - **ModuleVersion** - Specifies a minimum acceptable version of the module. - - **RequiredVersion** - Specifies an exact, required version of the module. - - **MaximumVersion** - Specifies the maximum acceptable version of the module. +- `ModuleName` - **Required** Specifies the module name. +- `GUID` - **Optional** Specifies the GUID of the module. +- It's also **Required** to specify at least one of the three below keys. + - `ModuleVersion` - Specifies a minimum acceptable version of the module. + - `MaximumVersion` - Specifies the maximum acceptable version of the module. + - `RequiredVersion` - Specifies an exact, required version of the module. This can't be used with + the other Version keys. ```yaml Type: System.Collections.Hashtable[] From 0450de8e84f1ecb4517bc68f86dab64c16d3f61b Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Fri, 26 Aug 2022 13:44:03 -0400 Subject: [PATCH 265/276] change path handle --- help/Save-PSResource.md | 5 ++--- src/code/SavePSResource.cs | 22 +++++++--------------- test/SavePSResource.Tests.ps1 | 8 +++++++- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/help/Save-PSResource.md b/help/Save-PSResource.md index e98cf87b3..162f0011c 100644 --- a/help/Save-PSResource.md +++ b/help/Save-PSResource.md @@ -192,15 +192,14 @@ Accept wildcard characters: False ### -Path -Specifies the path to save the resource to. If no path is provided, the resource is saved to the -current location. +Specifies the path to save the resource to. ```yaml Type: System.String Parameter Sets: (All) Aliases: -Required: False +Required: True Position: Named Default value: None Accept pipeline input: False diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 9c92a261f..0c33b3a94 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -81,7 +81,7 @@ public sealed class SavePSResource : PSCmdlet /// /// The destination where the resource is to be installed. Works for all resource types. /// - [Parameter] + [Parameter(Mandatory = true)] [ValidateNotNullOrEmpty] public string Path { @@ -90,21 +90,13 @@ public string Path set { - string resolvedPath = string.Empty; - if (string.IsNullOrEmpty(value)) - { - // If the user does not specify a path to save to, use the user's current working directory - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(SessionState.Path.CurrentFileSystemLocation.Path).First().Path; - } - else { - resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; - } + if (WildcardPattern.ContainsWildcardCharacters(value)) + { + throw new PSArgumentException("Wildcard characters are not allowed in the path."); + } - // Path where resource is saved must be a directory - if (Directory.Exists(resolvedPath)) - { - _path = resolvedPath; - } + // This will throw if path cannot be resolved + _path = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path; } } private string _path; diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index 3366cdec5..acd1162f1 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -280,7 +280,13 @@ Describe 'Test Save-PSResource for PSResources' { # Save script that is not signed # Should throw It "Save script that is not signed" -Skip:(!(Get-IsWindows)) { - { Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository } | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + { Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir} | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" + } + + # Save module without specifying -Path + # Should FAIL to save the module + It "Save module without specifying -Path" { + {Save-PSResource -Name $testModuleName -Repository $PSGalleryName } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } <# From d53a330fa8cffb315cab2a2b7c4bb17245f807be Mon Sep 17 00:00:00 2001 From: Alyssa Vu Date: Tue, 30 Aug 2022 15:06:36 -0400 Subject: [PATCH 266/276] delete test --- test/SavePSResource.Tests.ps1 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/SavePSResource.Tests.ps1 b/test/SavePSResource.Tests.ps1 index acd1162f1..d4300b66e 100644 --- a/test/SavePSResource.Tests.ps1 +++ b/test/SavePSResource.Tests.ps1 @@ -283,12 +283,6 @@ Describe 'Test Save-PSResource for PSResources' { { Save-PSResource -Name "TestTestScript" -Version "1.3.1.1" -AuthenticodeCheck -Repository $PSGalleryName -TrustRepository -Path $SaveDir} | Should -Throw -ErrorId "GetAuthenticodeSignatureError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" } - # Save module without specifying -Path - # Should FAIL to save the module - It "Save module without specifying -Path" { - {Save-PSResource -Name $testModuleName -Repository $PSGalleryName } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.PowerShellGet.Cmdlets.SavePSResource" - } - <# # Tests should not write to module directory It "Save specific module resource by name if no -Path param is specifed" { From f2f490a55a8642a207320116d9b117c5a0bc21a0 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 31 Aug 2022 13:37:08 -0400 Subject: [PATCH 267/276] Script file validation and metadata properties population for Publishing, Installing a script. (#781) * for Publish script validation use validation code from PSScriptFileInfo methods * for Install, script validation should use PSScriptFileInfo methods and also populate PSResourceInfo with metadata information accessible --- src/code/InstallHelper.cs | 30 +++++ src/code/PSResourceInfo.cs | 8 +- src/code/PSScriptFileInfo.cs | 26 ++++ src/code/PSScriptMetadata.cs | 23 ++++ src/code/PublishPSResource.cs | 197 ++----------------------------- test/InstallPSResource.Tests.ps1 | 24 ++++ test/PublishPSResource.Tests.ps1 | 32 ++++- 7 files changed, 145 insertions(+), 195 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 344b69631..09f28ff74 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -545,6 +545,10 @@ private List InstallPackage( } moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; + pkg.CompanyName = parsedMetadataHashtable.ContainsKey("CompanyName") ? parsedMetadataHashtable["CompanyName"] as string : String.Empty; + pkg.Copyright = parsedMetadataHashtable.ContainsKey("Copyright") ? parsedMetadataHashtable["Copyright"] as string : String.Empty; + pkg.ReleaseNotes = parsedMetadataHashtable.ContainsKey("ReleaseNotes") ? parsedMetadataHashtable["ReleaseNotes"] as string : String.Empty; + pkg.RepositorySourceLocation = repoUri; // Accept License verification if (!_savePkg && !CallAcceptLicense(pkg, moduleManifest, tempInstallPath, newVersion)) @@ -558,6 +562,32 @@ private List InstallPackage( continue; } } + else + { + // is script + if (!PSScriptFileInfo.TryTestPSScriptFile( + scriptFileInfoPath: scriptPath, + parsedScript: out PSScriptFileInfo scriptToInstall, + out ErrorRecord[] errors, + out string[] _ + )) + { + foreach (ErrorRecord error in errors) + { + _cmdletPassedIn.WriteError(error); + } + + continue; + } + + Hashtable parsedMetadataHashtable = scriptToInstall.ToHashtable(); + + moduleManifestVersion = parsedMetadataHashtable["ModuleVersion"] as string; + pkg.CompanyName = parsedMetadataHashtable.ContainsKey("CompanyName") ? parsedMetadataHashtable["CompanyName"] as string : String.Empty; + pkg.Copyright = parsedMetadataHashtable.ContainsKey("Copyright") ? parsedMetadataHashtable["Copyright"] as string : String.Empty; + pkg.ReleaseNotes = parsedMetadataHashtable.ContainsKey("ReleaseNotes") ? parsedMetadataHashtable["ReleaseNotes"] as string : String.Empty; + pkg.RepositorySourceLocation = repoUri; + } // Delete the extra nupkg related files that are not needed and not part of the module/script DeleteExtraneousFiles(pkgIdentity, tempDirNameVersion); diff --git a/src/code/PSResourceInfo.cs b/src/code/PSResourceInfo.cs index 6d1523cc4..ca6057002 100644 --- a/src/code/PSResourceInfo.cs +++ b/src/code/PSResourceInfo.cs @@ -234,8 +234,8 @@ public sealed class PSResourceInfo public Dictionary AdditionalMetadata { get; } public string Author { get; } - public string CompanyName { get; } - public string Copyright { get; } + public string CompanyName { get; internal set; } + public string Copyright { get; internal set; } public Dependency[] Dependencies { get; } public string Description { get; } public Uri IconUri { get; } @@ -250,9 +250,9 @@ public sealed class PSResourceInfo public string Prerelease { get; } public Uri ProjectUri { get; } public DateTime? PublishedDate { get; } - public string ReleaseNotes { get; } + public string ReleaseNotes { get; internal set; } public string Repository { get; } - public string RepositorySourceLocation { get; } + public string RepositorySourceLocation { get; internal set; } public string[] Tags { get; } public ResourceType Type { get; } public DateTime? UpdatedDate { get; } diff --git a/src/code/PSScriptFileInfo.cs b/src/code/PSScriptFileInfo.cs index dfeee2121..9e568554e 100644 --- a/src/code/PSScriptFileInfo.cs +++ b/src/code/PSScriptFileInfo.cs @@ -1,3 +1,4 @@ +using System.Collections; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. @@ -489,6 +490,31 @@ out ErrorRecord[] errors return fileContentsSuccessfullyCreated; } + + internal Hashtable ToHashtable() + { + Hashtable scriptHashtable = new Hashtable(StringComparer.OrdinalIgnoreCase); + + Hashtable metadataObjectHashtable = ScriptMetadataComment.ToHashtable(); + foreach(string key in metadataObjectHashtable.Keys) + { + if (!scriptHashtable.ContainsKey(key)) + { + // shouldn't have duplicate keys, but just for unexpected error handling + scriptHashtable.Add(key, metadataObjectHashtable[key]); + } + } + + scriptHashtable.Add(nameof(ScriptHelpComment.Description), ScriptHelpComment.Description); + + if (ScriptRequiresComment.RequiredModules.Length != 0) + { + scriptHashtable.Add(nameof(ScriptRequiresComment.RequiredModules), ScriptRequiresComment.RequiredModules); + } + + return scriptHashtable; + } + #endregion } } diff --git a/src/code/PSScriptMetadata.cs b/src/code/PSScriptMetadata.cs index 8ce8d0360..909d76210 100644 --- a/src/code/PSScriptMetadata.cs +++ b/src/code/PSScriptMetadata.cs @@ -544,6 +544,29 @@ internal bool UpdateContent( return true; } + + internal Hashtable ToHashtable() + { + // Constructor would be called first, which handles empty null values for required properties. + Hashtable metadataHashtable = new Hashtable(StringComparer.OrdinalIgnoreCase); + metadataHashtable.Add(nameof(Version), Version); + metadataHashtable.Add(nameof(Guid), Guid); + metadataHashtable.Add(nameof(Author), Author); + metadataHashtable.Add(nameof(CompanyName), CompanyName); + metadataHashtable.Add(nameof(Copyright), Copyright); + metadataHashtable.Add(nameof(Tags), Tags); + metadataHashtable.Add(nameof(LicenseUri), LicenseUri); + metadataHashtable.Add(nameof(ProjectUri), ProjectUri); + metadataHashtable.Add(nameof(IconUri), IconUri); + metadataHashtable.Add(nameof(ExternalModuleDependencies), ExternalModuleDependencies); + metadataHashtable.Add(nameof(RequiredScripts), RequiredScripts); + metadataHashtable.Add(nameof(ExternalScriptDependencies), ExternalScriptDependencies); + metadataHashtable.Add(nameof(ReleaseNotes), ReleaseNotes); + metadataHashtable.Add(nameof(PrivateData), PrivateData); + + return metadataHashtable; + } + #endregion } } diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 31c3d85f9..545c354ff 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -219,29 +219,31 @@ protected override void EndProcessing() return; } - Hashtable parsedMetadata; + Hashtable parsedMetadata = new Hashtable(StringComparer.OrdinalIgnoreCase); if (resourceType == ResourceType.Script) { - // Check that script metadata is valid - if (!TryParseScriptMetadata( - out parsedMetadata, - pathToScriptFileToPublish, - out ErrorRecord[] errors)) + if (!PSScriptFileInfo.TryTestPSScriptFile( + scriptFileInfoPath: pathToScriptFileToPublish, + parsedScript: out PSScriptFileInfo scriptToPublish, + out ErrorRecord[] errors, + out string[] _ + )) { - foreach (ErrorRecord err in errors) + foreach (ErrorRecord error in errors) { - WriteError(err); + WriteError(error); } return; } + parsedMetadata = scriptToPublish.ToHashtable(); + _pkgName = System.IO.Path.GetFileNameWithoutExtension(pathToScriptFileToPublish); } else { // parsedMetadata needs to be initialized for modules, will later be passed in to create nuspec - parsedMetadata = new Hashtable(); if (!string.IsNullOrEmpty(pathToModuleManifestToPublish)) { _pkgName = System.IO.Path.GetFileNameWithoutExtension(pathToModuleManifestToPublish); @@ -746,183 +748,6 @@ private Hashtable ParseRequiredModules(Hashtable parsedMetadataHash) return dependenciesHash; } - private bool TryParseScriptMetadata( - out Hashtable parsedMetadata, - string filePath, - out ErrorRecord[] errors) - { - parsedMetadata = new Hashtable(); - List parseMetadataErrors = new List(); - - // a valid example script will have this format: - /* <#PSScriptInfo - .VERSION 1.6 - .GUID abf490023 - 9128 - 4323 - sdf9a - jf209888ajkl - .AUTHOR Jane Doe - .COMPANYNAME Microsoft - .COPYRIGHT - .TAGS Windows MacOS - #> - - <# - - .SYNOPSIS - Synopsis description here - .DESCRIPTION - Description here - .PARAMETER Name - .EXAMPLE - Example cmdlet here - - #> - */ - - // Parse the script file - var ast = Parser.ParseFile( - filePath, - out System.Management.Automation.Language.Token[] tokens, - out ParseError[] parserErrors); - - if (parserErrors.Length > 0) - { - foreach (ParseError err in parserErrors) - { - // we ignore WorkFlowNotSupportedInPowerShellCore errors, as this is common in scripts currently on PSGallery - if (!String.Equals(err.ErrorId, "WorkflowNotSupportedInPowerShellCore", StringComparison.OrdinalIgnoreCase)) - { - var message = String.Format("Could not parse '{0}' as a PowerShell script file due to {1}.", filePath, err.Message); - var ex = new ArgumentException(message); - var psScriptFileParseError = new ErrorRecord(ex, err.ErrorId, ErrorCategory.ParserError, null); - parseMetadataErrors.Add(psScriptFileParseError); - } - } - - errors = parseMetadataErrors.ToArray(); - return false; - } - - if (ast == null) - { - var astNullMessage = String.Format(".ps1 file was parsed but AST was null"); - var astNullEx = new ArgumentException(astNullMessage); - var astCouldNotBeCreatedError = new ErrorRecord(astNullEx, "ASTCouldNotBeCreated", ErrorCategory.ParserError, null); - - parseMetadataErrors.Add(astCouldNotBeCreatedError); - errors = parseMetadataErrors.ToArray(); - return false; - - } - - // Get the block/group comment beginning with <#PSScriptInfo - List commentTokens = tokens.Where(a => String.Equals(a.Kind.ToString(), "Comment", StringComparison.OrdinalIgnoreCase)).ToList(); - string commentPattern = PSScriptInfoCommentString; - Regex rg = new Regex(commentPattern); - List psScriptInfoCommentTokens = commentTokens.Where(a => rg.IsMatch(a.Extent.Text)).ToList(); - - if (psScriptInfoCommentTokens.Count() == 0 || psScriptInfoCommentTokens[0] == null) - { - var message = String.Format("PSScriptInfo comment was missing or could not be parsed"); - var ex = new ArgumentException(message); - var psCommentMissingError = new ErrorRecord(ex, "psScriptInfoCommentMissingError", ErrorCategory.ParserError, null); - parseMetadataErrors.Add(psCommentMissingError); - errors = parseMetadataErrors.ToArray(); - return false; - } - - string[] commentLines = Regex.Split(psScriptInfoCommentTokens[0].Text, "[\r\n]").Where(x => !String.IsNullOrEmpty(x)).ToArray(); - string keyName = String.Empty; - string value = String.Empty; - - /** - If comment line count is not more than two, it doesn't have the any metadata property - comment block would look like: - <#PSScriptInfo - #> - */ - - if (commentLines.Count() > 2) - { - for (int i = 1; i < commentLines.Count(); i++) - { - string line = commentLines[i]; - if (String.IsNullOrEmpty(line)) - { - continue; - } - - // A line is starting with . conveys a new metadata property - if (line.Trim().StartsWith(".")) - { - string[] parts = line.Trim().TrimStart('.').Split(); - keyName = parts[0].ToLower(); - value = parts.Count() > 1 ? String.Join(" ", parts.Skip(1)) : String.Empty; - parsedMetadata.Add(keyName, value); - } - } - } - - // get .DESCRIPTION comment - CommentHelpInfo scriptCommentInfo = ast.GetHelpContent(); - if (scriptCommentInfo == null) - { - var message = String.Format("PSScript file is missing the required Description comment block in the script contents."); - var ex = new ArgumentException(message); - var psScriptMissingHelpContentCommentBlockError = new ErrorRecord(ex, "PSScriptMissingHelpContentCommentBlock", ErrorCategory.ParserError, null); - parseMetadataErrors.Add(psScriptMissingHelpContentCommentBlockError); - errors = parseMetadataErrors.ToArray(); - return false; - } - - if (!String.IsNullOrEmpty(scriptCommentInfo.Description) && !scriptCommentInfo.Description.Contains("<#") && !scriptCommentInfo.Description.Contains("#>")) - { - parsedMetadata.Add("description", scriptCommentInfo.Description); - } - else - { - var message = String.Format("PSScript is missing the required Description property or Description value contains '<#' or '#>' which is invalid"); - var ex = new ArgumentException(message); - var psScriptMissingDescriptionOrInvalidPropertyError = new ErrorRecord(ex, "MissingOrInvalidDescriptionInScriptMetadata", ErrorCategory.ParserError, null); - parseMetadataErrors.Add(psScriptMissingDescriptionOrInvalidPropertyError); - errors = parseMetadataErrors.ToArray(); - return false; - } - - - // Check that the mandatory properites for a script are there (version, author, guid, in addition to description) - if (!parsedMetadata.ContainsKey("version") || String.IsNullOrWhiteSpace(parsedMetadata["version"].ToString())) - { - var message = "No version was provided in the script metadata. Script metadata must specify a version, author, description, and Guid."; - var ex = new ArgumentException(message); - var MissingVersionInScriptMetadataError = new ErrorRecord(ex, "MissingVersionInScriptMetadata", ErrorCategory.InvalidData, null); - parseMetadataErrors.Add(MissingVersionInScriptMetadataError); - errors = parseMetadataErrors.ToArray(); - return false; - } - - if (!parsedMetadata.ContainsKey("author") || String.IsNullOrWhiteSpace(parsedMetadata["author"].ToString())) - { - var message = "No author was provided in the script metadata. Script metadata must specify a version, author, description, and Guid."; - var ex = new ArgumentException(message); - var MissingAuthorInScriptMetadataError = new ErrorRecord(ex, "MissingAuthorInScriptMetadata", ErrorCategory.InvalidData, null); - parseMetadataErrors.Add(MissingAuthorInScriptMetadataError); - errors = parseMetadataErrors.ToArray(); - return false; - } - - if (!parsedMetadata.ContainsKey("guid") || String.IsNullOrWhiteSpace(parsedMetadata["guid"].ToString())) - { - var message = "No guid was provided in the script metadata. Script metadata must specify a version, author, description, and Guid."; - var ex = new ArgumentException(message); - var MissingGuidInScriptMetadataError = new ErrorRecord(ex, "MissingGuidInScriptMetadata", ErrorCategory.InvalidData, null); - parseMetadataErrors.Add(MissingGuidInScriptMetadataError); - errors = parseMetadataErrors.ToArray(); - return false; - } - - errors = parseMetadataErrors.ToArray(); - return true; - } - private bool CheckDependenciesExist(Hashtable dependencies, string repositoryName) { // Check to see that all dependencies are in the repository diff --git a/test/InstallPSResource.Tests.ps1 b/test/InstallPSResource.Tests.ps1 index b9ab10495..21c15d783 100644 --- a/test/InstallPSResource.Tests.ps1 +++ b/test/InstallPSResource.Tests.ps1 @@ -8,6 +8,7 @@ Describe 'Test Install-PSResource for Module' { BeforeAll { $PSGalleryName = Get-PSGalleryName + $PSGalleryUri = Get-PSGalleryLocation $NuGetGalleryName = Get-NuGetGalleryName $testModuleName = "test_module" $testModuleName2 = "TestModule99" @@ -180,6 +181,29 @@ Describe 'Test Install-PSResource for Module' { ($env:PSModulePath).Contains($pkg.InstalledLocation) } + It "Install resource with companyname, copyright and repository source location and validate" { + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository PSGallery -TrustRepository + $pkg = Get-PSResource $testModuleName + $pkg.Version | Should -Be "5.2.5" + $pkg.Prerelease | Should -Be "alpha001" + + $pkg.CompanyName | Should -Be "Anam" + $pkg.Copyright | Should -Be "(c) Anam Navied. All rights reserved." + $pkg.RepositorySourceLocation | Should -Be $PSGalleryUri + } + + + It "Install script with companyname, copyright, and repository source location and validate" { + Install-PSResource -Name "Install-VSCode" -Version "1.4.2" -Repository $PSGalleryName -TrustRepository + + $res = Get-PSResource "Install-VSCode" -Version "1.4.2" + $res.Name | Should -Be "Install-VSCode" + $res.Version | Should -Be "1.4.2.0" + $res.CompanyName | Should -Be "Microsoft Corporation" + $res.Copyright | Should -Be "(c) Microsoft Corporation" + $res.RepositorySourceLocation | Should -Be $PSGalleryUri + } + # Windows only It "Install resource under CurrentUser scope - Windows only" -Skip:(!(Get-IsWindows)) { Install-PSResource -Name $testModuleName -Repository $PSGalleryName -TrustRepository -Scope CurrentUser diff --git a/test/PublishPSResource.Tests.ps1 b/test/PublishPSResource.Tests.ps1 index f1b1baf22..f143c9391 100644 --- a/test/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResource.Tests.ps1 @@ -378,6 +378,28 @@ Describe "Test Publish-PSResource" { (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath } + It "should publish a script without lines in between comment blocks locally" { + $scriptName = "ScriptWithoutEmptyLinesBetweenCommentBlocks" + $scriptVersion = "1.0.0" + $scriptPath = (Join-Path -Path $script:testScriptsFolderPath -ChildPath "$scriptName.ps1") + + Publish-PSResource -Path $scriptPath + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + } + + It "should publish a script without lines in help block locally" { + $scriptName = "ScriptWithoutEmptyLinesInMetadata" + $scriptVersion = "1.0.0" + $scriptPath = (Join-Path -Path $script:testScriptsFolderPath -ChildPath "$scriptName.ps1") + + Publish-PSResource -Path $scriptPath + + $expectedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" + (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath + } + It "should write error and not publish script when Author property is missing" { $scriptName = "InvalidScriptMissingAuthor.ps1" $scriptVersion = "1.0.0" @@ -385,7 +407,7 @@ Describe "Test Publish-PSResource" { $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingAuthorInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + $err[0].FullyQualifiedErrorId | Should -BeExactly "psScriptMissingAuthor,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" Test-Path -Path $publishedPath | Should -Be $false @@ -397,7 +419,7 @@ Describe "Test Publish-PSResource" { $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingVersionInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + $err[0].FullyQualifiedErrorId | Should -BeExactly "psScriptMissingVersion,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" $publishedPkgs = Get-ChildItem -Path $script:repositoryPath -Filter *.nupkg $publishedPkgs.Count | Should -Be 0 @@ -410,7 +432,7 @@ Describe "Test Publish-PSResource" { $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingGuidInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + $err[0].FullyQualifiedErrorId | Should -BeExactly "psScriptMissingGuid,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" Test-Path -Path $publishedPath | Should -Be $false @@ -423,7 +445,7 @@ Describe "Test Publish-PSResource" { $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "MissingOrInvalidDescriptionInScriptMetadata,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + $err[0].FullyQualifiedErrorId | Should -BeExactly "PSScriptInfoMissingDescription,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" Test-Path -Path $publishedPath | Should -Be $false @@ -437,7 +459,7 @@ Describe "Test Publish-PSResource" { $scriptFilePath = Join-Path $script:testScriptsFolderPath -ChildPath $scriptName Publish-PSResource -Path $scriptFilePath -ErrorVariable err -ErrorAction SilentlyContinue $err.Count | Should -Not -Be 0 - $err[0].FullyQualifiedErrorId | Should -BeExactly "PSScriptMissingHelpContentCommentBlock,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" + $err[0].FullyQualifiedErrorId | Should -BeExactly "missingHelpInfoCommentError,Microsoft.PowerShell.PowerShellGet.Cmdlets.PublishPSResource" $publishedPath = Join-Path -Path $script:repositoryPath -ChildPath "$scriptName.$scriptVersion.nupkg" Test-Path -Path $publishedPath | Should -Be $false From a64d2f90b239820206e4c91822774d1daecc6b16 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 31 Aug 2022 13:38:09 -0400 Subject: [PATCH 268/276] Install-PSResource: Installation path for scripts not included in environment PATH variable (#750) * when installing script ensure that Script InstallPath is added to env Path variable so script can be invoked without prepending install folder path * add prompting for setting env var, add scope based env var setting, and pass scope to InstallHelper * InstallHelper should take ScopeType? param, use Path.PathSeperator for cross platform compat, and add tests * instead of prompt, use ShouldProcess for modiying user's environment variable * Update src/code/InstallHelper.cs Co-authored-by: Paul Higinbotham * Update src/code/InstallHelper.cs Co-authored-by: Paul Higinbotham * detect if Script install path is not in environment PATH for appropriate scope and present warning and revert install tests * simplify scope based determination of environment PATH variable Co-authored-by: Paul Higinbotham --- src/code/InstallHelper.cs | 26 ++++++++++++++++++++++---- src/code/InstallPSResource.cs | 1 + src/code/SavePSResource.cs | 1 + src/code/UpdatePSResource.cs | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index 09f28ff74..43bb57a87 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -35,6 +35,7 @@ internal class InstallHelper public const string PSScriptFileExt = ".ps1"; private const string MsgRepositoryNotTrusted = "Untrusted repository"; private const string MsgInstallUntrustedPackage = "You are installing the modules from an untrusted repository. If you trust this repository, change its Trusted value by running the Set-PSResourceRepository cmdlet. Are you sure you want to install the PSresource from '{0}' ?"; + private const string ScriptPATHWarning = "The installation path for the script does not currently appear in the {0} path environment variable. To make the script discoverable, add the script installation path, {1}, to the environment PATH variable."; private CancellationToken _cancellationToken; private readonly PSCmdlet _cmdletPassedIn; private List _pathsToInstallPkg; @@ -84,6 +85,7 @@ public List InstallPackages( bool authenticodeCheck, bool savePkg, List pathsToInstallPkg, + ScopeType? scope, string tmpPath) { _cmdletPassedIn.WriteVerbose(string.Format("Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " + @@ -140,7 +142,8 @@ public List InstallPackages( repository: repository, trustRepository: _trustRepository, credential: _credential, - skipDependencyCheck: skipDependencyCheck); + skipDependencyCheck: skipDependencyCheck, + scope: scope?? ScopeType.CurrentUser); } #endregion @@ -152,7 +155,8 @@ private List ProcessRepositories( string[] repository, bool trustRepository, PSCredential credential, - bool skipDependencyCheck) + bool skipDependencyCheck, + ScopeType scope) { var listOfRepositories = RepositorySettings.Read(repository, out string[] _); var yesToAll = false; @@ -238,7 +242,8 @@ private List ProcessRepositories( repo.Uri.AbsoluteUri, repo.CredentialInfo, credential, - isLocalRepo); + isLocalRepo, + scope: scope); foreach (PSResourceInfo pkg in pkgsInstalled) { @@ -322,7 +327,8 @@ private List InstallPackage( string repoUri, PSCredentialInfo repoCredentialInfo, PSCredential credential, - bool isLocalRepo) + bool isLocalRepo, + ScopeType scope) { List pkgsSuccessfullyInstalled = new List(); int totalPkgs = pkgsToInstall.Count; @@ -610,6 +616,18 @@ out string[] _ _cmdletPassedIn.WriteVerbose(String.Format("Successfully installed package '{0}' to location '{1}'", pkg.Name, installPath)); pkgsSuccessfullyInstalled.Add(pkg); + + if (!_savePkg && !isModule) + { + string installPathwithBackSlash = installPath + "\\"; + string envPATHVarValue = Environment.GetEnvironmentVariable("PATH", + scope == ScopeType.CurrentUser ? EnvironmentVariableTarget.User : EnvironmentVariableTarget.Machine); + + if (!envPATHVarValue.Contains(installPath) && !envPATHVarValue.Contains(installPathwithBackSlash)) + { + _cmdletPassedIn.WriteWarning(String.Format(ScriptPATHWarning, scope, installPath)); + } + } } catch (Exception e) { diff --git a/src/code/InstallPSResource.cs b/src/code/InstallPSResource.cs index b27b48093..84e563235 100644 --- a/src/code/InstallPSResource.cs +++ b/src/code/InstallPSResource.cs @@ -552,6 +552,7 @@ private void ProcessInstallHelper(string[] pkgNames, VersionRange pkgVersion, bo authenticodeCheck: AuthenticodeCheck, savePkg: false, pathsToInstallPkg: _pathsToInstallPkg, + scope: Scope, tmpPath: _tmpPath); if (PassThru) diff --git a/src/code/SavePSResource.cs b/src/code/SavePSResource.cs index 9c92a261f..4b3c9cc82 100644 --- a/src/code/SavePSResource.cs +++ b/src/code/SavePSResource.cs @@ -291,6 +291,7 @@ private void ProcessSaveHelper(string[] pkgNames, bool pkgPrerelease, string[] p authenticodeCheck: AuthenticodeCheck, savePkg: true, pathsToInstallPkg: new List { _path }, + scope: null, tmpPath: _tmpPath); if (PassThru) diff --git a/src/code/UpdatePSResource.cs b/src/code/UpdatePSResource.cs index c670c0afe..fcb0dfe3e 100644 --- a/src/code/UpdatePSResource.cs +++ b/src/code/UpdatePSResource.cs @@ -213,6 +213,7 @@ protected override void ProcessRecord() authenticodeCheck: AuthenticodeCheck, savePkg: false, pathsToInstallPkg: _pathsToInstallPkg, + scope: Scope, tmpPath: _tmpPath); if (PassThru) From 3bd5ccdd8bc9653639788ca1a21b2f7c42832d7e Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Wed, 31 Aug 2022 12:43:21 -0700 Subject: [PATCH 269/276] Update CHANGELOG.md for beta17 (#782) * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Anam Navied --- CHANGELOG.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4333725..3ed819c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # CHANGELOG +## 3.0.17-beta17 + +### New Features +- Add -TemporaryPath parameter to Install-PSResource, Save-PSResource, and Update-PSResource (#763) +- Add String and SecureString as credential types in PSCredentialInfo (#764) +- Add a warning for when the script installation path is not in Path variable (#750) +- Expand acceptable paths for Publish-PSResource (Module root directory, module manifest file, script file)(#704) +- Add -Force parameter to Register-PSResourceRepository cmdlet, to override an existing repository (#717) + +### Bug Fixes +- Change casing of -IncludeXML to -IncludeXml (#739) +- Update priority range for PSResourceRepository to 0-100 (#741) +- Editorial pass on cmdlet reference (#743) +- Fix issue when PSScriptInfo has no empty lines (#744) +- Make ConfirmImpact low for Register-PSResourceRepository and Save-PSResource (#745) +- Fix -PassThru for Set-PSResourceRepository cmdlet to return all properties (#748) +- Rename -FilePath parameter to -Path for PSScriptFileInfo cmdlets (#765) +- Fix RequiredModules description and add Find example to docs (#769) +- Remove unneeded inheritance in InstallHelper.cs (#773) +- Make -Path a required parameter for Save-PSResource cmdlet (#780) +- Improve script validation for publishing and installing (#781) + ## 3.0.16-beta16 ### Bug Fixes @@ -192,4 +214,4 @@ New Features ## 3.0.0-beta1 BREAKING CHANGE -* Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. \ No newline at end of file +* Preview version of PowerShellGet. Many features are not fully implemented yet. Please see https://devblogs.microsoft.com/powershell/powershellget-3-0-preview1 for more details. From 1029f220565ba2a09b58037a6257cb92b3baac31 Mon Sep 17 00:00:00 2001 From: Alyssa Vu <49544763+alyssa1303@users.noreply.github.com> Date: Wed, 31 Aug 2022 15:56:35 -0400 Subject: [PATCH 270/276] Release 3.0.17 (#783) Co-authored-by: Alyssa Vu --- .ci/ci_release.yml | 2 +- src/PowerShellGet.psd1 | 26 ++++++++++++++++++++++++-- src/code/PowerShellGet.csproj | 6 +++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 706572091..924de1a50 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -248,7 +248,7 @@ stages: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' PackageName: 'PowerShellGet' - PackageVersion: '3.0.16' + PackageVersion: '3.0.17' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 6c9289575..7a6f52089 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.16' + ModuleVersion = '3.0.17' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -34,7 +34,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta16' + Prerelease = 'beta17' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', @@ -44,6 +44,28 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 3.0.17-beta17 + +### New Features +- Add -TemporaryPath parameter to Install-PSResource, Save-PSResource, and Update-PSResource (#763) +- Add String and SecureString as credential types in PSCredentialInfo (#764) +- Add a warning for when the script installation path is not in Path variable (#750) +- Expand acceptable paths for Publish-PSResource (Module root directory, module manifest file, script file)(#704) +- Add -Force parameter to Register-PSResourceRepository cmdlet, to override an existing repository (#717) + +### Bug Fixes +- Change casing of -IncludeXML to -IncludeXml (#739) +- Update priority range for PSResourceRepository to 0-100 (#741) +- Editorial pass on cmdlet reference (#743) +- Fix issue when PSScriptInfo has no empty lines (#744) +- Make ConfirmImpact low for Register-PSResourceRepository and Save-PSResource (#745) +- Fix -PassThru for Set-PSResourceRepository cmdlet to return all properties (#748) +- Rename -FilePath parameter to -Path for PSScriptFileInfo cmdlets (#765) +- Fix RequiredModules description and add Find example to docs (#769) +- Remove unneeded inheritance in InstallHelper.cs (#773) +- Make -Path a required parameter for Save-PSResource cmdlet (#780) +- Improve script validation for publishing and installing (#781) + ## 3.0.16-beta16 ### Bug Fixes diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 5f6856f3b..5d6b67868 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.16.0 - 3.0.16 - 3.0.16 + 3.0.17.0 + 3.0.17 + 3.0.17 netstandard2.0 8.0 From c19a0d0ff28440d57d4cbe0836c3e7faedc23e11 Mon Sep 17 00:00:00 2001 From: Sydney Smith <43417619+SydneyhSmith@users.noreply.github.com> Date: Thu, 1 Sep 2022 08:24:39 -0700 Subject: [PATCH 271/276] Update PowerShellGet.dll-Help.xml (#784) --- help/en-US/PowerShellGet.dll-Help.xml | 3978 ++++++++++++++++--------- 1 file changed, 2515 insertions(+), 1463 deletions(-) diff --git a/help/en-US/PowerShellGet.dll-Help.xml b/help/en-US/PowerShellGet.dll-Help.xml index 0afb8205c..56257ebcd 100644 --- a/help/en-US/PowerShellGet.dll-Help.xml +++ b/help/en-US/PowerShellGet.dll-Help.xml @@ -6,19 +6,19 @@ Find PSResource - Searches for packages from a repository (local or remote), based on `-Name` and other package properties. + Searches for packages from a repository (local or remote), based on a name or other package properties. - The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on `-Name` or other package properties. + The `Find-PSResource` cmdlet searches for a package from a repository (local or remote) based on a name or other package properties. Find-PSResource - - Name + + CommandName - Name of a resource or resources to find. Accepts wild card character '*'. + The name of the command to search for. System.String[] @@ -42,7 +42,7 @@ IncludeDependencies - When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + When specified, search returns all matching resources their dependencies. Dependencies are deduplicated. System.Management.Automation.SwitchParameter @@ -53,11 +53,12 @@ ModuleName - Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + Specifies a module resource package name type to search for. Wildcards are supported. + Not yet implemented. - System.String + System.String[] - System.String + System.String[] None @@ -76,7 +77,9 @@ Repository - 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. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. System.String[] @@ -97,20 +100,104 @@ None + + Version + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + Wildcards are supported but NuGet only accepts wildcard character `*`. For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + + Find-PSResource - Type + Credential - Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + Optional credentials to be used when accessing a repository. - - Module - Script - DscResource - Command - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + DscResourceName + + The name of the DSC Resource to search for. + + System.String[] - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + System.String[] + + + None + + + IncludeDependencies + + When specified, search returns all matching resources their dependencies. Dependencies are deduplicated. + + + System.Management.Automation.SwitchParameter + + + False + + + ModuleName + + Specifies a module resource package name type to search for. Wildcards are supported. + Not yet implemented. + + System.String[] + + System.String[] + + + None + + + Prerelease + + When specified, includes prerelease versions in search results returned. + + + System.Management.Automation.SwitchParameter + + + False + + + Repository + + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. + + System.String[] + + System.String[] + + + None + + + Tag + + Filters search results for resources that include one or more of the specified tags. + + System.String[] + + System.String[] None @@ -119,7 +206,8 @@ Version Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Wildcards are supported but NuGet only accepts wildcard character `*`. For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. System.String @@ -128,10 +216,37 @@ None - - Confirm + + + Find-PSResource + + Name - Prompts you for confirmation before running the cmdlet. + Name of a resource to find. Wildcards are supported but NuGet only accepts the `*` character. NuGet does not support wildcard searches of local (file-based) repositories. + + System.String[] + + System.String[] + + + None + + + Credential + + Optional credentials to be used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + IncludeDependencies + + When specified, search returns all matching resources their dependencies. Dependencies are deduplicated. System.Management.Automation.SwitchParameter @@ -139,10 +254,10 @@ False - - WhatIf + + Prerelease - Shows what would happen if the cmdlet runs. The cmdlet is not run. + When specified, includes prerelease versions in search results returned. System.Management.Automation.SwitchParameter @@ -150,9 +265,83 @@ False + + Repository + + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. + + System.String[] + + System.String[] + + + None + + + Tag + + Filters search results for resources that include one or more of the specified tags. + + System.String[] + + System.String[] + + + None + + + Type + + Specifies one or more resource types to find. Resource types supported are: + - `Module` + - `Script` + - `Command` + - `DscResource` + + + Module + Script + DscResource + Command + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType + + + None + + + Version + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + Wildcards are supported but NuGet only accepts wildcard character `*`. For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + CommandName + + The name of the command to search for. + + System.String[] + + System.String[] + + + None + Credential @@ -165,10 +354,22 @@ None + + DscResourceName + + The name of the DSC Resource to search for. + + System.String[] + + System.String[] + + + None + IncludeDependencies - When specified, search will return all matched resources along with any resources the matched resources depends on. Dependencies are deduplicated. + When specified, search returns all matching resources their dependencies. Dependencies are deduplicated. System.Management.Automation.SwitchParameter @@ -180,19 +381,20 @@ ModuleName - Specifies a module resource package name type to search for. Wildcards are supported. Not yet implemented. + Specifies a module resource package name type to search for. Wildcards are supported. + Not yet implemented. - System.String + System.String[] - System.String + System.String[] None - + Name - Name of a resource or resources to find. Accepts wild card character '*'. + Name of a resource to find. Wildcards are supported but NuGet only accepts the `*` character. NuGet does not support wildcard searches of local (file-based) repositories. System.String[] @@ -216,7 +418,9 @@ Repository - 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. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. System.String[] @@ -240,11 +444,15 @@ Type - Specifies one or more resource types to find. Resource types supported are: Module, Script, Command, DscResource. + Specifies one or more resource types to find. Resource types supported are: + - `Module` + - `Script` + - `Command` + - `DscResource` - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType - Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ResourceType None @@ -253,7 +461,8 @@ Version Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Wildcards are supported but NuGet only accepts wildcard character `*`. For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. System.String @@ -262,30 +471,6 @@ None - - Confirm - - Prompts you for confirmation before running the cmdlet. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - - - WhatIf - - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - System.Management.Automation.SwitchParameter - - System.Management.Automation.SwitchParameter - - - False - @@ -315,88 +500,129 @@ -------------------------- Example 1 -------------------------- - PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... + Find-PSResource -Name PowerShellGet -Repository PSGallery + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PowerShellGet 2.2.5.0 PSGallery PowerShell module with commands for discovering, installing, updating and … - This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest non-prerelease version for the package found by searching through the `-Repository` "PSGallery", which at the time of writing this example is version "1.0.0.0". + -------------------------- Example 2 -------------------------- - PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Repository PSGallery -Prerelease - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 1.1.0.0 preview2 This module ... + Find-PSResource -Name PowerShellGet -Repository PSGallery -Prerelease + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PowerShellGet 3.0.14.0 beta14 PSGallery PowerShell module with commands for discovering, installing, updating and… - This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns the highest version (including considering prerelease versions) for the package found by searching through the specified `-Repository` "PSGallery", which at the time of writing this example is version "1.1.0-preview2". + -------------------------- Example 3 -------------------------- - PS C:\> Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.0.0.0]" -Repository PSGallery -Prerelease - Name Version Prerelease Description - ---- ------- ---------- ----------- - Microsoft.PowerShell.SecretManagement 0.9.1.0 This module ... - Microsoft.PowerShell.SecretManagement 1.0.0.0 This module ... + Find-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "(0.9.0.0, 1.2.0.0]" -Repository PSGallery -Prerelease + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +Microsoft.PowerShell.SecretManagement 1.1.2.0 PSGallery … +Microsoft.PowerShell.SecretManagement 1.1.1.0 PSGallery … +Microsoft.PowerShell.SecretManagement 1.1.0.0 PSGallery … +Microsoft.PowerShell.SecretManagement 1.0.0.0 PSGallery … +Microsoft.PowerShell.SecretManagement 0.9.1.0 PSGallery … - This examples searches for the package with `-Name` "Microsoft.PowerShell.SecretManagement". It returns all versions which satisfy the specified `-Version` range by looking through the specified `-Repository` "PSGallery". At the time of writing this example those satisfying versions are: "0.9.1.0" and "1.0.0.0". + -------------------------- Example 4 -------------------------- - PS C:\> Find-PSResource -CommandName "Get-TargetResource" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 3.1.0.0 xPowerShellExecutionPolicy PSGallery - Get-TargetResource 1.0.0.4 WindowsDefender PSGallery - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery - Get-TargetResource 1.0.0.0 xInternetExplorerHomePage PSGallery - Get-TargetResource 4.0.1055.0 OctopusDSC PSGallery - Get-TargetResource 1.2.0.0 cRegFile PSGallery - Get-TargetResource 1.1.0.0 cWindowsErrorReporting PSGallery - Get-TargetResource 1.0.0.0 cVNIC PSGallery - Get-TargetResource 1.1.17.0 supVsts PSGallery + Find-PSResource -CommandName Get-TargetResource -Repository PSGallery | + Select-Object -ExpandProperty ParentResource + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +xPowerShellExecutionPolicy 3.1.0.0 PSGallery This DSC resource can change the user preference for the W… +WindowsDefender 1.0.0.4 PSGallery Windows Defender module allows you to configure Windows De… +SystemLocaleDsc 1.2.0.0 PSGallery This DSC Resource allows configuration of the Windows Syst… +xInternetExplorerHomePage 1.0.0.0 PSGallery This DSC Resources can easily set an URL for the home page… +OctopusDSC 4.0.1127.0 PSGallery Module with DSC resource to install and configure an Octop… +cRegFile 1.2.0.0 PSGallery DSC resource which is designed to manage large numbers of … +cWindowsErrorReporting 1.1.0.0 PSGallery DSC Resource to enable or disable Windows Error Reporting +cVNIC 1.0.0.0 PSGallery DSC Module to create and configuring virutal network adapt… +supVsts 1.1.17.0 PSGallery Dsc module for interfacing with VSTS. - This examples searches for all module resources with `-CommandName` "Get-TargetResource" from the `-Repository` PSGallery. It returns all the module resources which include a command named "Get-TargetResource" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + -------------------------- Example 5 -------------------------- - PS C:\> Find-PSResource -CommandName "Get-TargetResource" -ModuleName "SystemLocaleDsc" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + Find-PSResource -CommandName Get-TargetResource -ModuleName SystemLocaleDsc -Repository PSGallery | + Select-Object -ExpandProperty ParentResource + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +SystemLocaleDsc 1.2.0.0 PSGallery This DSC Resource allows configuration of the Windows System Locale. - This examples searches for a module resource with a command named "Get-TargetResource" (via the `-CommandName` parameter), specifically from the module resource "SystemLocaleDsc" (via the `-ModuleName` parameter) from the `-Repository` PSGallery. The "SystemLocaleDsc" resource does indeed include a command named Get-TargetResource so this resource will be returned. The returned object lists the name of the command (displayed under Name) and the following information for the parent module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the CommandName parameter set. + -------------------------- Example 6 -------------------------- - PS C:\> Find-PSResource -DscResourceName "SystemLocale" -Repository PSGallery - Name Version Prerelease ModuleName Repository - ---- ------- ---------- ---------- ---------- - Get-TargetResource 8.5.0.0 ComputerManagementDsc PSGallery - Get-TargetResource 1.2.0.0 SystemLocaleDsc PSGallery + Find-PSResource -DscResourceName SystemLocale -Repository PSGallery | + Select-Object -ExpandProperty ParentResource + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +ComputerManagementDsc 8.5.0.0 PSGallery DSC resources for configuration of a Windows computer. These DSC r… +SystemLocaleDsc 1.2.0.0 PSGallery This DSC Resource allows configuration of the Windows System Local… - This examples searches for all module resources with `-DscResourceName` "SystemLocale" from the `-Repository` PSGallery. It returns all the module resources which include a DSC resource named "SystemLocale" and also lists the following information for each module resource: version, name (displayed under ModuleName) and repository. To access the rest of the properties of the parent module resource, you can access the `$_.ParentResource` of the PSIncludedResourceInfo object returned from the DSCResourceName parameter set. + -------------------------- Example 7 -------------------------- - PS C:\> Find-PSResource -Name * + Find-PSResource -Name Computer* + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +ComputerManagementDsc 8.5.0.0 PSGallery DSC resources for configuration … +ComputerManagement 1.1.2.3 PSGallery A PowerShell module for working … +Computer_JoinDomain_Config 1.0.0.0 PSGalleryScripts This configuration sets the mach… +Computer_UnjoinDomainAndJoinWorkgroup_Config 1.0.0.0 PSGalleryScripts This example switches the comput… +Computer_SetComputerDescriptionInWorkgroup_Config 1.0.0.0 PSGalleryScripts This example will set the comput… +Computer_JoinDomainSpecifyingDC_Config 1.0.0.0 PSGalleryScripts This configuration sets the mach… +Computer_RenameComputerAndSetWorkgroup_Config 1.0.0.0 PSGalleryScripts This configuration will set the … +Computer_RenameComputerInDomain_Config 1.0.0.0 PSGalleryScripts This example will change the mac… +Computer_RenameComputerInWorkgroup_Config 1.0.0.0 PSGalleryScripts This example will set the machin… + + + + + + -------------------------- Example 8 -------------------------- + Find-PSResource -Tag CrescendoBuilt + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +Foil 0.1.0.0 PSGallery A PowerShell Crescendo wrapper for Chocolatey +Cobalt 0.3.1.0 PSGallery A PowerShell Crescendo wrapper for WinGet +SysInternals 1.1.0.0 PSGallery PowerShell cmdlets for SysInternal tools +Croze 0.0.4.0 PSGallery A PowerShell Crescendo wrapper for Homebrew +AptPackage 0.0.2.0 PSGallery PowerShell Crescendo-generated Module to query APT-Package Information +RoboCopy 1.0.1.0 PSGallery PowerShell cmdlet for the official RoboCopy.exe +TShark 1.0.2.0 PSGallery PowerShell cmdlet for tshark.exe +Image2Text 1.0.2.0 PSGallery PowerShell Images into ASCII art +SpeedTestCLI 1.0.0.0 PSGallery PowerShell cmdlets speedtest-cli +SpeedTest-CLI 1.0.0.0 PSGallery PowerShell cmdlets for Internet Speed Test +Quser.Crescendo 0.1.1.0 PSGallery This module displays session information of users logged onto a local or… +Takeown 1.0.2.0 PSGallery Crescendo Powershell wrapper of takeown.exe - This will search all PSResources from registered PSResourceRepositories. + - - - <add> - - - + @@ -404,19 +630,19 @@ Get PSResource - Returns resources (modules and scripts) installed on the machine via PowerShellGet. + Returns modules and scripts installed on the machine via PowerShellGet . - The Get-PSResource cmdlet combines the Get-InstalledModule, Get-InstalledScript cmdlets from V2. It performs a search within module or script installation paths based on the -Name parameter argument. It returns PSResourceInfo objects which describes each resource item found. Other parameters allow the returned results to be filtered by version and path. + This cmdlet searches the module and script installation paths and returns PSResourceInfo objects that describes each resource item found. This is equivalent to the combined output of the `Get-InstalledModule` and `Get-InstalledScript` cmdlets from PowerShellGet v2. Get-PSResource - + Name - Name of a resource or resources to find. Accepts wild card characters or a null value. + Name of a resource to find. Wildcards are supported but NuGet only accepts the `*` character. NuGet does not support wildcard searches of local (file-based) repositories. System.String[] @@ -437,19 +663,6 @@ None - - Version - - Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. - - System.String - - System.String - - - None - Scope @@ -466,13 +679,27 @@ None + + Version + + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + - + Name - Name of a resource or resources to find. Accepts wild card characters or a null value. + Name of a resource to find. Wildcards are supported but NuGet only accepts the `*` character. NuGet does not support wildcard searches of local (file-based) repositories. System.String[] @@ -494,26 +721,27 @@ None - Version + Scope - Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Specifies the scope of the resource. - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - Scope + Version - Specifies the scope of the resource. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.String - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.String None @@ -529,58 +757,77 @@ -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResource Az + Get-PSResource - This will return versions (stable and prerelease) of the Az module installed via PowerShellGet. + -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResource Az -version "1.0.0" + Get-PSResource Az - This will return version 1.0.0 of the Az module. + -------------------------- Example 3 -------------------------- - PS C:\> Get-PSResource Az -version "(1.0.0, 3.0.0)" + Get-PSResource Az -Path . - This will return all versions of the Az module within the specified range. + -------------------------- Example 4 -------------------------- - PS C:\> Get-PSResource Az -version "4.0.1-preview" + Get-PSResource Az -Version 1.0.0 - Assume that the package Az version 4.0.1-preview is already installed. This will return version 4.0.1-preview of the Az module. + -------------------------- Example 5 -------------------------- - PS C:\> Get-PSResource Az -version "4.0.1" + Get-PSResource Az -Version "(1.0.0, 3.0.0)" - Assume that the package Az version 4.0.1-preview is already installed. This will not return Az version 4.0.1-preview as the full version (including prerelease label, i.e "4.0.1-preview") was not specified. + -------------------------- Example 6 -------------------------- - PS C:\> Get-PSResource Az -Version "[4.0.1, 4.0.2-preview] + Get-PSResource PowerShellGet -Version 3.0.14-beta14 + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PowerShellGet 3.0.14 beta14 PSGallery PowerShell module with commands for discovering, installing, updating and … - Assume that the following versions are already installed for package Az: 4.0.1-preview and 4.0.2-preview. This will only return version 4.0.2-preview as it is the only one which falls within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be returned. + -------------------------- Example 6 -------------------------- - PS C:\> Get-PSResource Az -Path . + Get-PSResource PowerShellGet -Version 3.0.14 - This will return all versions of the Az module that have been installed in the current directory. + There is no output from this command. -------------------------- Example 7 -------------------------- - PS C:\> Get-PSResource + Get-PSResource PSReadLine + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PSReadLine 2.2.6 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.5 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.2 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.0 beta4 PSGallery Great command line editing in the PowerShell console host + +Get-PSResource PSReadLine -Version '[2.2.0, 2.3.0]' + +Name Version Prerelease Repository Description +---- ------- ---------- ---------- ----------- +PSReadLine 2.2.6 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.5 PSGallery Great command line editing in the PowerShell console host +PSReadLine 2.2.2 PSGallery Great command line editing in the PowerShell console host - This will return all versions and scripts installed on the machine. + According to NuGet version rules a prerelease version is less than a stable version, so `2.2.0-beta4` is less than the `2.2.0` version in the specified version range. @@ -596,7 +843,7 @@ - The Get-PSResourceRepository cmdlet searches for the PowerShell resource repositories that are registered on the machine. By default it will return all registered repositories, or if the `-Name` parameter argument is specified then it will return the repository which matches that name. It returns PSRepositoryInfo objects which contain information for each repository item found. + This cmdlet searches for PowerShell resource repositories that are registered on the machine. By default, it returns all registered repositories. @@ -604,11 +851,11 @@ Name - This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + The name of the repository to search for. Wildcards are supported. Tab completion for this parameter cycles through the registered repository names. - String[] + System.String[] - String[] + System.String[] None @@ -619,11 +866,11 @@ Name - This parameter takes a String argument, including wildcard characters, or an array of such String arguments. It is used to search for repository names from the repository store which match the provided name pattern. Tab completion is provided on this argument and will display registered repository names. + The name of the repository to search for. Wildcards are supported. Tab completion for this parameter cycles through the registered repository names. - String[] + System.String[] - String[] + System.String[] None @@ -651,52 +898,56 @@ - If no value for Name is provided, Get-PSResourceRepository will return information for all registered repositories. + -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 + Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 +psgettestlocal file:///c:/code/testdir True 50 - This example runs the command with the 'Name' parameter being set to "PSGallery". This repository is registered on this machine so the command returns information on this repository. + -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResourceRepository -Name "*Gallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 + Get-PSResourceRepository -Name PSGallery + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 - This example runs the command with the 'Name' parameter being set to "*Gallery" which includes a wildcard. The following repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + -------------------------- Example 3 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 + Get-PSResourceRepository -Name "*Gallery" + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 - This example runs the command with the 'Name' parameter being set to an array of Strings. Both of the specified repositories are registered on this machine and match the name pattern, so the command returns information on these repositories. + -------------------------- Example 4 -------------------------- - PS C:\> Get-PSResourceRepository -Name "*" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir True 50 + Get-PSResourceRepository -Name "PSGallery","PoshTestGallery" + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 - This example runs the command with the 'Name' parameter being set to a single wildcard character. So all the repositories registered on this machine are returned. + @@ -708,44 +959,158 @@ Install PSResource - Installs resources (modules and scripts) from a registered repository onto the machine. + Installs resources from a registered repository. - The Install-PSResource cmdlet combines the Install-Module and Install-Script cmdlets from V2. It installs a resource from a registered repository to an installation path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to suppress prompts or specify the scope of installation. + This cmdlet installs resources from a registered repository to an installation path on a machine. By default, the cmdlet doesn't return any object. Other parameters allow you to specify the repository, scope, and version for a resource, and suppress license prompts. + This cmdlet combines the functions of the `Install-Module` and `Install-Script` cmdlets from PowerShellGet v2. Install-PSResource - - Name + + AcceptLicense + + Specifies that the resource should accept any request to accept the license agreement. This suppresses prompting if the module mandates that a user accept the license agreement. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Validates Authenticode signatures and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + Credential + + Optional credentials used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + NoClobber + + Prevents installing a package that contains cmdlets that already exist on the machine. + + + System.Management.Automation.SwitchParameter + + + False + + + PassThru + + When specified, outputs a PSResourceInfo object for the saved resource. + + + System.Management.Automation.SwitchParameter + + + False + + + TemporaryPath + + Specifies the path to temporarily install the resource before actual installation. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + + System.String + + System.String + + + None + + + Quiet + + Suppresses installation progress bar. + + + System.Management.Automation.SwitchParameter + + + False + + + Reinstall + + Installs the latest version of a module even if the latest version is already installed. The installed version is overwritten. This allows you to repair a damaged installation of the module. + If an older version of the module is installed, the new version is installed side-by-side in a new version-specific folder. + + + System.Management.Automation.SwitchParameter + + + False + + + Scope - Name of a resource or resources to install. Does not accept wildcard characters or a null value. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation for install. + The `AllUsers` scope installs modules in a location accessible to all users of the computer. For example: + - `$env:ProgramFiles\PowerShell\Modules` + The `CurrentUser` installs modules in a location accessible only to the current user of the computer. For example: + - `$home\Documents\PowerShell\Modules` - System.String[] + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType None - Version + SkipDependencyCheck - Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. - System.String - System.String + System.Management.Automation.SwitchParameter - None + False - Prerelease + TrustRepository - When specified, includes prerelease versions in search results returned. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -753,10 +1118,35 @@ False - - Repository + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet isn't run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Install-PSResource + + Name - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + The name of one or more resources to install. System.String[] @@ -765,10 +1155,32 @@ None + + AcceptLicense + + Specifies that the resource should accept any request to accept the license agreement. This suppresses prompting if the module mandates that a user accept the license agreement. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Validates Authenticode signatures and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + Credential - Optional credentials to be used when accessing a repository. + Optional credentials used when accessing a repository. System.Management.Automation.PSCredential @@ -778,25 +1190,20 @@ None - Scope + NoClobber - Specifies the scope under which a user has access. + Prevents installing a package that contains cmdlets that already exist on the machine. - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - None + False - TrustRepository + PassThru - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -805,9 +1212,21 @@ False - Reinstall + TemporaryPath + + Specifies the path to temporarily install the resource before actual installation. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + + System.String + + System.String + + + None + + + Prerelease - Writes over any previously installed resource version that already exists on the machine. + When specified, includes prerelease versions in search results returned. System.Management.Automation.SwitchParameter @@ -818,7 +1237,7 @@ Quiet - Supresses installation progress bar. + Suppresses installation progress bar. System.Management.Automation.SwitchParameter @@ -827,9 +1246,10 @@ False - AcceptLicense + Reinstall - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + Installs the latest version of a module even if the latest version is already installed. The installed version is overwritten. This allows you to repair a damaged installation of the module. + If an older version of the module is installed, the new version is installed side-by-side in a new version-specific folder. System.Management.Automation.SwitchParameter @@ -838,31 +1258,47 @@ False - NoClobber + Repository - Prevents installing a package that contains cmdlets that already exist on the machine. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None - SkipDependencyCheck + Scope - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation for install. + The `AllUsers` scope installs modules in a location accessible to all users of the computer. For example: + - `$env:ProgramFiles\PowerShell\Modules` + The `CurrentUser` installs modules in a location accessible only to the current user of the computer. For example: + - `$home\Documents\PowerShell\Modules` + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - AuthenticodeCheck + SkipDependencyCheck - Does a check to to validate signed files and catalog files on Windows. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. System.Management.Automation.SwitchParameter @@ -871,9 +1307,9 @@ False - PassThru + TrustRepository - Passes the resource installed to the console. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -881,14 +1317,16 @@ False - - InputObject + + Version - Used for pipeline input. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String None @@ -907,7 +1345,7 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -918,92 +1356,56 @@ Install-PSResource - + RequiredResource - A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. - The hashtable will take a format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - A json string will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } + A hashtable or JSON string that specifies resources to install. Wildcard characters aren't allowed. See the NOTES (#notes)section for a description of the file formats. - RequiredResource + System.Object - RequiredResource + System.Object None - Credential + AcceptLicense - Optional credentials to be used when accessing a repository. + Specifies that the resource should accept any request to accept the license agreement. This suppresses prompting if the module mandates that a user accept the license agreement. - System.Management.Automation.PSCredential - System.Management.Automation.PSCredential + System.Management.Automation.SwitchParameter - None + False - Scope + AuthenticodeCheck - Specifies the scope under which a user has access. + Validates Authenticode signatures and catalog files on Windows. - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - None + False - TrustRepository + Credential - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + Optional credentials used when accessing a repository. + System.Management.Automation.PSCredential - System.Management.Automation.SwitchParameter + System.Management.Automation.PSCredential - False + None - Reinstall + NoClobber - Writes over any previously installed resource version that already exists on the machine. + Prevents installing a package that contains cmdlets that already exist on the machine. System.Management.Automation.SwitchParameter @@ -1012,9 +1414,9 @@ False - Quiet + PassThru - Supresses installation progress bar. + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -1023,20 +1425,21 @@ False - AcceptLicense + TemporaryPath - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + Specifies the path to temporarily install the resource before actual installation. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - NoClobber + Quiet - Prevents installing a package that contains cmdlets that already exist on the machine. + Suppresses installation progress bar. System.Management.Automation.SwitchParameter @@ -1045,9 +1448,10 @@ False - SkipDependencyCheck + Reinstall - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + Installs the latest version of a module even if the latest version is already installed. The installed version is overwritten. This allows you to repair a damaged installation of the module. + If an older version of the module is installed, the new version is installed side-by-side in a new version-specific folder. System.Management.Automation.SwitchParameter @@ -1056,20 +1460,33 @@ False - AuthenticodeCheck + Scope - Does a check to to validate signed files and catalog files on Windows. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation for install. + The `AllUsers` scope installs modules in a location accessible to all users of the computer. For example: + - `$env:ProgramFiles\PowerShell\Modules` + The `CurrentUser` installs modules in a location accessible only to the current user of the computer. For example: + - `$home\Documents\PowerShell\Modules` + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - PassThru + SkipDependencyCheck - Passes the resource installed to the console. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. System.Management.Automation.SwitchParameter @@ -1077,17 +1494,16 @@ False - - InputObject + + TrustRepository - Used for pipeline input. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.Management.Automation.SwitchParameter - None + False Confirm @@ -1103,7 +1519,7 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -1114,92 +1530,56 @@ Install-PSResource - + RequiredResourceFile - Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. - The psd1 will take a hashtable format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - json files will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } + Path to a `.psd1` or `.json` that specifies resources to install. Wildcard characters aren't allowed. See the NOTES (#notes)section for a description of the file formats. - System.String[] + System.String - System.String[] + System.String None - Credential + AcceptLicense - Optional credentials to be used when accessing a repository. + Specifies that the resource should accept any request to accept the license agreement. This suppresses prompting if the module mandates that a user accept the license agreement. - System.Management.Automation.PSCredential - System.Management.Automation.PSCredential + System.Management.Automation.SwitchParameter - None + False - Scope + AuthenticodeCheck - Specifies the scope under which a user has access. + Validates Authenticode signatures and catalog files on Windows. - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - None + False - TrustRepository + Credential - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + Optional credentials used when accessing a repository. + System.Management.Automation.PSCredential - System.Management.Automation.SwitchParameter + System.Management.Automation.PSCredential - False + None - Reinstall + NoClobber - Writes over any previously installed resource version that already exists on the machine. + Prevents installing a package that contains cmdlets that already exist on the machine. System.Management.Automation.SwitchParameter @@ -1208,9 +1588,9 @@ False - Quiet + PassThru - Supresses installation progress bar. + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -1219,20 +1599,21 @@ False - AcceptLicense + TemporaryPath - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + Specifies the path to temporarily install the resource before actual installation. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - NoClobber + Quiet - Prevents installing a package that contains cmdlets that already exist on the machine. + Suppresses installation progress bar. System.Management.Automation.SwitchParameter @@ -1241,9 +1622,10 @@ False - SkipDependencyCheck + Reinstall - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + Installs the latest version of a module even if the latest version is already installed. The installed version is overwritten. This allows you to repair a damaged installation of the module. + If an older version of the module is installed, the new version is installed side-by-side in a new version-specific folder. System.Management.Automation.SwitchParameter @@ -1252,20 +1634,33 @@ False - AuthenticodeCheck + Scope - Does a check to to validate signed files and catalog files on Windows. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation for install. + The `AllUsers` scope installs modules in a location accessible to all users of the computer. For example: + - `$env:ProgramFiles\PowerShell\Modules` + The `CurrentUser` installs modules in a location accessible only to the current user of the computer. For example: + - `$home\Documents\PowerShell\Modules` + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - PassThru + SkipDependencyCheck - Passes the resource installed to the console. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. System.Management.Automation.SwitchParameter @@ -1273,17 +1668,16 @@ False - - InputObject + + TrustRepository - Used for pipeline input. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.Management.Automation.SwitchParameter - None + False Confirm @@ -1299,7 +1693,7 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -1310,35 +1704,22 @@ - - Name - - Name of a resource or resources to install. Does not accept wildcard characters or a null value. - - System.String[] - - System.String[] - - - None - - Version + AcceptLicense - Specifies the version of the resource to be installed. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Specifies that the resource should accept any request to accept the license agreement. This suppresses prompting if the module mandates that a user accept the license agreement. - System.String + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter - None + False - Prerelease + AuthenticodeCheck - When specified, includes prerelease versions in search results returned. + Validates Authenticode signatures and catalog files on Windows. System.Management.Automation.SwitchParameter @@ -1348,95 +1729,33 @@ False - Repository + Credential - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + Optional credentials used when accessing a repository. - System.String[] + System.Management.Automation.PSCredential - System.String[] + System.Management.Automation.PSCredential None - - RequiredResource + + InputObject - A hashtable or json string which specifies resources to install. Does not accept wildcard characters or a null value. - The hashtable will take a format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - A json string will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } - - RequiredResource + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - RequiredResource + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None - RequiredResourceFile + Name - Path to a psd1 or json which specifies resources to install. Does not accept wildcard characters or a null value. - The psd1 will take a hashtable format with the module attributes like the following example - - @{ - TestModule = @{ - version = "[0.0.1,1.3.0]" - repository = "PSGallery" - } - - TestModulePrerelease = @{ - version = "[0.0.0,0.0.5]" - repository = "PSGallery" - prerelease = "true" - } - - TestModule99 = @{} - } - - json files will take the following example format - - { - "TestModule": { - "version": "[0.0.1,1.3.0)", - "repository": "PSGallery" - }, - "TestModulePrerelease": { - "version": "[0.0.0,0.0.5]", - "repository": "PSGallery", - "prerelease": "true" - }, - "TestModule99": {} - } + The name of one or more resources to install. System.String[] @@ -1446,45 +1765,45 @@ None - Credential + NoClobber - Optional credentials to be used when accessing a repository. + Prevents installing a package that contains cmdlets that already exist on the machine. - System.Management.Automation.PSCredential + System.Management.Automation.SwitchParameter - System.Management.Automation.PSCredential + System.Management.Automation.SwitchParameter - None + False - Scope + PassThru - Specifies the scope under which a user has access. + When specified, outputs a PSResourceInfo object for the saved resource. - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - None + False - TrustRepository + TemporaryPath - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + Specifies the path to temporarily install the resource before actual installation. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. - System.Management.Automation.SwitchParameter + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - Reinstall + Prerelease - Writes over any previously installed resource version that already exists on the machine. + When specified, includes prerelease versions in search results returned. System.Management.Automation.SwitchParameter @@ -1496,7 +1815,7 @@ Quiet - Supresses installation progress bar. + Suppresses installation progress bar. System.Management.Automation.SwitchParameter @@ -1506,9 +1825,10 @@ False - AcceptLicense + Reinstall - Specifies that the resource should accept any request to accept license. This will suppress prompting if the module mandates that a user accept their license. + Installs the latest version of a module even if the latest version is already installed. The installed version is overwritten. This allows you to repair a damaged installation of the module. + If an older version of the module is installed, the new version is installed side-by-side in a new version-specific folder. System.Management.Automation.SwitchParameter @@ -1518,33 +1838,67 @@ False - NoClobber + Repository - Prevents installing a package that contains cmdlets that already exist on the machine. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. - System.Management.Automation.SwitchParameter + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None + + + RequiredResource + + A hashtable or JSON string that specifies resources to install. Wildcard characters aren't allowed. See the NOTES (#notes)section for a description of the file formats. + + System.Object + + System.Object + + + None + + + RequiredResourceFile + + Path to a `.psd1` or `.json` that specifies resources to install. Wildcard characters aren't allowed. See the NOTES (#notes)section for a description of the file formats. + + System.String + + System.String + + + None - SkipDependencyCheck + Scope - Skips the check for resource dependencies, so that only found resources are installed, and not any resources the found resource depends on. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation for install. + The `AllUsers` scope installs modules in a location accessible to all users of the computer. For example: + - `$env:ProgramFiles\PowerShell\Modules` + The `CurrentUser` installs modules in a location accessible only to the current user of the computer. For example: + - `$home\Documents\PowerShell\Modules` - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - AuthenticodeCheck + SkipDependencyCheck - Does a check to to validate signed files and catalog files on Windows. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. System.Management.Automation.SwitchParameter @@ -1554,9 +1908,9 @@ False - PassThru + TrustRepository - Passes the resource installed to the console. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -1565,14 +1919,16 @@ False - - InputObject + + Version - Used for pipeline input. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String None @@ -1592,7 +1948,7 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -1603,52 +1959,80 @@ - + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + By default, the cmdlet doesn't return any objects. When the PassThru parameter is used, the cmdlet outputs a PSResourceInfo object for the saved resource. + + + + The RequiredResource and RequiredResourceFile parameters are used to match PSResources matching specific criteria. You can specify the criteria using a hashtable or a JSON object. For the RequiredResourceFile parameter, the hashtable is stored in a `.psd1` file and the JSON object is stored in a `.json` file. + The hashtable can contain attributes for multiple modules. The following example show the structure of the module specification: + + This example contains specifications for three modules. As you can, the module attributes are optional. -------------------------- Example 1 -------------------------- - PS C:\> Install-PSResource Az + Install-PSResource Az - Installs the Az module. + -------------------------- Example 2 -------------------------- - PS C:\> Install-PSResource Az -Version "[2.0.0, 3.0.0]" + Install-PSResource Az -Version '[7.3.0, 8.3.0]' - Installs the latest stable Az module that is within the range 2.0.0 and 3.0.0. + -------------------------- Example 3 -------------------------- - PS C:\> Install-PSResource Az -Repository PSGallery + Install-PSResource Az -Reinstall - Installs the latest stable Az module from the PowerShellGallery. + - -------------------------- Example 3 -------------------------- - PS C:\> Install-PSResource Az -Reinstall + -------------------------- Example 4 -------------------------- + Install-PSResource -RequiredResourceFile myRequiredModules.psd1 - Installs the Az module and will write over any previously installed version if it is already installed. + - -------------------------- Example 4 -------------------------- - PS C:\> Install-PSResource -RequiredResourceFile myRequiredModules.psd1 + -------------------------- Example 5 -------------------------- + Install-PSResource -RequiredResource @{ + TestModule = @{ + version = "[0.0.1,1.3.0]" + repository = "PSGallery" + } + TestModulePrerelease = @{ + version = "[0.0.0,0.0.5]" + repository = "PSGallery" + prerelease = "true" + } + TestModule99 = @{} +} - Installs the PSResources specified in the psd1 file. + - Online Version: + Package versioning + + + + Uninstall-PSResource @@ -1663,7 +2047,7 @@ - The Publish-PSResource cmdlet combines the Publish-Module and Publish-Script cmdlets from V2. It publishes a specified resource from the local computer to an online Nuget-based gallery by using an API key, stored as part of a user's profile in the gallery or to a local repository. You can specify the resource to publish either by the resource's name, or by the path to the folder containing the module or script resource. + This cmdlet combines the functions of the `Publish-Module` and `Publish-Script` cmdlets from PowerShellGet v2. `Publish-PSResource` publishes a resource from the local computer to an online Nuget-based repository. You can specify the resource by the resource's name or by the path containing the module or script resource. @@ -1671,7 +2055,7 @@ Path - When specified, includes prerelease versions in search. + The path to the module or script file or the path to a folder containing the module or script file to be published. System.String @@ -1681,7 +2065,7 @@ None - APIKey + ApiKey Specifies the API key that you want to use to publish a resource to the online gallery. @@ -1693,21 +2077,21 @@ None - Repository + Credential - Specifies the repository to publish to. + Specifies a user account that has rights to a specific repository. - System.String + System.Management.Automation.PSCredential - System.String + System.Management.Automation.PSCredential None - + DestinationPath - Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + Specifies the path where the NuGet package `.nupkg` file should be saved. This parameter can be used in conjunction with the Repository parameter to publish to a repository and also save the exact same package to the local file system. System.String @@ -1717,9 +2101,21 @@ None - Credential + Proxy + + The URL to a proxy server used to access repositories outside of your network. + + System.Uri + + System.Uri + + + None + + + ProxyCredential - Specifies a user account that has rights to a specific repository (used for finding dependencies). + The credentials required to use the proxy server. System.Management.Automation.PSCredential @@ -1728,10 +2124,22 @@ None + + Repository + + Specifies the repository to publish to. + + System.String + + System.String + + + None + SkipDependenciesCheck - Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + Bypasses the default check that all dependencies are present in the target repository. System.Management.Automation.SwitchParameter @@ -1753,7 +2161,7 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -1765,7 +2173,7 @@ - APIKey + ApiKey Specifies the API key that you want to use to publish a resource to the online gallery. @@ -1777,9 +2185,21 @@ None - Repository + Credential - Specifies the repository to publish to. + Specifies a user account that has rights to a specific repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + DestinationPath + + Specifies the path where the NuGet package `.nupkg` file should be saved. This parameter can be used in conjunction with the Repository parameter to publish to a repository and also save the exact same package to the local file system. System.String @@ -1791,7 +2211,7 @@ Path - When specified, includes prerelease versions in search. + The path to the module or script file or the path to a folder containing the module or script file to be published. System.String @@ -1800,22 +2220,22 @@ None - - DestinationPath + + Proxy - Specifies the path to where the resource (as a nupkg) should be saved to. This parameter can be used in conjunction with the -Repository parameter to publish to a repository and also save the exact same package to the local file system. + The URL to a proxy server used to access repositories outside of your network. - System.String + System.Uri - System.String + System.Uri None - Credential + ProxyCredential - Specifies a user account that has rights to a specific repository (used for finding dependencies). + The credentials required to use the proxy server. System.Management.Automation.PSCredential @@ -1824,10 +2244,22 @@ None + + Repository + + Specifies the repository to publish to. + + System.String + + System.String + + + None + SkipDependenciesCheck - Bypasses the default check that all dependencies are present on the repository which the resource is being published to. + Bypasses the default check that all dependencies are present in the target repository. System.Management.Automation.SwitchParameter @@ -1851,7 +2283,7 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -1865,31 +2297,26 @@ - + Fileshare-based repository have no metadata about the resources. Therefore, there is no way to check for dependencies. -------------------------- Example 1 -------------------------- - PS C:\> Publish-PSResource -Path c:\Test-Module + Publish-PSResource -Path c:\TestModule - This will publish the module 'Test-Module' to the highest priority repository + -------------------------- Example 2 -------------------------- - PS C:\> Publish-PSResource -Path c:\Test-Module -Repository PSGallery -APIKey '1234567' + Publish-PSResource -Path c:\TestModule -Repository PSGallery -APIKey '1234567' - This will publish the module 'Test-Module' to the PowerShellGallery. Note that the API key is a secret that is generated for a user from the website itself. + - - - Online Version: - - - + @@ -1901,7 +2328,7 @@ - The Register-PSResourceRepository cmdlet registers a repository for PowerShell resources. + The cmdlet registers a NuGet repository containing PowerShell resources. @@ -1909,70 +2336,109 @@ Name - Name of the repository to be registered. Cannot be "PSGallery". + Name of the repository to be registered. Can't be `PSGallery`. + + System.String + + System.String + + + None + + + Uri + + Specifies the location of the repository to be registered. The value must use one of the following URI schemas: + - `https://` + - `http://` + - `ftp://` + - `file://` - String + System.String - String + System.String None - - Uri + + CredentialInfo - Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. + A PSCredentialInfo object that includes the name of a vault and a secret that is stored in a Microsoft.PowerShell.SecretManagement store. - String + PSCredentialInfo - String + PSCredentialInfo None + + PassThru + + When specified, displays the successfully registered repository and its information. + + + System.Management.Automation.SwitchParameter + + + False + Priority - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + Specifies the priority ranking of the repository. Valid priority values range from 0 to 100. Lower values have a higher priority ranking. The default value is `100`. + Repositories are searched in priority order (highest first). - Int32 + System.Int32 - Int32 + System.Int32 50 - Trusted + Proxy - Specifies whether the repository should be trusted. + The URL to a proxy server used to access repositories outside of your network. + System.Uri - SwitchParameter + System.Uri - False + None - CredentialInfo + ProxyCredential - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + The credentials required to use the proxy server. - PSCredentialInfo + System.Management.Automation.PSCredential - PSCredentialInfo + System.Management.Automation.PSCredential None + + Trusted + + Specifies whether the repository should be trusted. + + + System.Management.Automation.SwitchParameter + + + False + Confirm Prompts you for confirmation before running the cmdlet. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -1980,47 +2446,72 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. - SwitchParameter + System.Management.Automation.SwitchParameter False + + + Register-PSResourceRepository PassThru - When specified, displays the succcessfully registered repository and its information. + When specified, displays the successfully registered repository and its information. - SwitchParameter + System.Management.Automation.SwitchParameter False - - - Register-PSResourceRepository Priority - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + Specifies the priority ranking of the repository. Valid priority values range from 0 to 100. Lower values have a higher priority ranking. The default value is `100`. + Repositories are searched in priority order (highest first). - Int32 + System.Int32 - Int32 + System.Int32 50 + + Proxy + + The URL to a proxy server used to access repositories outside of your network. + + System.Uri + + System.Uri + + + None + + + ProxyCredential + + The credentials required to use the proxy server. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + PSGallery When specified, registers PSGallery repository. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2031,7 +2522,7 @@ Specifies whether the repository should be trusted. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2042,7 +2533,7 @@ Prompts you for confirmation before running the cmdlet. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2050,80 +2541,82 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. - SwitchParameter + System.Management.Automation.SwitchParameter False + + + Register-PSResourceRepository PassThru - When specified, displays the succcessfully registered repository and its information. + When specified, displays the successfully registered repository and its information. - SwitchParameter + System.Management.Automation.SwitchParameter False - - - Register-PSResourceRepository - - Repository + + Proxy - Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + The URL to a proxy server used to access repositories outside of your network. - Hashtable[] + System.Uri - Hashtable[] + System.Uri None - Trusted + ProxyCredential - Specifies whether the repository should be trusted. + The credentials required to use the proxy server. + System.Management.Automation.PSCredential - SwitchParameter + System.Management.Automation.PSCredential - False + None - - Confirm + + Repository - Prompts you for confirmation before running the cmdlet. + Specifies an array of hashtables that contain repository information. Use this parameter to register multiple repositories at once. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet . + System.Collections.Hashtable[] - SwitchParameter + System.Collections.Hashtable[] - False + None - - WhatIf + + Confirm - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Prompts you for confirmation before running the cmdlet. - SwitchParameter + System.Management.Automation.SwitchParameter False - - PassThru + + WhatIf - When specified, displays the succcessfully registered repository and its information. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2131,50 +2624,99 @@ + + CredentialInfo + + A PSCredentialInfo object that includes the name of a vault and a secret that is stored in a Microsoft.PowerShell.SecretManagement store. + + PSCredentialInfo + + PSCredentialInfo + + + None + Name - Name of the repository to be registered. Cannot be "PSGallery". + Name of the repository to be registered. Can't be `PSGallery`. - String + System.String - String + System.String None + + PassThru + + When specified, displays the successfully registered repository and its information. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + Priority - Specifies the priority ranking of the repository. Repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 50, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). Has default value of 50. + Specifies the priority ranking of the repository. Valid priority values range from 0 to 100. Lower values have a higher priority ranking. The default value is `100`. + Repositories are searched in priority order (highest first). - Int32 + System.Int32 - Int32 + System.Int32 50 + + Proxy + + The URL to a proxy server used to access repositories outside of your network. + + System.Uri + + System.Uri + + + None + + + ProxyCredential + + The credentials required to use the proxy server. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + PSGallery When specified, registers PSGallery repository. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False - + Repository - Specifies an array of hashtables which contains repository information and is used to register multiple repositories at once. + Specifies an array of hashtables that contain repository information. Use this parameter to register multiple repositories at once. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet . - Hashtable[] + System.Collections.Hashtable[] - Hashtable[] + System.Collections.Hashtable[] None @@ -2184,9 +2726,9 @@ Specifies whether the repository should be trusted. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2194,24 +2736,15 @@ Uri - Specifies the location of the repository to be registered. Uri can be of the following Uri schemas: HTTPS, HTTP, FTP, file share based. - - String - - String - - - None - - - CredentialInfo - - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + Specifies the location of the repository to be registered. The value must use one of the following URI schemas: + - `https://` + - `http://` + - `ftp://` + - `file://` - PSCredentialInfo + System.String - PSCredentialInfo + System.String None @@ -2221,9 +2754,9 @@ Prompts you for confirmation before running the cmdlet. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2231,23 +2764,11 @@ WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. - - SwitchParameter - - SwitchParameter - - - False - - - PassThru - - When specified, displays the succcessfully registered repository and its information. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -2266,58 +2787,90 @@ - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter is used) + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo - + By default, the cmdlet produces no output. When you use the PassThru parameter, the cmdlet returns a PSRepositoryInfo object. - Repositories are unique by 'Name'. Attempting to register a repository with same 'Name' as an already registered repository will not successfully register. - Registering the PSGallery repository must be done via the PSGalleryParameterSet (i.e by using the 'PSGallery' parameter instead of 'Name' and 'Uri' parameters). - Uri string input must be of one of the following Uri schemes: HTTP, HTTPS, FTP, File + Repositories are unique by Name . Attempting to register a repository with same name results in an error. -------------------------- Example 1 -------------------------- - PS C:\> Register-PSResourceRepository -Name "PoshTestGallery" -Uri "https://www.powershellgallery.com/api/v2" -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + Register-PSResourceRepository -Name PoshTestGallery -Uri "https://www.powershellgallery.com/api/v2" +Get-PSResourceRepository -Name PoshTestGallery + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 - This example registers the repository with the `-Name` of "PoshTestGallery" along with the associated `Uri` value for it. + -------------------------- Example 2 -------------------------- - PS C:\> Register-PSResourceRepository -PSGallery -PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 + Register-PSResourceRepository -PSGallery +Get-PSResourceRepository -Name "PSGallery" + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 - This example registers the "PSGallery" repository, with the 'PSGallery' parameter. Unlike the previous example, we cannot use the `-Name` or `-Uri` parameters to register the "PSGallery" repository as it is considered Powershell's default repository store and has its own value for Uri. + -------------------------- Example 3 -------------------------- - PS C:\> $arrayOfHashtables = @{Name = "psgettestlocal"; Uri = "c:/code/testdir"}, @{PSGallery = $True} -PS C:\> Register-PSResourceRepository -Repository $arrayOfHashtables -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir False 50 + $arrayOfHashtables = @{Name = "Local"; Uri = "D:/PSRepoLocal/"; Trusted = $true; Priority = 20 }, + @{Name = "PSGv3"; Uri = "https://www.powershellgallery.com/api/v3"; Trusted = $true; Priority = 50 }, + @{PSGallery = $true; Trusted = $true; Priority = 10 } +Register-PSResourceRepository -Repository $arrayOfHashtables +Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +psgettestlocal file:///c:/code/testdir False 50 + + + + + + -------------------------- Example 4 -------------------------- + $parameters = @{ + Name = "PSGv3" + Uri = "https://www.powershellgallery.com/api/v3" + Trusted = $true + Priority = 50 + CredentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ('SecretStore', 'TestSecret') +} +Register-PSResourceRepository @parameters +Get-PSResourceRepository | Select-Object * -ExpandProperty CredentialInfo + +Name : PSGv3 +Uri : https://www.powershellgallery.com/api/v3 +Trusted : True +Priority : 50 +CredentialInfo : Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo +VaultName : SecretStore +SecretName : TestSecret +Credential : - This example registers multiple repositories at once. To do so, we use the `-Repository` parameter and provide an array of hashtables. Each hashtable can only have keys associated with parameters for the NameParameterSet or the PSGalleryParameterSet. Upon running the command we can see that the "psgettestlocal" and "PSGallery" repositories have been succesfully registered. + - + + + Microsoft.PowerShell.SecretManagement + + + @@ -2329,28 +2882,95 @@ PS C:\> Get-PSResourceRepository - The Save-PSResource cmdlet combines the Save-Module and Save-Script cmdlets from V2. It saves a resource from a registered repository to a specific path on a machine based on the -Name parameter argument. It does not return any object. Other parameters allow the resource to be specified by repository and version, and allow the user to save the resource as a .nupkg or with the PowerShellGet XML metadata. + This cmdlet combines the functionality of the `Save-Module` and `Save-Script` cmdlets from PowerShellGet v2. `Save-PSResource` downloads a resource from a registered repository to a specific path on the local machine. By default, the resource is saved in the unpacked or installed format. The scripts or modules could be run from the saved location. There is also an option to download the resource in `.nupkg` format. Save-PSResource - - Name + + AsNupkg + + Saves the resource as a `.nupkg` file. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Validates the resource's signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + + + Credential + + Optional credentials used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential + + + None + + + IncludeXML + + Includes the PowerShellGet metadata XML used to verify that PowerShellGet has installed a module. + + + System.Management.Automation.SwitchParameter + + + False + + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + PassThru - Name of a resource or resources to save. Does not accept wildcard characters or a null value. + When specified, outputs a PSResourceInfo object for the saved resource. - System.String[] - System.String[] + System.Management.Automation.SwitchParameter + + + False + + + Path + + Specifies the path to save the resource to. + + System.String + + System.String None - Version + TemporaryPath - Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Specifies the path to temporarily install the resource before saving. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. System.String @@ -2360,9 +2980,9 @@ PS C:\> Get-PSResourceRepository None - Prerelease + Quiet - Specifies to include prerelease versions. + Supresses progress information. System.Management.Automation.SwitchParameter @@ -2371,9 +2991,56 @@ PS C:\> Get-PSResourceRepository False - Repository + SkipDependencyCheck + + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. + + + System.Management.Automation.SwitchParameter + + + False + + + TrustRepository + + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. + + + System.Management.Automation.SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet isn't run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Save-PSResource + + Name - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + The name of one or more resources to install. System.String[] @@ -2382,10 +3049,32 @@ PS C:\> Get-PSResourceRepository None + + AsNupkg + + Saves the resource as a `.nupkg` file. + + + System.Management.Automation.SwitchParameter + + + False + + + AuthenticodeCheck + + Validates the resource's signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + Credential - Optional credentials to be used when accessing a repository. + Optional credentials used when accessing a repository. System.Management.Automation.PSCredential @@ -2395,9 +3084,9 @@ PS C:\> Get-PSResourceRepository None - AsNupkg + IncludeXML - Saves the resource as a zipped .nupkg file. + Includes the PowerShellGet metadata XML used to verify that PowerShellGet has installed a module. System.Management.Automation.SwitchParameter @@ -2406,9 +3095,9 @@ PS C:\> Get-PSResourceRepository False - IncludeXml + PassThru - Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -2416,7 +3105,7 @@ PS C:\> Get-PSResourceRepository False - + Path Specifies the path to save the resource to. @@ -2429,20 +3118,21 @@ PS C:\> Get-PSResourceRepository None - TrustRepository + TemporaryPath - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + Specifies the path to temporarily install the resource before saving. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - AuthenticodeCheck + Prerelease - Does a check to to validate signed files and catalog files on Windows. + When specified, includes prerelease versions in search results returned. System.Management.Automation.SwitchParameter @@ -2451,9 +3141,9 @@ PS C:\> Get-PSResourceRepository False - PassThru + Quiet - Passes the resource saved to the console. + Supresses progress information. System.Management.Automation.SwitchParameter @@ -2461,10 +3151,24 @@ PS C:\> Get-PSResourceRepository False + + Repository + + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. + + System.String[] + + System.String[] + + + None + SkipDependencyCheck - Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. System.Management.Automation.SwitchParameter @@ -2473,9 +3177,9 @@ PS C:\> Get-PSResourceRepository False - Quiet + TrustRepository - Supresses progress information. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -2483,14 +3187,16 @@ PS C:\> Get-PSResourceRepository False - - InputObject + + Version - Used for pipeline input. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String None @@ -2509,7 +3215,7 @@ PS C:\> Get-PSResourceRepository WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -2520,35 +3226,46 @@ PS C:\> Get-PSResourceRepository - - Name + + AsNupkg - Name of a resource or resources to save. Does not accept wildcard characters or a null value. + Saves the resource as a `.nupkg` file. - System.String[] + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False - Version + AuthenticodeCheck - Specifies the version of the resource to be saved. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Validates the resource's signed files and catalog files on Windows. - System.String + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter + + + False + + + Credential + + Optional credentials used when accessing a repository. + + System.Management.Automation.PSCredential + + System.Management.Automation.PSCredential None - Prerelease + IncludeXML - Specifies to include prerelease versions. + Includes the PowerShellGet metadata XML used to verify that PowerShellGet has installed a module. System.Management.Automation.SwitchParameter @@ -2557,34 +3274,34 @@ PS C:\> Get-PSResourceRepository False - - Repository + + InputObject - Specifies one or more repository names to search. If not specified, search will include all currently registered repositories, in order of highest priority, until first repository package is found in. + Used for pipeline input. - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - System.String[] + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo None - - Credential + + Name - Optional credentials to be used when accessing a repository. + The name of one or more resources to install. - System.Management.Automation.PSCredential + System.String[] - System.Management.Automation.PSCredential + System.String[] None - AsNupkg + PassThru - Saves the resource as a zipped .nupkg file. + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -2593,22 +3310,22 @@ PS C:\> Get-PSResourceRepository False - - IncludeXml + + Path - Includes the PowerShellGet metadata XML (used to verify that PowerShellGet has installed a module). + Specifies the path to save the resource to. - System.Management.Automation.SwitchParameter + System.String - System.Management.Automation.SwitchParameter + System.String - False + None - - Path + + TemporaryPath - Specifies the path to save the resource to. + Specifies the path to temporarily install the resource before saving. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. System.String @@ -2618,9 +3335,9 @@ PS C:\> Get-PSResourceRepository None - TrustRepository + Prerelease - Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository is not already set to a trusted level. + When specified, includes prerelease versions in search results returned. System.Management.Automation.SwitchParameter @@ -2630,9 +3347,9 @@ PS C:\> Get-PSResourceRepository False - AuthenticodeCheck + Quiet - Does a check to to validate signed files and catalog files on Windows. + Supresses progress information. System.Management.Automation.SwitchParameter @@ -2641,22 +3358,24 @@ PS C:\> Get-PSResourceRepository False - - PassThru + + Repository - Passes the resource saved to the console. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. - System.Management.Automation.SwitchParameter + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None SkipDependencyCheck - Skips the check for resource dependencies, so that only found resources are saved, and not any resources the found resource depends on. + Skips the check for resource dependencies. Only found resources are installed. No resources of the found resource are installed. System.Management.Automation.SwitchParameter @@ -2666,9 +3385,9 @@ PS C:\> Get-PSResourceRepository False - Quiet + TrustRepository - Supresses progress information. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -2677,14 +3396,16 @@ PS C:\> Get-PSResourceRepository False - - InputObject + + Version - Used for pipeline input. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String None @@ -2704,7 +3425,7 @@ PS C:\> Get-PSResourceRepository WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -2715,7 +3436,16 @@ PS C:\> Get-PSResourceRepository - + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + By default, the cmdlet doesn't return any objects. When the PassThru parameter is used, the cmdlet outputs a PSResourceInfo object for the saved resource. + + + @@ -2724,39 +3454,34 @@ PS C:\> Get-PSResourceRepository -------------------------- Example 1 -------------------------- - PS C:\> Save-PSResource -Name Az + Save-PSResource -Name Az - Saves the Az module + -------------------------- Example 2 -------------------------- - PS C:\> Save-PSResource -Name Az -Repository PSGallery + Save-PSResource -Name Az -Repository PSGallery - Saves the Az module found in the PowerShellGallery + -------------------------- Example 3 -------------------------- - PS C:\> Save-PSResource Az -AsNupkg + Save-PSResource Az -AsNupkg - Saves the Az module as a .nupkg file + -------------------------- Example 4 -------------------------- - PS C:\> Save-PSResource Az -IncludeXml + Save-PSResource Az -IncludeXML - Saves the Az module and includes the PowerShellGet XML metadata + - - - Online Version: - - - + @@ -2773,22 +3498,47 @@ PS C:\> Get-PSResourceRepository Set-PSResourceRepository - + Name - Specifies the name of the repository to be set. + Specifies the name of the repository to be modified. + > [!NOTE] > The Uri value of the default PSGallery repository can't be changed. + + System.String + + System.String + + + None + + + CredentialInfo + + A PSCredentialInfo object that includes the name of a vault and a secret that is stored in a Microsoft.PowerShell.SecretManagement store. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo + + + None + + + PassThru + + When specified, displays the successfully registered repository and its information. - System.String - System.String + System.Management.Automation.SwitchParameter - None + False Priority - Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + Specifies the priority ranking of the repository. Valid priority values range from 0 to 50. Lower values have a higher priority ranking. The default value is `50`. + Repositories are searched in priority order (highest first). System.Int32 @@ -2811,32 +3561,48 @@ PS C:\> Get-PSResourceRepository Uri - Specifies the location of the repository to be set. + Specifies the location of the repository to be registered. The value must use one of the following URI schemas: + - `https://` + - `http://` + - `ftp://` + - `file://` - String + System.String - String + System.String None - - CredentialInfo + + Confirm - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + Prompts you for confirmation before running the cmdlet. - PSCredentialInfo - PSCredentialInfo + System.Management.Automation.SwitchParameter - None + False - + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet isn't run. + + + System.Management.Automation.SwitchParameter + + + False + + + + Set-PSResourceRepository + PassThru - When specified, displays the succcessfully registered repository and its information + When specified, displays the successfully registered repository and its information. System.Management.Automation.SwitchParameter @@ -2844,6 +3610,18 @@ PS C:\> Get-PSResourceRepository False + + Repository + + Specifies an array of hashtables that contain repository information. Use this parameter to register multiple repositories at once. Each hashtable can only have keys associated with parameters for the NameParameterSet . + + System.Collections.Hashtable[] + + System.Collections.Hashtable[] + + + None + Confirm @@ -2858,7 +3636,7 @@ PS C:\> Get-PSResourceRepository WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -2869,34 +3647,35 @@ PS C:\> Get-PSResourceRepository - - Name + + CredentialInfo - Specifies the name of the repository to be set. + A PSCredentialInfo object that includes the name of a vault and a secret that is stored in a Microsoft.PowerShell.SecretManagement store. - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo - System.String + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo None - - Priority + + Name - Specifies the priority ranking of the repository, such that repositories with higher ranking priority are searched before a lower ranking priority one, when searching for a repository item across multiple registered repositories. Valid priority values range from 0 to 100, such that a lower numeric value (i.e 10) corresponds to a higher priority ranking than a higher numeric value (i.e 40). + Specifies the name of the repository to be modified. + > [!NOTE] > The Uri value of the default PSGallery repository can't be changed. - System.Int32 + System.String - System.Int32 + System.String None - Trusted + PassThru - Specifies whether the repository should be trusted. + When specified, displays the successfully registered repository and its information. System.Management.Automation.SwitchParameter @@ -2906,34 +3685,34 @@ PS C:\> Get-PSResourceRepository False - Uri + Priority - Specifies the location of the repository to be set. + Specifies the priority ranking of the repository. Valid priority values range from 0 to 50. Lower values have a higher priority ranking. The default value is `50`. + Repositories are searched in priority order (highest first). - String + System.Int32 - String + System.Int32 None - - CredentialInfo + + Repository - Specifies where a credential is stored to access the PSResourceRepository for Find/Install/Update commands. Takes a PSCredentialInfo Objects which takes in a vault name and secret name. This parameter utilizes the Microsoft.PowerShell.SecretManagement module for interfacing with the stored credential. - `New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("VaultName", "SecretName")` + Specifies an array of hashtables that contain repository information. Use this parameter to register multiple repositories at once. Each hashtable can only have keys associated with parameters for the NameParameterSet . - PSCredentialInfo + System.Collections.Hashtable[] - PSCredentialInfo + System.Collections.Hashtable[] None - - PassThru + + Trusted - When specified, displays the succcessfully registered repository and its information + Specifies whether the repository should be trusted. System.Management.Automation.SwitchParameter @@ -2942,6 +3721,22 @@ PS C:\> Get-PSResourceRepository False + + Uri + + Specifies the location of the repository to be registered. The value must use one of the following URI schemas: + - `https://` + - `http://` + - `ftp://` + - `file://` + + System.String + + System.String + + + None + Confirm @@ -2957,7 +3752,7 @@ PS C:\> Get-PSResourceRepository WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -2988,10 +3783,10 @@ PS C:\> Get-PSResourceRepository - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo (if 'PassThru' parameter used) + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo - + By default, the cmdlet produces no output. When you use the PassThru parameter, the cmdlet returns a PSRepositoryInfo object. @@ -3003,53 +3798,87 @@ PS C:\> Get-PSResourceRepository -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery file:///c:/code/testdir False 50 + Get-PSResourceRepository -Name "PoshTestGallery" + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + +Set-PSResourceRepository -Name "PoshTestGallery" -Uri "c:/code/testdir" -PassThru + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery file:///c:/code/testdir False 50 - This example first checks if the PoshTestGallery repository has been registered. We wish to set the `-Uri` value of this repository by running the Set-PSResourceRepository cmdlet with the `-Uri` parameter and a valid Uri scheme Uri. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Uri` of the repository was changed. We also use the `-PassThru` parameter to see the changed repository. + -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PSGallery" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 -PS C:\> Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 True 25 + Get-PSResourceRepository -Name "PSGallery" + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 + +Set-PSResourceRepository -Name "PSGallery" -Priority 25 -Trusted -PassThru + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 25 - This example first checks if the PSGallery repository has been registered. We wish to set the `-Priority` and `-Trusted` values of this repository by running the Set-PSResourceRepository cmdlet with the `-Priority` parameter set to a value between 0 and 100 and by using the `-Trusted` parameter switch. We run the Get-PSResourceRepository cmdlet again to ensure that the `-Priority` and `-Trusted` values of the repository were changed. An important note here is that just for the default PSGallery repository, the `-Uri` value can't be changed/set. We also use the `-PassThru` parameter to see the changed repository. + -------------------------- Example 3 -------------------------- - PS C:\> Get-PSResourceRepository -Name "*" - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 - PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 + Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 +PoshTestGallery https://www.poshtestgallery.com/api/v2 False 50 -PS C:\> $arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} +$arrayOfHashtables = @{Name = "PSGallery"; Trusted = $True}, + @{Name = "PoshTestGallery"; Uri = "c:/code/testdir"} +Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 50 +PoshTestGallery file:///c:/code/testdir False 50 + + + + + + -------------------------- Example 4 -------------------------- + $parameters = @{ + Name = "PoshTestGallery" + Uri = "c:/code/testdir" + CredentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ('SecretStore', 'TestSecret') +} +Set-PSResourceRepository @parameters -PassThru | Select-Object * -ExpandProperty CredentialInfo -PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 True 50 - PoshTestGallery file:///c:/code/testdir False 50 +Name : PoshTestGallery +Uri : file:///c:/code/testdir +Trusted : False +Priority : 50 +CredentialInfo : Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo +VaultName : SecretStore +SecretName : TestSecret +Credential : - This example first checks for all registered repositories. We wish to set the properties for multiple repositories at once (i.e the PSGallery and PoshTestGallery repositories), so we run Set-PSResourceRepository with the `-Repository` parameter. This parameter takes an array of hashtables, where each hashtable contains information for a repository we wish to set information for. We also use the `-PassThru` parameter to see the changed repositories. + - + + + Microsoft.PowerShell.SecretManagement + + + @@ -3057,19 +3886,95 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Uninstall PSResource - Uninstalls a resource (module or script) that has been installed on the machine via PowerShellGet. + Uninstalls a resource that was installed using PowerShellGet . - The Uninstall-PSResource cmdlet combines the Uninstall-Module, Uninstall-Script cmdlets from V2. It uninstalls a package found in a module or script installation path based on the -Name parameter argument. It does not return an object. Other parameters allow the returned results to be further filtered. + This cmdlet combines the functionality of the `Uninstall-Module` and `Uninstall-Script` cmdlets from PowerShellGet v2. The cmdlet searches the package installation paths for resources that have the PowerShellGet XML metadata file. Matching resources are uninstalled from the system. + By default, the cmdlet checks to see whether the resource being removed is a dependency for another resource. + + Uninstall-PSResource + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + + + Prerelease + + Indicates that only prerelease version resources should be removed. + + + System.Management.Automation.SwitchParameter + + + False + + + Scope + + Specifies the scope of the resource to uninstall. + + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + + + None + + + SkipDependencyCheck + + By default, the cmdlet checks to see whether the resource being removed is a dependency for another resource. Using this parameter skips the dependency test. + + + System.Management.Automation.SwitchParameter + + + False + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet isn't run. + + + System.Management.Automation.SwitchParameter + + + False + + Uninstall-PSResource Name - Name of a resource or resources that has been installed. Accepts wild card characters. + Name of a resource or resources to remove. Wildcards are supported but NuGet only accepts the `*` character. System.String[] @@ -3078,17 +3983,16 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru None - - Version + + Prerelease - Specifies the version of the resource to be uninstalled. + Indicates that only prerelease version resources should be removed. - System.String - System.String + System.Management.Automation.SwitchParameter - None + False Scope @@ -3109,7 +4013,7 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru SkipDependencyCheck - Skips check to see if other resources are dependent on the resource being uninstalled. + By default, the cmdlet checks to see whether the resource being removed is a dependency for another resource. Using this parameter skips the dependency test. System.Management.Automation.SwitchParameter @@ -3117,22 +4021,35 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru False - - InputObject + + Version - Used for pipeline input. + Specifies the version of the resource to be removed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + System.String None + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + System.Management.Automation.SwitchParameter + + + False + WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -3143,10 +4060,22 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru + + InputObject + + Used for pipeline input. + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + None + Name - Name of a resource or resources that has been installed. Accepts wild card characters. + Name of a resource or resources to remove. Wildcards are supported but NuGet only accepts the `*` character. System.String[] @@ -3155,17 +4084,17 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru None - - Version + + Prerelease - Specifies the version of the resource to be uninstalled. + Indicates that only prerelease version resources should be removed. - System.String + System.Management.Automation.SwitchParameter - System.String + System.Management.Automation.SwitchParameter - None + False Scope @@ -3179,10 +4108,36 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru None - - SkipDependencyCheck + + SkipDependencyCheck + + By default, the cmdlet checks to see whether the resource being removed is a dependency for another resource. Using this parameter skips the dependency test. + + System.Management.Automation.SwitchParameter + + System.Management.Automation.SwitchParameter + + + False + + + Version + + Specifies the version of the resource to be removed. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. + + System.String + + System.String + + + None + + + Confirm - Skips check to see if other resources are dependent on the resource being uninstalled. + Prompts you for confirmation before running the cmdlet. System.Management.Automation.SwitchParameter @@ -3191,22 +4146,10 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru False - - InputObject - - Used for pipeline input. - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo - - - None - WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -3226,41 +4169,50 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru -------------------------- Example 1 -------------------------- - PS C:\> Uninstall-PSResource Az + Uninstall-PSResource Az - Uninstalls the latest version of the Az module. + -------------------------- Example 2 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "1.0.0" + Uninstall-PSResource -name Az -version "5.0.0" - Uninstalls version 1.0.0 of the Az module. + -------------------------- Example 3 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "(1.0.0, 3.0.0)" + Uninstall-PSResource -name Az -version "(5.0.0, 7.5.0)" - Uninstalls all versions within the specified version range. + -------------------------- Example 4 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" + Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" - Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed, this will uninstall all versions (stable and prerelease) which fall within the specified version range. Per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version so 4.0.1-preview does not fall within the specified version range and won't be removed. Versions 4.1.0 and 4.0.2-preview do fall in the range and will both be removed. + - -------------------------- Example 4 -------------------------- - PS C:\> Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease + -------------------------- Example 5 -------------------------- + Uninstall-PSResource -name Az -version "[4.0.1, 4.1.0]" -Prerelease - Assume that the following versions are already installed for package Az: 4.0.1-preview, 4.1.0, 4.0.2-preview installed. This is the same example as above, except the added `-Prerelease` parameter means only prerelease versions which fall within this range will be removed. Again, per NuGetVersion rules, a prerelease version is less than a stable version, so 4.0.1-preview is actually less than the 4.0.1 specified version. Therefore 4.0.1-preview does not fall within the specified version range and won't be removed. Version 4.1.0 does fall in range however it is not a prerelease version so it will remain installed. Version 4.0.2-preview does fall in the range and is prerelease so it will be removed. + - + + + Package versioning + + + + Install-PSResource + + + @@ -3268,11 +4220,11 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Unregister PSResourceRepository - Un-registers a repository from the repository store. + Removes a registered repository from the local machine. - The Unregister-PSResourceRepository cmdlet unregisters a repository. + The cmdlet removes a registered repository from the the local machine. @@ -3280,11 +4232,11 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Name - This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + The name of one or more repositories to remove. - String[] + System.String[] - String[] + System.String[] None @@ -3292,10 +4244,10 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru PassThru - Passes the resource installed to the console. + When specified, outputs a PSRepositoryInfo object for each repository that is removed. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -3306,7 +4258,7 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Prompts you for confirmation before running the cmdlet. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -3314,10 +4266,10 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -3328,11 +4280,11 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Name - This parameter takes a String argument, or an array of String arguments. It is the name of the repository to un-register. + The name of one or more repositories to remove. - String[] + System.String[] - String[] + System.String[] None @@ -3340,11 +4292,11 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru PassThru - Passes the resource installed to the console. + When specified, outputs a PSRepositoryInfo object for each repository that is removed. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -3354,9 +4306,9 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru Prompts you for confirmation before running the cmdlet. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -3364,11 +4316,11 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. - SwitchParameter + System.Management.Automation.SwitchParameter - SwitchParameter + System.Management.Automation.SwitchParameter False @@ -3384,7 +4336,16 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru - + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSRepositoryInfo + + + By default, the cmdlet doesn't return any objects. When the PassThru parameter is used, the cmdlet outputs a PSRepositoryInfo object for each repository that is removed. + + + @@ -3393,34 +4354,52 @@ PS C:\> Set-PSResourceRepository -Repository $arrayOfHashtables -PassThru -------------------------- Example 1 -------------------------- - PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" -PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery" -PS C:\> Get-PSResourceRepository -Name "PoshTestGallery" -PS C:\> + Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 10 +Local file:///D:/PSRepoLocal/ True 20 +PSGv3 https://www.powershellgallery.com/api/v3 True 50 + +Unregister-PSResourceRepository -Name PSGv3 +Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 True 10 +Local file:///D:/PSRepoLocal/ True 20 - In this example, we assume the repository "PoshTestGallery" has been previously registered. So when we first run the command to find "PoshTestGallery" it verifies that this repository can be found. Next, we run the command to unregister "PoshTestGallery". Finally, we again run the command to find "PoshTestGallery" but since it was successfully un-registered it cannot be found or retrieved. + -------------------------- Example 2 -------------------------- - PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 - PSGallery https://www.powershellgallery.com/api/v2 False 50 - psgettestlocal file:///c:/code/testdir True 50 + Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PoshTestGallery https://www.poshtestgallery.com/api/v2 True 40 +PSGallery https://www.powershellgallery.com/api/v2 False 50 +psgettestlocal file:///c:/code/testdir True 50 -PS C:\> Unregister-PSResourceRepository -Name "PoshTestGallery","psgettestlocal" -PS C:\> Get-PSResourceRepository - Name Uri Trusted Priority - ---- --- ------- -------- - PSGallery https://www.powershellgallery.com/api/v2 False 50 +Unregister-PSResourceRepository -Name PoshTestGallery, psgettestlocal +Get-PSResourceRepository + +Name Uri Trusted Priority +---- --- ------- -------- +PSGallery https://www.powershellgallery.com/api/v2 False 50 - In this example, the command to find all registered repositories is run and the repositories found are displayed. Next, the command to un-register is run with a list of names ("PoshTestGallery", "psgettestlocal") provided for the `-Name` parameter. Finally, the command to find all registered repositories is run again, but this time we can see that "PoshTestGallery" and "psgettestlocal" are not found and displayed as they have been successfully unregistered. + - + + + Register-PSResourceRepository + + + @@ -3432,56 +4411,68 @@ PS C:\> Get-PSResourceRepository - The Update-ModuleManifest cmdlet replaces the Update-ModuleManifest cmdlet from V2. It updates a module manifest based on the `-Path` parameter argument. It does not return an object. Other parameters allow specific properties of the manifest to be updated. + This cmdlet updates the data stored in a module manifest file. The parameters allow you to specify which properties get updated. `Update-ModuleManifest` overwrites any existing values in the module manifest. + The cmdlet doesn't return an object. Update-ModuleManifest - + Path - Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + Specifies the path and filename of the module manifest. Enter filename with a `.psd1` file extension. - String + System.String - String + System.String None - - NestedModules + + AliasesToExport - Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + Specifies the aliases that the module exports. Wildcards are permitted. - Object[] + System.String[] - Object[] + System.String[] None - Guid + Author - Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + Specifies the module author. - System.Guid + System.String - System.Guid + System.String None - Author + ClrVersion - Specifies the module author. + Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework required by the module. + + System.Version + + System.Version + + + None + + + CmdletsToExport + + Specifies the cmdlets that the module exports. Wildcards are permitted. - String + System.String[] - String + System.String[] None @@ -3491,31 +4482,33 @@ PS C:\> Get-PSResourceRepository Specifies the company or vendor who created the module. - String + System.String - String + System.String None - Copyright + CompatiblePSEditions - Specifies a copyright statement for the module. + Specifies the compatible PSEditions of the module. For information about PSEdition , see Modules with compatible PowerShell Editions (/powershell/scripting/gallery/concepts/module-psedition-support). - String + + Desktop + Core + + System.String[] - String + System.String[] None - RootModule + Copyright - Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. - If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). - To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + Specifies a copyright statement for the module. System.String @@ -3525,13 +4518,13 @@ PS C:\> Get-PSResourceRepository None - ModuleVersion + DefaultCommandPrefix - Specifies the version of the module. + Specifies the default command prefix. - System.Version + System.String - System.Version + System.String None @@ -3549,33 +4542,22 @@ PS C:\> Get-PSResourceRepository None - ProcessorArchitecture + DotNetFrameworkVersion - Specifies the processor architecture that the module requires. - The acceptable values for this parameter are: - * Amd64 - * Arm - * IA64 - * MSIL - * None (unknown or unspecified) - * X86 + Specifies the minimum version of the Microsoft .NET Framework required by the module. - System.Reflection.ProcessorArchitecture + System.Version - System.Reflection.ProcessorArchitecture + System.Version None - - CompatiblePSEditions + + DscResourcesToExport - Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. - - Desktop - Core - System.String[] System.String[] @@ -3584,216 +4566,198 @@ PS C:\> Get-PSResourceRepository None - PowerShellVersion + ExternalModuleDependencies - Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + Specifies an array of external module dependencies. - System.Version + System.String[] - System.Version + System.String[] None - ClrVersion + FileList - Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + Specifies all items that are included in the module. - System.Version + System.String[] - System.Version + System.String[] None - DotNetFrameworkVersion + FormatsToProcess - Specifies the minimum version of the Microsoft .NET Framework that the module requires. + Specifies the formatting files (`.ps1xml`) that are processed when the module is imported. + When you import a module, PowerShell runs the `Update-FormatData` cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. - System.Version + System.String[] - System.Version + System.String[] None - - PowerShellHostName + + FunctionsToExport - Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. - To find the name of a host program, in the program, type $Host.Name. + Specifies the functions that the module exports. Wildcards are permitted. - System.String + System.String[] - System.String + System.String[] None - PowerShellHostVersion + Guid - Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + Specifies a unique identifier for the module. The GUID is used to distinguish between modules with the same name. - System.Version + System.Guid - System.Version + System.Guid None - RequiredModules + HelpInfoUri - Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with `http:` or `https:`. + For more information, see Updatable Help (/powershell/module/microsoft.powershell.core/about/about_updatable_help). - System.Object[] + System.Uri - System.Object[] + System.Uri None - TypesToProcess + IconUri - Specifies the type files (.ps1xml) that run when the module is imported. - When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + Specifies the URI of an icon for the module. The specified icon is displayed on the gallery web page for the module. - System.String[] + System.Uri - System.String[] + System.Uri None - FormatsToProcess + LicenseUri - Specifies the formatting files (.ps1xml) that run when the module is imported. - When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + Specifies the URL of licensing terms for the module. - System.String[] + System.Uri - System.String[] + System.Uri None - ScriptsToProcess + ModuleList - Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. - To specify scripts that run in the module's session state, use the NestedModules key. + Specifies an array of modules that are included in the module. + Enter each module name as a string or as a hashtable with ModuleName and ModuleVersion keys. The hashtable can also have an optional GUID key. You can combine strings and hashtables in the parameter value. + This key is designed to act as a module inventory. - System.String[] + System.Object[] - System.String[] + System.Object[] None - RequiredAssemblies + ModuleVersion - Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. - Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + Specifies the version of the module. - System.String[] + System.Version - System.String[] + System.Version None - FileList + NestedModules - Specifies all items that are included in the module. + Specifies script modules (`.psm1`) and binary modules (`.dll`) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed. + Enter each module name as a string or as a hashtable with ModuleName and ModuleVersion keys. The hashtable can also have an optional GUID key. You can combine strings and hashtables in the parameter value. - System.String[] + System.Object[] - System.String[] + System.Object[] None - ModuleList - - Specifies an array of modules that are included in the module. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. - This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. - - System.String[] - - System.String[] - - - None - - - FunctionsToExport + PassThru - Specifies the functions that the module exports. Wildcards are permitted. - Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + - System.String[] - System.String[] + System.Management.Automation.SwitchParameter - None + False - - AliasesToExport + + PowerShellHostName - Specifies the aliases that the module exports. Wildcards are permitted. - Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + The name of a host program is stored in `$Host.Name`. - System.String[] + System.String - System.String[] + System.String None - - VariablesToExport + + PowerShellHostVersion - Specifies the variables that the module exports. Wildcards are permitted. - Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. - System.String[] + System.Version - System.String[] + System.Version None - - CmdletsToExport + + PowerShellVersion - Specifies the cmdlets that the module exports. Wildcards are permitted. - Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + Specifies the minimum version of PowerShell that works with this module. For example, you can specify versions such as `5.1` or `7.2`. - System.String[] + System.Version - System.String[] + System.Version None - - DscResourcesToExport + + Prerelease - Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + Specifies the prerelease value that is appended to the module version. For example, if Prerelease is `preview` and the ModuleVersion is `1.0.0`, the version of the module is `1.0.0-preview`. - System.String[] + System.String - System.String[] + System.String None @@ -3801,23 +4765,30 @@ PS C:\> Get-PSResourceRepository PrivateData - Specifies data that is passed to the module when it's imported. + Specifies data that is passed to the module when it's imported. This can be any arbitrary values stored in a hashtable. - Hashtable + System.Collections.Hashtable - Hashtable + System.Collections.Hashtable None - Tags + ProcessorArchitecture - Specifies an array of tags. + Specifies the processor architecture that the module requires. + The acceptable values for this parameter are: + - `Amd64` + - `Arm` + - `IA64` + - `MSIL` + - `None` (unknown or unspecified) + - `X86` - System.String[] + System.Reflection.ProcessorArchitecture - System.String[] + System.Reflection.ProcessorArchitecture None @@ -3825,55 +4796,71 @@ PS C:\> Get-PSResourceRepository ProjectUri - Specifies the URL of a web page about this project. + Specifies the URI of a web page about this project. - Uri + System.Uri - Uri + System.Uri None - LicenseUri + ReleaseNotes - Specifies the URL of licensing terms for the module. + Specifies a string that contains release notes or comments for the module. - Uri + System.String - Uri + System.String None - IconUri + RequiredAssemblies - Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + Specifies the assembly (`.dll`) files required by the module. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file specified in the RootModule key. + Use RequiredAssemblies for assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed in the NestedModules key. - Uri + System.String[] - Uri + System.String[] None - ReleaseNotes + RequiredModules - Specifies a string array that contains release notes or comments that you want available for this version of the script. + Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the `Import-Module` command fails. + The value can be an array containing module names or module specifications. A module specification is a hashtable that has the following keys. + - `ModuleName` - Required Specifies the module name. - `GUID` - Optional Specifies the GUID of the module. - It's also Required to specify at least one of the three below keys. - `ModuleVersion` - Specifies a minimum acceptable version of the module. - `MaximumVersion` - Specifies the maximum acceptable version of the module. - `RequiredVersion` - Specifies an exact, required version of the module. This can't be used with the other Version keys. - System.String[] + System.Object[] - System.String[] + System.Object[] None - Prerelease + RequireLicenseAcceptance + + Specifies that a license acceptance is required for the module. + + + System.Management.Automation.SwitchParameter + + + False + + + RootModule - Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + Specifies the primary or root file of the module. Enter the file name of a script (`.ps1`), a script module (`.psm1`), a module manifest (`.psd1`), an assembly (`.dll`), or a cmdlet definition XML file (`.cdxml`). When the module is imported, the members exported from the root module are imported into the caller's session state. + If a module has a manifest file and no file is specified in the RootModule key, the manifest becomes the primary file for the module. The module is known as a manifest module ( ModuleType = `Manifest`). + To export members from `.psm1` or `.dll` files, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. System.String @@ -3883,35 +4870,35 @@ PS C:\> Get-PSResourceRepository None - HelpInfoUri + ScriptsToProcess - Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. - The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. - For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + Specifies script (`.ps1`) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + To specify scripts that run in the module's session state, use the NestedModules key. - Uri + System.String[] - Uri + System.String[] None - DefaultCommandPrefix + Tags - Specifies the default command prefix. + Specifies an array of tags. - System.String + System.String[] - System.String + System.String[] None - ExternalModuleDependencies + TypesToProcess - Specifies an array of external module dependencies. + Specifies the type files (`.ps1xml`) that run when the module is imported. + When you import the module, PowerShell runs the `Update-TypeData` cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. System.String[] @@ -3920,65 +4907,66 @@ PS C:\> Get-PSResourceRepository None - - RequireLicenseAcceptance + + VariablesToExport - Specifies that a license acceptance is required for the module. + Specifies the variables that the module exports. Wildcards are permitted. + Use this parameter to restrict which variables that are exported by the module. + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None - - Path + + AliasesToExport - Specifies the path and file name of the module manifest. Enter a path and file name with a .psd1 file name extension, such as `"$PSHOME\Modules\MyModule\MyModule.psd1`. + Specifies the aliases that the module exports. Wildcards are permitted. - String + System.String[] - String + System.String[] None - NestedModules + Author - Specifies script modules (.psm1) and binary modules (.dll) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed in the value. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. + Specifies the module author. - Object[] + System.String - Object[] + System.String None - Guid + ClrVersion - Specifies a unique identifier for the module. The GUID can be used to distinguish among modules with the same name. + Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework required by the module. - System.Guid + System.Version - System.Guid + System.Version None - - Author + + CmdletsToExport - Specifies the module author. + Specifies the cmdlets that the module exports. Wildcards are permitted. - String + System.String[] - String + System.String[] None @@ -3988,31 +4976,29 @@ PS C:\> Get-PSResourceRepository Specifies the company or vendor who created the module. - String + System.String - String + System.String None - Copyright + CompatiblePSEditions - Specifies a copyright statement for the module. + Specifies the compatible PSEditions of the module. For information about PSEdition , see Modules with compatible PowerShell Editions (/powershell/scripting/gallery/concepts/module-psedition-support). - String + System.String[] - String + System.String[] None - RootModule + Copyright - Specifies the primary or root file of the module. Enter the file name of a script (.ps1), a script module (.psm1), a module manifest (.psd1), an assembly (.dll), a cmdlet definition XML file (.cdxml), or a workflow (.xaml). When the module is imported, the members that are exported from the root module file are imported into the caller's session state. - If a module has a manifest file and no root file has been specified in the RootModule key, the manifest becomes the primary file for the module. And, the module becomes a manifest module (ModuleType = Manifest). - To export members from .psm1 or .dll files in a module that has a manifest, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. Otherwise, their members aren't exported. + Specifies a copyright statement for the module. System.String @@ -4022,13 +5008,13 @@ PS C:\> Get-PSResourceRepository None - ModuleVersion + DefaultCommandPrefix - Specifies the version of the module. + Specifies the default command prefix. - System.Version + System.String - System.Version + System.String None @@ -4046,28 +5032,21 @@ PS C:\> Get-PSResourceRepository None - ProcessorArchitecture + DotNetFrameworkVersion - Specifies the processor architecture that the module requires. - The acceptable values for this parameter are: - * Amd64 - * Arm - * IA64 - * MSIL - * None (unknown or unspecified) - * X86 + Specifies the minimum version of the Microsoft .NET Framework required by the module. - System.Reflection.ProcessorArchitecture + System.Version - System.Reflection.ProcessorArchitecture + System.Version None - - CompatiblePSEditions + + DscResourcesToExport - Specifies the compatible PSEditions of the module. For information about PSEdition, see: https://docs.microsoft.com/en-us/powershell/scripting/gallery/concepts/module-psedition-support + Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. System.String[] @@ -4077,296 +5056,315 @@ PS C:\> Get-PSResourceRepository None - PowerShellVersion + ExternalModuleDependencies - Specifies the minimum version of PowerShell that will work with this module. For example, you can specify 3.0, 4.0, or 5.0 as the value of this parameter. + Specifies an array of external module dependencies. - System.Version + System.String[] - System.Version + System.String[] None - ClrVersion + FileList - Specifies the minimum version of the Common Language Runtime (CLR) of the Microsoft .NET Framework that the module requires. + Specifies all items that are included in the module. - System.Version + System.String[] - System.Version + System.String[] None - DotNetFrameworkVersion + FormatsToProcess - Specifies the minimum version of the Microsoft .NET Framework that the module requires. + Specifies the formatting files (`.ps1xml`) that are processed when the module is imported. + When you import a module, PowerShell runs the `Update-FormatData` cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. - System.Version + System.String[] - System.Version + System.String[] None - - PowerShellHostName + + FunctionsToExport - Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. - To find the name of a host program, in the program, type $Host.Name. + Specifies the functions that the module exports. Wildcards are permitted. - System.String + System.String[] - System.String + System.String[] None - PowerShellHostVersion + Guid - Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. + Specifies a unique identifier for the module. The GUID is used to distinguish between modules with the same name. - System.Version + System.Guid - System.Version + System.Guid None - RequiredModules + HelpInfoUri - Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the Import-Module command fails. + Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with `http:` or `https:`. + For more information, see Updatable Help (/powershell/module/microsoft.powershell.core/about/about_updatable_help). - System.Object[] + System.Uri - System.Object[] + System.Uri None - TypesToProcess + IconUri - Specifies the type files (.ps1xml) that run when the module is imported. - When you import the module, PowerShell runs the Update-TypeData cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. + Specifies the URI of an icon for the module. The specified icon is displayed on the gallery web page for the module. - System.String[] + System.Uri - System.String[] + System.Uri None - FormatsToProcess + LicenseUri - Specifies the formatting files (.ps1xml) that run when the module is imported. - When you import a module, PowerShell runs the Update-FormatData cmdlet with the specified files. Because formatting files aren't scoped, they affect all session states in the session. + Specifies the URL of licensing terms for the module. - System.String[] + System.Uri - System.String[] + System.Uri None - ScriptsToProcess + ModuleList - Specifies script (.ps1) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. - To specify scripts that run in the module's session state, use the NestedModules key. + Specifies an array of modules that are included in the module. + Enter each module name as a string or as a hashtable with ModuleName and ModuleVersion keys. The hashtable can also have an optional GUID key. You can combine strings and hashtables in the parameter value. + This key is designed to act as a module inventory. - System.String[] + System.Object[] - System.String[] + System.Object[] None - RequiredAssemblies + ModuleVersion - Specifies the assembly (.dll) files that the module requires. Enter the assembly file names. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file that is specified in the value of the RootModule key. - Use this parameter to specify all the assemblies that the module requires, including assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed as binary modules in the NestedModules key. + Specifies the version of the module. - System.String[] + System.Version - System.String[] + System.Version None - FileList + NestedModules - Specifies all items that are included in the module. + Specifies script modules (`.psm1`) and binary modules (`.dll`) that are imported into the module's session state. The files in the NestedModules key run in the order in which they're listed. + Enter each module name as a string or as a hashtable with ModuleName and ModuleVersion keys. The hashtable can also have an optional GUID key. You can combine strings and hashtables in the parameter value. - System.String[] + System.Object[] - System.String[] + System.Object[] None - ModuleList + PassThru - Specifies an array of modules that are included in the module. - Enter each module name as a string or as a hash table with ModuleName and ModuleVersion keys. The hash table can also have an optional GUID key. You can combine strings and hash tables in the parameter value. - This key is designed to act as a module inventory. The modules that are listed in the value of this key aren't automatically processed. + - System.String[] + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter + + + False + + + Path + + Specifies the path and filename of the module manifest. Enter filename with a `.psd1` file extension. + + System.String + + System.String None - - FunctionsToExport + + PowerShellHostName - Specifies the functions that the module exports. Wildcards are permitted. - Use this parameter to restrict the functions that are exported by the module. FunctionsToExport can remove functions from the list of exported aliases, but it can't add functions to the list. + Specifies the name of the PowerShell host program that the module requires. Enter the name of the host program, such as PowerShell ISE Host or ConsoleHost. Wildcards aren't permitted. + The name of a host program is stored in `$Host.Name`. - System.String[] + System.String - System.String[] + System.String None - - AliasesToExport + + PowerShellHostVersion - Specifies the aliases that the module exports. Wildcards are permitted. - Use this parameter to restrict the aliases that are exported by the module. AliasesToExport can remove aliases from the list of exported aliases, but it can't add aliases to the list. + Specifies the minimum version of the PowerShell host program that works with the module. Enter a version number, such as 1.1. - System.String[] + System.Version - System.String[] + System.Version None - - VariablesToExport + + PowerShellVersion - Specifies the variables that the module exports. Wildcards are permitted. - Use this parameter to restrict the variables that are exported by the module. VariablesToExport can remove variables from the list of exported variables, but it can't add variables to the list. + Specifies the minimum version of PowerShell that works with this module. For example, you can specify versions such as `5.1` or `7.2`. - System.String[] + System.Version - System.String[] + System.Version None - - CmdletsToExport + + Prerelease - Specifies the cmdlets that the module exports. Wildcards are permitted. - Use this parameter to restrict the cmdlets that are exported by the module. CmdletsToExport can remove cmdlets from the list of exported cmdlets, but it can't add cmdlets to the list. + Specifies the prerelease value that is appended to the module version. For example, if Prerelease is `preview` and the ModuleVersion is `1.0.0`, the version of the module is `1.0.0-preview`. - System.String[] + System.String - System.String[] + System.String None - - DscResourcesToExport + + PrivateData - Specifies the Desired State Configuration (DSC) resources that the module exports. Wildcards are permitted. + Specifies data that is passed to the module when it's imported. This can be any arbitrary values stored in a hashtable. - System.String[] + System.Collections.Hashtable - System.String[] + System.Collections.Hashtable None - PrivateData + ProcessorArchitecture - Specifies data that is passed to the module when it's imported. + Specifies the processor architecture that the module requires. + The acceptable values for this parameter are: + - `Amd64` + - `Arm` + - `IA64` + - `MSIL` + - `None` (unknown or unspecified) + - `X86` - Hashtable + System.Reflection.ProcessorArchitecture - Hashtable + System.Reflection.ProcessorArchitecture None - Tags + ProjectUri - Specifies an array of tags. + Specifies the URI of a web page about this project. - System.String[] + System.Uri - System.String[] + System.Uri None - ProjectUri + ReleaseNotes - Specifies the URL of a web page about this project. + Specifies a string that contains release notes or comments for the module. - Uri + System.String - Uri + System.String None - LicenseUri + RequiredAssemblies - Specifies the URL of licensing terms for the module. + Specifies the assembly (`.dll`) files required by the module. PowerShell loads the specified assemblies before updating types or formats, importing nested modules, or importing the module file specified in the RootModule key. + Use RequiredAssemblies for assemblies that must be loaded to update any formatting or type files that are listed in the FormatsToProcess or TypesToProcess keys, even if those assemblies are also listed in the NestedModules key. - Uri + System.String[] - Uri + System.String[] None - IconUri + RequiredModules - Specifies the URL of an icon for the module. The specified icon is displayed on the gallery web page for the module. + Specifies modules that must be in the global session state. If the required modules aren't in the global session state, PowerShell imports them. If the required modules aren't available, the `Import-Module` command fails. + The value can be an array containing module names or module specifications. A module specification is a hashtable that has the following keys. + - `ModuleName` - Required Specifies the module name. - `GUID` - Optional Specifies the GUID of the module. - It's also Required to specify at least one of the three below keys. - `ModuleVersion` - Specifies a minimum acceptable version of the module. - `MaximumVersion` - Specifies the maximum acceptable version of the module. - `RequiredVersion` - Specifies an exact, required version of the module. This can't be used with the other Version keys. - Uri + System.Object[] - Uri + System.Object[] None - ReleaseNotes + RequireLicenseAcceptance - Specifies a string array that contains release notes or comments that you want available for this version of the script. + Specifies that a license acceptance is required for the module. - System.String[] + System.Management.Automation.SwitchParameter - System.String[] + System.Management.Automation.SwitchParameter - None + False - Prerelease + RootModule - Specifies the prerelease tag that is appended to the module version. For example, if prerelease is "preview" and the module version is "1.0.0" the version of the module would be "1.0.0-preview". + Specifies the primary or root file of the module. Enter the file name of a script (`.ps1`), a script module (`.psm1`), a module manifest (`.psd1`), an assembly (`.dll`), or a cmdlet definition XML file (`.cdxml`). When the module is imported, the members exported from the root module are imported into the caller's session state. + If a module has a manifest file and no file is specified in the RootModule key, the manifest becomes the primary file for the module. The module is known as a manifest module ( ModuleType = `Manifest`). + To export members from `.psm1` or `.dll` files, the names of those files must be specified in the values of the RootModule or NestedModules keys in the manifest. System.String @@ -4376,35 +5374,35 @@ PS C:\> Get-PSResourceRepository None - HelpInfoUri + ScriptsToProcess - Specifies the internet address of the module's HelpInfo XML file. Enter a Uniform Resource Identifier (URI) that begins with http or https. - The HelpInfo XML file supports the Updatable Help feature that was introduced in PowerShell version 3.0. It contains information about the location of the module's downloadable help files and the version numbers of the newest help files for each supported locale. - For information about Updatable Help, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_updatable_help?view=powershell-7.2. For information about the HelpInfo XML file, see: https://docs.microsoft.com/en-us/powershell/scripting/developer/module/supporting-updatable-help. + Specifies script (`.ps1`) files that run in the caller's session state when the module is imported. You can use these scripts to prepare an environment, just as you might use a login script. + To specify scripts that run in the module's session state, use the NestedModules key. - Uri + System.String[] - Uri + System.String[] None - DefaultCommandPrefix + Tags - Specifies the default command prefix. + Specifies an array of tags. - System.String + System.String[] - System.String + System.String[] None - ExternalModuleDependencies + TypesToProcess - Specifies an array of external module dependencies. + Specifies the type files (`.ps1xml`) that run when the module is imported. + When you import the module, PowerShell runs the `Update-TypeData` cmdlet with the specified files. Because type files aren't scoped, they affect all session states in the session. System.String[] @@ -4413,17 +5411,18 @@ PS C:\> Get-PSResourceRepository None - - RequireLicenseAcceptance + + VariablesToExport - Specifies that a license acceptance is required for the module. + Specifies the variables that the module exports. Wildcards are permitted. + Use this parameter to restrict which variables that are exported by the module. - System.Management.Automation.SwitchParameter + System.String[] - System.Management.Automation.SwitchParameter + System.String[] - False + None @@ -4439,33 +5438,38 @@ PS C:\> Get-PSResourceRepository - ## RELATED LINKS + For a full description of the module manifest file, see about_Module_Manifests (/powershell/module/microsoft.powershell.core/about/about_module_manifests). -------------------------- Example 1 -------------------------- - PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" + Update-ModuleManifest -Path "C:\MyModules\TestModule" -Author "New Author" - In this example the author property in the module manifest will be updated to "New Author". + -------------------------- Example 2 -------------------------- - PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" + Update-ModuleManifest -Path "C:\MyModules\TestModule" -Prerelease "beta2" - In this example the prerelease property will be updated to "beta2" + -------------------------- Example 3 -------------------------- - PS C:\> Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." + Update-ModuleManifest -Path "C:\MyModules\TestModule" -Tags "Windows", "Linux" -Description "A module for managing packages." - In this example the tags and description will be updated to the passed in values. + - + + + New-ModuleManifest + + + @@ -4473,19 +5477,20 @@ PS C:\> Get-PSResourceRepository Update PSResource - Updates a package already installed on the user's machine. + Downloads and installs the newest version of a package already installed on the local machine. - The Update-PSResource cmdlet replaces the Update-Module and Update-Script cmdlets from V2. It updates an already installed package based on the `-Name` parameter argument. It does not return an object. Other parameters allow the package to be updated to be further filtered. + `Update-PSResource` downloads and installs the newest version of a package already installed on the local machine. This cmdlet replaces the `Update-Module` and `Update-Script` cmdlets from PowerShellGet v2. The new version of the resource is installed side-by-side with previous versions in a new versioned folder. + By default, `Update-PSResource` installs the latest version of the package and any of its dependencies without deleting the older versions installed. Update-PSResource - + Name - Specifies name of a resource or resources to update. + Specifies the name of one or more resources to update. Wildcards are supported but NuGet only accepts the `*` character. NuGet does not support wildcard searches of local (file-based) repositories. System.String[] @@ -4505,10 +5510,21 @@ PS C:\> Get-PSResourceRepository False + + AuthenticodeCheck + + Validates signed files and catalog files on Windows. + + + System.Management.Automation.SwitchParameter + + + False + Credential - Specifies optional credentials to be used when accessing a private repository. + Specifies optional credentials used when accessing a private repository. System.Management.Automation.PSCredential @@ -4518,9 +5534,9 @@ PS C:\> Get-PSResourceRepository None - Prerelease + Force - When specified, allows updating to a prerelease version. + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. System.Management.Automation.SwitchParameter @@ -4529,9 +5545,9 @@ PS C:\> Get-PSResourceRepository False - Quiet + PassThru - Supresses progress information. + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -4540,37 +5556,32 @@ PS C:\> Get-PSResourceRepository False - Repository + TemporaryPath - Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + Specifies the path to temporarily install the resource before actual installatoin. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. - System.String[] + System.String - System.String[] + System.String None - Scope + Prerelease - Specifies the scope of the resource to update. + When specified, allows updating to a prerelease version. - - CurrentUser - AllUsers - - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - None + False - TrustRepository + Quiet - Specifies optional credentials to be used when accessing a private repository. + Supresses progress information. System.Management.Automation.SwitchParameter @@ -4578,34 +5589,44 @@ PS C:\> Get-PSResourceRepository False - - Version + + Repository - Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. - System.String + System.String[] - System.String + System.String[] None - Force + Scope - When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation. + + CurrentUser + AllUsers + + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - PassThru + SkipDependencyCheck - Passes the resource updated to the console. + Skips the check for resource dependencies. This means that only named resources are updated. System.Management.Automation.SwitchParameter @@ -4614,9 +5635,9 @@ PS C:\> Get-PSResourceRepository False - AuthenticodeCheck + TrustRepository - Does a check to to validate signed files and catalog files on Windows. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -4625,15 +5646,18 @@ PS C:\> Get-PSResourceRepository False - SkipdependencyCheck + Version - Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. + System.String - System.Management.Automation.SwitchParameter + System.String - False + None Confirm @@ -4649,7 +5673,7 @@ PS C:\> Get-PSResourceRepository WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -4673,33 +5697,33 @@ PS C:\> Get-PSResourceRepository False - Credential + AuthenticodeCheck - Specifies optional credentials to be used when accessing a private repository. + Validates signed files and catalog files on Windows. - System.Management.Automation.PSCredential + System.Management.Automation.SwitchParameter - System.Management.Automation.PSCredential + System.Management.Automation.SwitchParameter - None + False - - Name + + Credential - Specifies name of a resource or resources to update. + Specifies optional credentials used when accessing a private repository. - System.String[] + System.Management.Automation.PSCredential - System.String[] + System.Management.Automation.PSCredential - "*" + None - Prerelease + Force - When specified, allows updating to a prerelease version. + When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. System.Management.Automation.SwitchParameter @@ -4708,10 +5732,22 @@ PS C:\> Get-PSResourceRepository False + + Name + + Specifies the name of one or more resources to update. Wildcards are supported but NuGet only accepts the `*` character. NuGet does not support wildcard searches of local (file-based) repositories. + + System.String[] + + System.String[] + + + "*" + - Quiet + PassThru - Supresses progress information. + When specified, outputs a PSResourceInfo object for the saved resource. System.Management.Automation.SwitchParameter @@ -4721,33 +5757,33 @@ PS C:\> Get-PSResourceRepository False - Repository + TemporaryPath - Specifies one or more repository names to update packages from. If not specified, search for packages to update will include all currently registered repositories in order of highest priority. + Specifies the path to temporarily install the resource before actual installatoin. If no temporary path is provided, the resource is temporarily installed in the current user's temporary folder. - System.String[] + System.String - System.String[] + System.String None - Scope + Prerelease - Specifies the scope of the resource to update. + When specified, allows updating to a prerelease version. - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType + System.Management.Automation.SwitchParameter - None + False - TrustRepository + Quiet - Specifies optional credentials to be used when accessing a private repository. + Supresses progress information. System.Management.Automation.SwitchParameter @@ -4756,35 +5792,40 @@ PS C:\> Get-PSResourceRepository False - - Version + + Repository - Specifies the version of the resource to be updated to. The value can be an exact version or a version range using the NuGet versioning syntax. - For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges)PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. So inputting "1.0.0.0" as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the values is considered as the required version and yields version 1.0.0.0 only (required version). To use the minimum inclusive range, provide `[1.0.0.0, ]` as the version range. + Specifies one or more repository names to search. Wildcards are supported. + If not specified, search includes all registered repositories, in priority order (highest first), until a repository is found that contains the package. + Lower Priority values have a higher precedence. - System.String + System.String[] - System.String + System.String[] None - Force + Scope - When specified, bypasses checks for TrustRepository and AcceptLicense and updates the package. + Specifies the installation scope. Accepted values are: + - `CurrentUser` + - `AllUsers` + + The default scope is `CurrentUser`, which doesn't require elevation. - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - System.Management.Automation.SwitchParameter + Microsoft.PowerShell.PowerShellGet.UtilClasses.ScopeType - False + None - PassThru + SkipDependencyCheck - Passes the resource updated to the console. + Skips the check for resource dependencies. This means that only named resources are updated. System.Management.Automation.SwitchParameter @@ -4794,9 +5835,9 @@ PS C:\> Get-PSResourceRepository False - AuthenticodeCheck + TrustRepository - Does a check to to validate signed files and catalog files on Windows. + Suppress prompts to trust repository. The prompt to trust repository only occurs if the repository isn't configured as trusted. System.Management.Automation.SwitchParameter @@ -4806,16 +5847,18 @@ PS C:\> Get-PSResourceRepository False - SkipdependencyCheck + Version - Skips the check for resource dependencies, so that only found resources are updated, and not any resources the found resource depends on. + Specifies the version of the resource to be returned. The value can be an exact version or a version range using the NuGet versioning syntax. + For more information about NuGet version ranges, see Package versioning (/nuget/concepts/package-versioning#version-ranges). + PowerShellGet supports all but the minimum inclusive version listed in the NuGet version range documentation. Using `1.0.0.0` as the version doesn't yield versions 1.0.0.0 and higher (minimum inclusive range). Instead, the value is considered to be the required version. To search for a minimum inclusive range, use `[1.0.0.0, ]` as the version range. - System.Management.Automation.SwitchParameter + System.String - System.Management.Automation.SwitchParameter + System.String - False + None Confirm @@ -4832,7 +5875,7 @@ PS C:\> Get-PSResourceRepository WhatIf - Shows what would happen if the cmdlet runs. The cmdlet is not run. + Shows what would happen if the cmdlet runs. The cmdlet isn't run. System.Management.Automation.SwitchParameter @@ -4852,7 +5895,16 @@ PS C:\> Get-PSResourceRepository - + + + + Microsoft.PowerShell.PowerShellGet.UtilClasses.PSResourceInfo + + + By default, the cmdlet doesn't return any objects. When the PassThru parameter is used, the cmdlet outputs a PSResourceInfo object for the saved resource. + + + @@ -4861,26 +5913,26 @@ PS C:\> Get-PSResourceRepository -------------------------- Example 1 -------------------------- - PS C:\> Update-PSResource -Name "TestModule" - Name Version Prerelease Description - ---- ------- ---------- ----------- - TestModule 1.2.0 test + Get-PSResource -Name "TestModule" -PS C:\> Update-PSResource -Name "TestModule" +Name Version Prerelease Description +---- ------- ---------- ----------- +TestModule 1.2.0 test -PS C:\> Update-PSResource -Name "TestModule" - Name Version Prerelease Description - ---- ------- ---------- ----------- - TestModule 1.3.0 test - TestModule 1.2.0 test +Update-PSResource -Name "TestModule" + +Name Version Prerelease Description +---- ------- ---------- ----------- +TestModule 1.3.0 test +TestModule 1.2.0 test - In this example, the user already has the TestModule package installed and they update the package. Update-PSResource will install the latest version of the package without deleting the older version installed. + - <add> + Install-PSResource From 5412c5bc4685767abde08d25c4502e2523a4d806 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 1 Sep 2022 11:50:29 -0400 Subject: [PATCH 272/276] replace exposed hardcoded test secrets with random one (#785) --- test/PSCredentialInfo.Tests.ps1 | 56 +++++++++++++-------- test/RegisterPSResourceRepository.Tests.ps1 | 19 ++++--- test/SetPSResourceRepository.Tests.ps1 | 15 +++--- 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/test/PSCredentialInfo.Tests.ps1 b/test/PSCredentialInfo.Tests.ps1 index 5ae827ddb..8bdcb8daf 100644 --- a/test/PSCredentialInfo.Tests.ps1 +++ b/test/PSCredentialInfo.Tests.ps1 @@ -6,7 +6,8 @@ Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force Describe "Create PSCredentialInfo with VaultName and SecretName" -tags 'CI' { It "Verifies VaultName is not empty" { - { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("", "testsecret") } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" + $randomSecret = [System.IO.Path]::GetRandomFileName() + { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("", $randomSecret) } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" } It "Verifies SecretName is not empty" { @@ -14,27 +15,30 @@ Describe "Create PSCredentialInfo with VaultName and SecretName" -tags 'CI' { } It "Creates PSCredentialInfo successfully if VaultName and SecretName are non-empty" { - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") + $randomSecret = [System.IO.Path]::GetRandomFileName() + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret) $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.SecretName | Should -Be $randomSecret } } Describe "Create PSCredentialInfo with VaultName, SecretName, and Credential" -tags 'CI' { It "Creates PSCredentialInfo successfully if Credential is null" { - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") + $randomSecret = [System.IO.Path]::GetRandomFileName() + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret) $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.SecretName | Should -Be $randomSecret } It "Creates PSCredentialInfo successfully if Credential is non-null and of type PSCredential" { + $randomSecret = [System.IO.Path]::GetRandomFileName() $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString "password" -AsPlainText -Force)) - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $credential) + $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret, $credential) $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.SecretName | Should -Be $randomSecret } } @@ -52,59 +56,69 @@ Describe "Create PSCredentialInfo from a PSObject" -tags 'CI' { } It "Creates PSCredentialInfo successfully from PSObject with VaultName and SecretName" { + $randomSecret = [System.IO.Path]::GetRandomFileName() $properties = [PSCustomObject]@{ VaultName = "testvault" - SecretName = "testsecret" + SecretName = $randomSecret } $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.SecretName | Should -Be $randomSecret } It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and PSCredential Credential" { - $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString "password" -AsPlainText -Force)) + $randomSecret = [System.IO.Path]::GetRandomFileName() + $randomPassword = [System.IO.Path]::GetRandomFileName() + + $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString $randomPassword -AsPlainText -Force)) $properties = [PSCustomObject]@{ VaultName = "testvault" - SecretName = "testsecret" + SecretName = $randomSecret Credential = [PSCredential] $credential } $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" + $credentialInfo.SecretName | Should -Be $randomSecret $credentialInfo.Credential.UserName | Should -Be "username" - $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" + $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be $randomPassword } It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and string Credential" { + $randomSecret = [System.IO.Path]::GetRandomFileName() + $randomPassword = [System.IO.Path]::GetRandomFileName() + $properties = [PSCustomObject]@{ VaultName = "testvault" - SecretName = "testsecret" - Credential = "password" + SecretName = $randomSecret + Credential = $randomPassword } $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" - $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" + $credentialInfo.SecretName | Should -Be $randomSecret + $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be $randomPassword } It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and SecureString Credential" { - $secureString = ConvertTo-SecureString "password" -AsPlainText -Force + $randomSecret = [System.IO.Path]::GetRandomFileName() + $randomPassword = [System.IO.Path]::GetRandomFileName() + + $secureString = ConvertTo-SecureString $randomPassword -AsPlainText -Force $properties = [PSCustomObject]@{ VaultName = "testvault" - SecretName = "testsecret" + SecretName = $randomSecret Credential = $secureString } $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be "testsecret" - $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be "password" + $credentialInfo.SecretName | Should -Be $randomSecret + $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be $randomPassword } } diff --git a/test/RegisterPSResourceRepository.Tests.ps1 b/test/RegisterPSResourceRepository.Tests.ps1 index 4853495ac..e28817bd3 100644 --- a/test/RegisterPSResourceRepository.Tests.ps1 +++ b/test/RegisterPSResourceRepository.Tests.ps1 @@ -22,10 +22,13 @@ Describe "Test Register-PSResourceRepository" { $relativeCurrentPath = Get-Location - $credentialInfo1 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") - $secureString = ConvertTo-SecureString "testpassword" -AsPlainText -Force + $randomSecret = [System.IO.Path]::GetRandomFileName() + $randomPassword = [System.IO.Path]::GetRandomFileName() + + $credentialInfo1 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret) + $secureString = ConvertTo-SecureString $randomPassword -AsPlainText -Force $credential = New-Object pscredential ("testusername", $secureString) - $credentialInfo2 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $credential) + $credentialInfo2 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret, $credential) } AfterEach { Get-RevertPSResourceRepositoryFile @@ -68,7 +71,7 @@ Describe "Test Register-PSResourceRepository" { $res.Trusted | Should -Be True $res.Priority | Should -Be 20 $res.CredentialInfo.VaultName | Should -Be "testvault" - $res.CredentialInfo.SecretName | Should -Be "testsecret" + $res.CredentialInfo.SecretName | Should -Be $randomSecret } It "register repository with PSGallery parameter (PSGalleryParameterSet)" { @@ -102,7 +105,7 @@ Describe "Test Register-PSResourceRepository" { $hashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} $hashtable2 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} $hashtable3 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} - $hashtable4 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} + $hashtable4 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret))} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 Register-PSResourceRepository -Repository $arrayOfHashtables @@ -126,7 +129,7 @@ Describe "Test Register-PSResourceRepository" { $res4.Trusted | Should -Be True $res4.Priority | Should -Be 30 $res4.CredentialInfo.VaultName | Should -Be "testvault" - $res4.CredentialInfo.SecretName | Should -Be "testsecret" + $res4.CredentialInfo.SecretName | Should -Be $randomSecret $res4.CredentialInfo.Credential | Should -BeNullOrEmpty } @@ -146,7 +149,7 @@ Describe "Test Register-PSResourceRepository" { $hashtable2 = @{Name = $TestRepoName1; Uri = $tmpDir1Path} $hashtable3 = @{Name = $TestRepoName2; Uri = $tmpDir2Path; Trusted = $True} $hashtable4 = @{Name = $TestRepoName3; Uri = $tmpDir3Path; Trusted = $True; Priority = 20} - $hashtable5 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret"))} + $hashtable5 = @{Name = $TestRepoName4; Uri = $tmpDir4Path; Trusted = $True; Priority = 30; CredentialInfo = (New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret))} $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4, $hashtable5 Register-PSResourceRepository -Repository $arrayOfHashtables @@ -176,7 +179,7 @@ Describe "Test Register-PSResourceRepository" { $res5.Trusted | Should -Be True $res5.Priority | Should -Be 30 $res5.CredentialInfo.VaultName | Should -Be "testvault" - $res5.CredentialInfo.SecretName | Should -Be "testsecret" + $res5.CredentialInfo.SecretName | Should -Be $randomSecret $res5.CredentialInfo.Credential | Should -BeNullOrEmpty } diff --git a/test/SetPSResourceRepository.Tests.ps1 b/test/SetPSResourceRepository.Tests.ps1 index 17b413849..99928fd28 100644 --- a/test/SetPSResourceRepository.Tests.ps1 +++ b/test/SetPSResourceRepository.Tests.ps1 @@ -21,10 +21,13 @@ Describe "Test Set-PSResourceRepository" { $relativeCurrentPath = Get-Location - $credentialInfo1 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret") - $secureString = ConvertTo-SecureString "testpassword" -AsPlainText -Force + $randomSecret = [System.IO.Path]::GetRandomFileName() + $randomPassword = [System.IO.Path]::GetRandomFileName() + + $credentialInfo1 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret) + $secureString = ConvertTo-SecureString $randomPassword -AsPlainText -Force $credential = New-Object pscredential ("testusername", $secureString) - $credentialInfo2 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "testsecret", $credential) + $credentialInfo2 = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret, $credential) } AfterEach { Get-RevertPSResourceRepositoryFile @@ -89,7 +92,7 @@ Describe "Test Set-PSResourceRepository" { $res.Priority | Should -Be 50 $res.Trusted | Should -Be False $res.CredentialInfo.VaultName | Should -Be "testvault" - $res.CredentialInfo.SecretName | Should -Be "testsecret" + $res.CredentialInfo.SecretName | Should -Be $randomSecret $res.CredentialInfo.Credential | Should -BeNullOrEmpty } @@ -145,7 +148,7 @@ Describe "Test Set-PSResourceRepository" { $hashtable1 = @{Name = $TestRepoName1; Uri = $tmpDir2Path}; $hashtable2 = @{Name = $TestRepoName2; Priority = 25}; - $hashtable3 = @{Name = $TestRepoName3; CredentialInfo = [PSCustomObject] @{ VaultName = "testvault"; SecretName = "testsecret" }}; + $hashtable3 = @{Name = $TestRepoName3; CredentialInfo = [PSCustomObject] @{ VaultName = "testvault"; SecretName = $randomSecret }}; $hashtable4 = @{Name = $PSGalleryName; Trusted = $True}; $arrayOfHashtables = $hashtable1, $hashtable2, $hashtable3, $hashtable4 @@ -170,7 +173,7 @@ Describe "Test Set-PSResourceRepository" { $res3.Priority | Should -Be 50 $res3.Trusted | Should -Be False $res3.CredentialInfo.VaultName | Should -Be "testvault" - $res3.CredentialInfo.SecretName | Should -Be "testsecret" + $res3.CredentialInfo.SecretName | Should -Be $randomSecret $res3.CredentialInfo.Credential | Should -BeNullOrEmpty $res4 = Get-PSResourceRepository -Name $PSGalleryName From 1ef484f9c97f26fa591147ab40a073b2359f82da Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 1 Sep 2022 09:10:06 -0700 Subject: [PATCH 273/276] Missed one case of hardcoded test passwd. (#786) --- test/PSCredentialInfo.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/PSCredentialInfo.Tests.ps1 b/test/PSCredentialInfo.Tests.ps1 index 8bdcb8daf..20f121adb 100644 --- a/test/PSCredentialInfo.Tests.ps1 +++ b/test/PSCredentialInfo.Tests.ps1 @@ -34,7 +34,8 @@ Describe "Create PSCredentialInfo with VaultName, SecretName, and Credential" -t It "Creates PSCredentialInfo successfully if Credential is non-null and of type PSCredential" { $randomSecret = [System.IO.Path]::GetRandomFileName() - $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString "password" -AsPlainText -Force)) + $randomPassword = [System.IO.Path]::GetRandomFileName() + $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString $randomPassword -AsPlainText -Force)) $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret, $credential) $credentialInfo.VaultName | Should -Be "testvault" From d257425972e8e471796685f3dfa004757fb8dd5e Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 1 Sep 2022 09:38:54 -0700 Subject: [PATCH 274/276] Remove unneeded constructor tests (#787) --- test/PSCredentialInfo.Tests.ps1 | 81 --------------------------------- 1 file changed, 81 deletions(-) diff --git a/test/PSCredentialInfo.Tests.ps1 b/test/PSCredentialInfo.Tests.ps1 index 20f121adb..23d38c2c2 100644 --- a/test/PSCredentialInfo.Tests.ps1 +++ b/test/PSCredentialInfo.Tests.ps1 @@ -42,84 +42,3 @@ Describe "Create PSCredentialInfo with VaultName, SecretName, and Credential" -t $credentialInfo.SecretName | Should -Be $randomSecret } } - -Describe "Create PSCredentialInfo from a PSObject" -tags 'CI' { - - It "Throws if VaultName is null" { - $customObject = New-Object PSObject - { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo $customObject } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" - } - - It "Throws if SecretName is null" { - $customObject = New-Object PSObject - $customObject | Add-Member -Name "VaultName" -Value "testvault" -MemberType NoteProperty - { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo $customObject } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" - } - - It "Creates PSCredentialInfo successfully from PSObject with VaultName and SecretName" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $properties = [PSCustomObject]@{ - VaultName = "testvault" - SecretName = $randomSecret - } - - $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties - - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - } - - It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and PSCredential Credential" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $randomPassword = [System.IO.Path]::GetRandomFileName() - - $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString $randomPassword -AsPlainText -Force)) - $properties = [PSCustomObject]@{ - VaultName = "testvault" - SecretName = $randomSecret - Credential = [PSCredential] $credential - } - - $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties - - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - $credentialInfo.Credential.UserName | Should -Be "username" - $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be $randomPassword - } - - It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and string Credential" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $randomPassword = [System.IO.Path]::GetRandomFileName() - - $properties = [PSCustomObject]@{ - VaultName = "testvault" - SecretName = $randomSecret - Credential = $randomPassword - } - - $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties - - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be $randomPassword - } - - It "Creates PSCredentialInfo successfully from PSObject with VaultName, SecretName and SecureString Credential" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $randomPassword = [System.IO.Path]::GetRandomFileName() - - $secureString = ConvertTo-SecureString $randomPassword -AsPlainText -Force - $properties = [PSCustomObject]@{ - VaultName = "testvault" - SecretName = $randomSecret - Credential = $secureString - } - - $credentialInfo = [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] $properties - - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - $credentialInfo.Credential.GetNetworkCredential().Password | Should -Be $randomPassword - } -} From 24c637c0f474eef3d0f5e922b2d881f346faf62a Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 1 Sep 2022 09:59:33 -0700 Subject: [PATCH 275/276] Remove unneeded test. (#788) --- test/PSCredentialInfo.Tests.ps1 | 44 --------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 test/PSCredentialInfo.Tests.ps1 diff --git a/test/PSCredentialInfo.Tests.ps1 b/test/PSCredentialInfo.Tests.ps1 deleted file mode 100644 index 23d38c2c2..000000000 --- a/test/PSCredentialInfo.Tests.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module "$psscriptroot\PSGetTestUtils.psm1" -Force - -Describe "Create PSCredentialInfo with VaultName and SecretName" -tags 'CI' { - - It "Verifies VaultName is not empty" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("", $randomSecret) } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" - } - - It "Verifies SecretName is not empty" { - { New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", "") } | Should -Throw -ErrorId "ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand" - } - - It "Creates PSCredentialInfo successfully if VaultName and SecretName are non-empty" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret) - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - } -} - -Describe "Create PSCredentialInfo with VaultName, SecretName, and Credential" -tags 'CI' { - - It "Creates PSCredentialInfo successfully if Credential is null" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret) - - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - } - - It "Creates PSCredentialInfo successfully if Credential is non-null and of type PSCredential" { - $randomSecret = [System.IO.Path]::GetRandomFileName() - $randomPassword = [System.IO.Path]::GetRandomFileName() - $credential = New-Object System.Management.Automation.PSCredential ("username", (ConvertTo-SecureString $randomPassword -AsPlainText -Force)) - $credentialInfo = New-Object Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo ("testvault", $randomSecret, $credential) - - $credentialInfo.VaultName | Should -Be "testvault" - $credentialInfo.SecretName | Should -Be $randomSecret - } -} From 2311980453c4656ad4eff643bb0969a6ab83dde8 Mon Sep 17 00:00:00 2001 From: PaulHigin Date: Mon, 9 Jan 2023 14:48:57 -0800 Subject: [PATCH 276/276] Update PSGet module version --- .ci/ci_release.yml | 2 +- CHANGELOG.md | 6 ++++++ src/PowerShellGet.psd1 | 4 ++-- src/code/PowerShellGet.csproj | 6 +++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.ci/ci_release.yml b/.ci/ci_release.yml index 924de1a50..a1a534e1a 100644 --- a/.ci/ci_release.yml +++ b/.ci/ci_release.yml @@ -248,7 +248,7 @@ stages: BuildDropPath: $(signOutPath) Build_Repository_Uri: 'https://github.com/powershell/powershellget' PackageName: 'PowerShellGet' - PackageVersion: '3.0.17' + PackageVersion: '3.0.18' - pwsh: | $modulePath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'TempModules' diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ed819c6a..ca106741a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 3.0.18-beta18 + +### New Features + +### Bug Fixes + ## 3.0.17-beta17 ### New Features diff --git a/src/PowerShellGet.psd1 b/src/PowerShellGet.psd1 index 8db85c963..66cad0547 100644 --- a/src/PowerShellGet.psd1 +++ b/src/PowerShellGet.psd1 @@ -3,7 +3,7 @@ @{ RootModule = './netstandard2.0/PowerShellGet.dll' - ModuleVersion = '3.0.17' + ModuleVersion = '3.0.18' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -35,7 +35,7 @@ AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') PrivateData = @{ PSData = @{ - Prerelease = 'beta17' + Prerelease = 'beta18' Tags = @('PackageManagement', 'PSEdition_Desktop', 'PSEdition_Core', diff --git a/src/code/PowerShellGet.csproj b/src/code/PowerShellGet.csproj index 286cbc380..5daded60e 100644 --- a/src/code/PowerShellGet.csproj +++ b/src/code/PowerShellGet.csproj @@ -5,9 +5,9 @@ Library PowerShellGet PowerShellGet - 3.0.17.0 - 3.0.17 - 3.0.17 + 3.0.18.0 + 3.0.18 + 3.0.18 netstandard2.0 8.0