MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Globalization;9using System.IO;10using System.Linq;11using System.Management.Automation;12using System.Management.Automation.Internal;13using System.Reflection;14using System.Text;15using Dbg = System.Management.Automation.Diagnostics;16 17//18// Now define the set of commands for manipulating modules.19//20 21namespace Microsoft.PowerShell.Commands22{23 #region New-ModuleManifest24 /// <summary>25 /// Cmdlet to create a new module manifest file.26 /// </summary>27 [Cmdlet(VerbsCommon.New, "ModuleManifest", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low,28 HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096487")]29 [OutputType(typeof(string))]30 public sealed class NewModuleManifestCommand : PSCmdlet31 {32 /// <summary>33 /// Gets or sets the output path for the generated file.34 /// </summary>35 [Parameter(Mandatory = true, Position = 0)]36 public string Path37 {38 get { return _path; }39 40 set { _path = value; }41 }42 43 private string _path;44 45 /// <summary>46 /// Gets or sets the list of files to load by default.47 /// </summary>48 [Parameter]49 [AllowEmptyCollection]50 public object[] NestedModules51 {52 get { return _nestedModules; }53 54 set { _nestedModules = value; }55 }56 57 private object[] _nestedModules;58 59 /// <summary>60 /// Gets or sets the GUID in the manifest file.61 /// </summary>62 [Parameter]63 public Guid Guid64 {65 get { return _guid; }66 67 set { _guid = value; }68 }69 70 private Guid _guid = Guid.NewGuid();71 72 /// <summary>73 /// Gets or sets the author string in the manifest.74 /// </summary>75 [Parameter]76 [AllowEmptyString]77 public string Author78 {79 get { return _author; }80 81 set { _author = value; }82 }83 84 private string _author;85 86 /// <summary>87 /// Gets or sets the company name in the manifest.88 /// </summary>89 [Parameter]90 [AllowEmptyString]91 public string CompanyName92 {93 get { return _companyName; }94 95 set { _companyName = value; }96 }97 98 private string _companyName = string.Empty;99 100 /// <summary>101 /// Gets or sets the copyright string in the module manifest.102 /// </summary>103 [Parameter]104 [AllowEmptyString]105 public string Copyright106 {107 get { return _copyright; }108 109 set { _copyright = value; }110 }111 112 private string _copyright;113 114 /// <summary>115 /// Gets or sets the root module.116 /// </summary>117 [Parameter]118 [AllowEmptyString]119 [Alias("ModuleToProcess")]120 public string RootModule121 {122 get { return _rootModule; }123 124 set { _rootModule = value; }125 }126 127 private string _rootModule = null;128 129 /// <summary>130 /// Gets or sets the module version.131 /// </summary>132 [Parameter]133 [ValidateNotNull]134 public Version ModuleVersion135 {136 get { return _moduleVersion; }137 138 set { _moduleVersion = value; }139 }140 141 private Version _moduleVersion = new Version(0, 0, 1);142 143 /// <summary>144 /// Gets or sets the module description.145 /// </summary>146 [Parameter]147 [AllowEmptyString]148 public string Description149 {150 get { return _description; }151 152 set { _description = value; }153 }154 155 private string _description;156 157 /// <summary>158 /// Gets or sets the ProcessorArchitecture required by this module.159 /// </summary>160 [Parameter]161 public ProcessorArchitecture ProcessorArchitecture162 {163 get { return _processorArchitecture ?? ProcessorArchitecture.None; }164 165 set { _processorArchitecture = value; }166 }167 168 private ProcessorArchitecture? _processorArchitecture = null;169 170 /// <summary>171 /// Gets or sets the PowerShell version required by this module.172 /// </summary>173 [Parameter]174 public Version PowerShellVersion175 {176 get { return _powerShellVersion; }177 178 set { _powerShellVersion = value; }179 }180 181 private Version _powerShellVersion = null;182 183 /// <summary>184 /// Gets or sets the CLR version required by the module.185 /// </summary>186 [Parameter]187 public Version ClrVersion188 {189 get { return _ClrVersion; }190 191 set { _ClrVersion = value; }192 }193 194 private Version _ClrVersion = null;195 196 /// <summary>197 /// Gets or sets the version of .NET Framework required by the module.198 /// </summary>199 [Parameter]200 public Version DotNetFrameworkVersion201 {202 get { return _DotNetFrameworkVersion; }203 204 set { _DotNetFrameworkVersion = value; }205 }206 207 private Version _DotNetFrameworkVersion = null;208 209 /// <summary>210 /// Gets or sets the name of PowerShell host required by the module.211 /// </summary>212 [Parameter]213 public string PowerShellHostName214 {215 get { return _PowerShellHostName; }216 217 set { _PowerShellHostName = value; }218 }219 220 private string _PowerShellHostName = null;221 222 /// <summary>223 /// Gets or sets the version of PowerShell host required by the module.224 /// </summary>225 [Parameter]226 public Version PowerShellHostVersion227 {228 get { return _PowerShellHostVersion; }229 230 set { _PowerShellHostVersion = value; }231 }232 233 private Version _PowerShellHostVersion = null;234 235 /// <summary>236 /// Gets or sets the list of Dependencies for the module.237 /// </summary>238 [Parameter]239 [ArgumentTypeConverter(typeof(ModuleSpecification[]))]240 public object[] RequiredModules241 {242 get { return _requiredModules; }243 244 set { _requiredModules = value; }245 }246 247 private object[] _requiredModules;248 249 /// <summary>250 /// Gets or sets the list of types files for the module.251 /// </summary>252 [Parameter]253 [AllowEmptyCollection]254 public string[] TypesToProcess255 {256 get { return _types; }257 258 set { _types = value; }259 }260 261 private string[] _types;262 263 /// <summary>264 /// Gets or sets the list of formats files for the module.265 /// </summary>266 [Parameter]267 [AllowEmptyCollection]268 public string[] FormatsToProcess269 {270 get { return _formats; }271 272 set { _formats = value; }273 }274 275 private string[] _formats;276 277 /// <summary>278 /// Gets or sets the list of ps1 scripts to run in the session state of the import-module invocation.279 /// </summary>280 [Parameter]281 [AllowEmptyCollection]282 public string[] ScriptsToProcess283 {284 get { return _scripts; }285 286 set { _scripts = value; }287 }288 289 private string[] _scripts;290 291 /// <summary>292 /// Gets or sets the list of assemblies to load for this module.293 /// </summary>294 [Parameter]295 [AllowEmptyCollection]296 public string[] RequiredAssemblies297 {298 get { return _requiredAssemblies; }299 300 set { _requiredAssemblies = value; }301 }302 303 private string[] _requiredAssemblies;304 305 /// <summary>306 /// Gets or sets the additional files used by this module.307 /// </summary>308 [Parameter]309 [AllowEmptyCollection]310 public string[] FileList311 {312 get { return _miscFiles; }313 314 set { _miscFiles = value; }315 }316 317 private string[] _miscFiles;318 319 /// <summary>320 /// Gets or sets the list of other modules included with this module.321 /// Like the RequiredModules key, this list can be a simple list of module names or a complex list of module hashtables.322 /// </summary>323 [Parameter]324 [AllowEmptyCollection]325 [ArgumentTypeConverter(typeof(ModuleSpecification[]))]326 public object[] ModuleList327 {328 get { return _moduleList; }329 330 set { _moduleList = value; }331 }332 333 private object[] _moduleList;334 335 /// <summary>336 /// Gets or sets the functions to export from this manifest.337 /// </summary>338 [Parameter]339 [AllowEmptyCollection]340 public string[] FunctionsToExport341 {342 get { return _exportedFunctions; }343 344 set { _exportedFunctions = value; }345 }346 347 private string[] _exportedFunctions;348 349 /// <summary>350 /// Gets or sets the aliases to export from this manifest.351 /// </summary>352 [Parameter]353 [AllowEmptyCollection]354 public string[] AliasesToExport355 {356 get { return _exportedAliases; }357 358 set { _exportedAliases = value; }359 }360 361 private string[] _exportedAliases;362 363 /// <summary>364 /// Gets or sets the variables to export from this manifest.365 /// </summary>366 [Parameter]367 [AllowEmptyCollection]368 public string[] VariablesToExport369 {370 get { return _exportedVariables; }371 372 set { _exportedVariables = value; }373 }374 375 private string[] _exportedVariables = new string[] { "*" };376 377 /// <summary>378 /// Gets or sets the cmdlets to export from this manifest.379 /// </summary>380 [Parameter]381 [AllowEmptyCollection]382 public string[] CmdletsToExport383 {384 get { return _exportedCmdlets; }385 386 set { _exportedCmdlets = value; }387 }388 389 private string[] _exportedCmdlets;390 391 /// <summary>392 /// Gets or sets the dsc resources to export from this manifest.393 /// </summary>394 [Parameter]395 [AllowEmptyCollection]396 public string[] DscResourcesToExport397 {398 get { return _dscResourcesToExport; }399 400 set { _dscResourcesToExport = value; }401 }402 403 private string[] _dscResourcesToExport;404 405 /// <summary>406 /// Gets or sets the compatible PSEditions of this module.407 /// </summary>408 [Parameter]409 [AllowEmptyCollection]410 [ValidateSet("Desktop", "Core")]411 public string[] CompatiblePSEditions412 {413 get { return _compatiblePSEditions; }414 415 set { _compatiblePSEditions = value; }416 }417 418 private string[] _compatiblePSEditions;419 420 /// <summary>421 /// Gets or sets the module-specific private data here.422 /// </summary>423 [Parameter(Mandatory = false)]424 [AllowNull]425 public object PrivateData426 {427 get { return _privateData; }428 429 set { _privateData = value; }430 }431 432 private object _privateData;433 434 /// <summary>435 /// Gets or sets the Tags.436 /// </summary>437 [Parameter(Mandatory = false)]438 [ValidateNotNullOrEmpty]439 public string[] Tags { get; set; }440 441 /// <summary>442 /// Gets or sets the ProjectUri.443 /// </summary>444 [Parameter(Mandatory = false)]445 [ValidateNotNullOrEmpty]446 public Uri ProjectUri { get; set; }447 448 /// <summary>449 /// Gets or sets the LicenseUri.450 /// </summary>451 [Parameter(Mandatory = false)]452 [ValidateNotNullOrEmpty]453 public Uri LicenseUri { get; set; }454 455 /// <summary>456 /// Gets or sets the IconUri.457 /// </summary>458 [Parameter(Mandatory = false)]459 [ValidateNotNullOrEmpty]460 public Uri IconUri { get; set; }461 462 /// <summary>463 /// Gets or sets the ReleaseNotes.464 /// </summary>465 [Parameter(Mandatory = false)]466 [ValidateNotNullOrEmpty]467 public string ReleaseNotes { get; set; }468 469 /// <summary>470 /// Gets or sets whether or not the module is a prerelease.471 /// </summary>472 [Parameter]473 [ValidateNotNullOrEmpty]474 public string Prerelease { get; set; }475 476 /// <summary>477 /// Gets or sets whether or not the module requires explicit user acceptance for install/update/save.478 /// </summary>479 [Parameter]480 public SwitchParameter RequireLicenseAcceptance { get; set; }481 482 /// <summary>483 /// Gets or sets the external module dependencies.484 /// </summary>485 [Parameter]486 [ValidateNotNullOrEmpty]487 public string[] ExternalModuleDependencies { get; set; }488 489 /// <summary>490 /// Gets or sets the HelpInfo URI.491 /// </summary>492 [Parameter]493 [AllowNull]494 public string HelpInfoUri495 {496 get { return _helpInfoUri; }497 498 set { _helpInfoUri = value; }499 }500 501 private string _helpInfoUri;502 503 /// <summary>504 /// Gets or sets whether the module manifest string should go to the output stream.505 /// </summary>506 [Parameter]507 public SwitchParameter PassThru508 {509 get { return (SwitchParameter)_passThru; }510 511 set { _passThru = value; }512 }513 514 private bool _passThru;515 516 /// <summary>517 /// Gets or sets the Default Command Prefix.518 /// </summary>519 [Parameter]520 [AllowNull]521 public string DefaultCommandPrefix522 {523 get { return _defaultCommandPrefix; }524 525 set { _defaultCommandPrefix = value; }526 }527 528 private string _defaultCommandPrefix;529 530 private string _indent = string.Empty;531 532 /// <summary>533 /// Return a single-quoted string. Any embedded single quotes will be doubled.534 /// </summary>535 /// <param name="name">The string to quote.</param>536 /// <returns>The quoted string.</returns>537 private static string QuoteName(string name)538 {539 if (name == null)540 return "''";541 return ("'" + name.Replace("'", "''") + "'");542 }543 544 /// <summary>545 /// Return a single-quoted string using the AbsoluteUri member to ensure it is escaped correctly.546 /// </summary>547 /// <param name="name">The Uri to quote.</param>548 /// <returns>The quoted AbsoluteUri.</returns>549 private static string QuoteName(Uri name)550 {551 if (name == null)552 return "''";553 return QuoteName(name.AbsoluteUri);554 }555 556 /// <summary>557 /// Return a single-quoted string from a Version object.558 /// </summary>559 /// <param name="name">The Version object to quote.</param>560 /// <returns>The quoted Version string.</returns>561 private static string QuoteName(Version name)562 {563 if (name == null)564 return "''";565 return QuoteName(name.ToString());566 }567 568 /// <summary>569 /// Takes a collection of strings and returns the collection570 /// quoted.571 /// </summary>572 /// <param name="names">The list to quote.</param>573 /// <param name="streamWriter">Streamwriter to get end of line character from.</param>574 /// <returns>The quoted list.</returns>575 private static string QuoteNames(IEnumerable names, StreamWriter streamWriter)576 {577 if (names == null)578 return "@()";579 580 StringBuilder result = new StringBuilder();581 582 int offset = 15;583 bool first = true;584 foreach (string name in names)585 {586 if (!string.IsNullOrEmpty(name))587 {588 if (first)589 {590 first = false;591 }592 else593 {594 result.Append(", ");595 }596 597 string quotedString = QuoteName(name);598 offset += quotedString.Length;599 if (offset > 80)600 {601 result.Append(streamWriter.NewLine);602 result.Append(" ");603 offset = 15 + quotedString.Length;604 }605 606 result.Append(quotedString);607 }608 }609 610 if (result.Length == 0)611 return "@()";612 613 return result.ToString();614 }615 616 /// <summary>617 /// This function is created to PreProcess -NestedModules in Win8.618 /// In Win7, -NestedModules is of type string[]. In Win8, we changed619 /// this to object[] to support module specification using hashtable.620 /// To be backward compatible, this function calls ToString() on any621 /// object that is not of type hashtable or string.622 /// </summary>623 /// <param name="moduleSpecs"></param>624 /// <returns></returns>625 private static IEnumerable PreProcessModuleSpec(IEnumerable moduleSpecs)626 {627 if (moduleSpecs != null)628 {629 foreach (object spec in moduleSpecs)630 {631 if (spec is not Hashtable)632 {633 yield return spec.ToString();634 }635 else636 {637 yield return spec;638 }639 }640 }641 }642 643 /// <summary>644 /// Takes a collection of "module specifications" (string or hashtable)645 /// and returns the collection as a string that can be inserted into a module manifest.646 /// </summary>647 /// <param name="moduleSpecs">The list to quote.</param>648 /// <param name="streamWriter">Streamwriter to get end of line character from.</param>649 /// <returns>The quoted list.</returns>650 private static string QuoteModules(IEnumerable moduleSpecs, StreamWriter streamWriter)651 {652 StringBuilder result = new StringBuilder();653 result.Append("@(");654 655 if (moduleSpecs != null)656 {657 bool firstModule = true;658 foreach (object spec in moduleSpecs)659 {660 if (spec == null)661 {662 continue;663 }664 665 ModuleSpecification moduleSpecification = (ModuleSpecification)LanguagePrimitives.ConvertTo(666 spec,667 typeof(ModuleSpecification),668 CultureInfo.InvariantCulture);669 670 if (!firstModule)671 {672 result.Append(", ");673 result.Append(streamWriter.NewLine);674 result.Append(" ");675 }676 677 firstModule = false;678 679 if ((moduleSpecification.Guid == null) && (moduleSpecification.Version == null) && (moduleSpecification.MaximumVersion == null) && (moduleSpecification.RequiredVersion == null))680 {681 result.Append(QuoteName(moduleSpecification.Name));682 }683 else684 {685 result.Append("@{");686 687 result.Append("ModuleName = ");688 result.Append(QuoteName(moduleSpecification.Name));689 result.Append("; ");690 691 if (moduleSpecification.Guid != null)692 {693 result.Append("GUID = ");694 result.Append(QuoteName(moduleSpecification.Guid.ToString()));695 result.Append("; ");696 }697 698 if (moduleSpecification.Version != null)699 {700 result.Append("ModuleVersion = ");701 result.Append(QuoteName(moduleSpecification.Version.ToString()));702 result.Append("; ");703 }704 705 if (moduleSpecification.MaximumVersion != null)706 {707 result.Append("MaximumVersion = ");708 result.Append(QuoteName(moduleSpecification.MaximumVersion));709 result.Append("; ");710 }711 712 if (moduleSpecification.RequiredVersion != null)713 {714 result.Append("RequiredVersion = ");715 result.Append(QuoteName(moduleSpecification.RequiredVersion.ToString()));716 result.Append("; ");717 }718 719 result.Append('}');720 }721 }722 }723 724 result.Append(')');725 return result.ToString();726 }727 728 /// <summary>729 /// Takes a collection of file names and returns the collection730 /// quoted.731 /// </summary>732 /// <param name="names">The list to quote.</param>733 /// <param name="streamWriter">Streamwriter to get end of line character from.</param>734 /// <returns>The quoted list.</returns>735 private string QuoteFiles(IEnumerable names, StreamWriter streamWriter)736 {737 List<string> resolvedPaths = new List<string>();738 739 if (names != null)740 {741 foreach (string name in names)742 {743 if (!string.IsNullOrEmpty(name))744 {745 foreach (string path in TryResolveFilePath(name))746 {747 resolvedPaths.Add(path);748 }749 }750 }751 }752 753 return QuoteNames(resolvedPaths, streamWriter);754 }755 756 ///// <summary>757 ///// Takes a collection of file names and returns the collection758 ///// quoted. It does not expand wildcard to actual files (as QuoteFiles does).759 ///// It throws an error when the entered filename is different than the allowedExtension.760 ///// If any file name falls outside the directory tree basPath a warning is issued.761 ///// </summary>762 ///// <param name="basePath">This is the path which will be used to determine whether a warning is to be displayed.</param>763 ///// <param name="names">The list to quote</param>764 ///// <param name="allowedExtension">This is the allowed file extension, any other extension will give an error.</param>765 ///// <param name="streamWriter">Streamwriter to get end of line character from</param>766 ///// <param name="item">The item of the manifest file for which names are being resolved.</param>767 ///// <returns>The quoted list.</returns>768 // private string QuoteFilesWithWildcard(string basePath, IEnumerable names, string allowedExtension, StreamWriter streamWriter, string item)769 // {770 // if (names != null)771 // {772 // foreach (string name in names)773 // {774 // if (string.IsNullOrEmpty(name))775 // continue;776 777 // string fileName = name;778 779 // string extension = System.IO.Path.GetExtension(fileName);780 // if (string.Equals(extension, allowedExtension, StringComparison.OrdinalIgnoreCase))781 // {782 // string drive = string.Empty;783 // if (!SessionState.Path.IsPSAbsolute(fileName, out drive) && !System.IO.Path.IsPathRooted(fileName))784 // {785 // fileName = SessionState.Path.Combine(SessionState.Path.CurrentLocation.ProviderPath, fileName);786 // }787 788 // string basePathDir = System.IO.Path.GetDirectoryName(SessionState.Path.GetUnresolvedProviderPathFromPSPath(basePath));789 // if (basePathDir[basePathDir.Length - 1] != StringLiterals.DefaultPathSeparator)790 // {791 // basePathDir += StringLiterals.DefaultPathSeparator;792 // }793 // string fileDir = null;794 795 // // Call to SessionState.Path.GetUnresolvedProviderPathFromPSPath throws an exception796 // // when the drive in the path does not exist.797 // // Based on the exception it is obvious that the path is outside the basePath, because798 // // basePath must always exist.799 // try800 // {801 // fileDir = System.IO.Path.GetDirectoryName(SessionState.Path.GetUnresolvedProviderPathFromPSPath(fileName));802 // if (fileDir[fileDir.Length - 1] != StringLiterals.DefaultPathSeparator)803 // {804 // fileDir += StringLiterals.DefaultPathSeparator;805 // }806 // }807 // catch808 // {809 // }810 811 // if (fileDir == null812 // || !fileDir.StartsWith(basePathDir, StringComparison.OrdinalIgnoreCase))813 // {814 // WriteWarning(StringUtil.Format(Modules.IncludedItemPathFallsOutsideSaveTree, name,815 // fileDir ?? name, item));816 // }817 // }818 // else819 // {820 // string message = StringUtil.Format(Modules.InvalidWorkflowExtension);821 // InvalidOperationException invalidOp = new InvalidOperationException(message);822 // ErrorRecord er = new ErrorRecord(invalidOp, "Modules_InvalidWorkflowExtension",823 // ErrorCategory.InvalidOperation, null);824 // ThrowTerminatingError(er);825 // }826 // }827 // }828 829 // return QuoteNames(names, streamWriter);830 // }831 832 /// <summary>833 /// Glob a set of files then resolve them to relative paths.834 /// </summary>835 /// <param name="filePath"></param>836 /// <returns></returns>837 private List<string> TryResolveFilePath(string filePath)838 {839 List<string> result = new List<string>();840 ProviderInfo provider = null;841 SessionState sessionState = Context.SessionState;842 try843 {844 Collection<string> filePaths =845 sessionState.Path.GetResolvedProviderPathFromPSPath(filePath, out provider);846 847 // If the name doesn't resolve to something we can use, just return the unresolved name...848 if (!provider.NameEquals(this.Context.ProviderNames.FileSystem) || filePaths == null || filePaths.Count < 1)849 {850 result.Add(filePath);851 return result;852 }853 854 // Otherwise get the relative resolved path and trim the .\ or ./ because855 // modules are always loaded relative to the manifest base directory.856 foreach (string path in filePaths)857 {858 string adjustedPath = SessionState.Path.NormalizeRelativePath(path,859 SessionState.Path.CurrentLocation.ProviderPath);860 if (adjustedPath.StartsWith(".\\", StringComparison.OrdinalIgnoreCase) ||861 adjustedPath.StartsWith("./", StringComparison.OrdinalIgnoreCase))862 {863 adjustedPath = adjustedPath.Substring(2);864 }865 866 result.Add(adjustedPath);867 }868 }869 catch (ItemNotFoundException)870 {871 result.Add(filePath);872 }873 874 return result;875 }876 877 /// <summary>878 /// This routine builds a fragment of the module manifest file879 /// for a particular key. It returns a formatted string that includes880 /// a comment describing the key as well as the key and its value.881 /// </summary>882 /// <param name="key">The manifest key to use.</param>883 /// <param name="resourceString">ResourceString that holds the message.</param>884 /// <param name="value">The formatted manifest fragment.</param>885 /// <param name="streamWriter">Streamwriter to get end of line character from.</param>886 /// <returns></returns>887 private string ManifestFragment(string key, string resourceString, string value, StreamWriter streamWriter)888 {889 return string.Format(CultureInfo.InvariantCulture, "{0}# {1}{2}{0}{3:19} = {4}{2}{2}", _indent, resourceString, streamWriter.NewLine, key, value);890 }891 892 private string ManifestFragmentForNonSpecifiedManifestMember(string key, string resourceString, string value, StreamWriter streamWriter)893 {894 return string.Format(CultureInfo.InvariantCulture, "{0}# {1}{2}{0}# {3:19} = {4}{2}{2}", _indent, resourceString, streamWriter.NewLine, key, value);895 }896 897 private static string ManifestComment(string insert, StreamWriter streamWriter)898 {899 // Prefix a non-empty string with a space for formatting reasons...900 if (!string.IsNullOrEmpty(insert))901 {902 insert = " " + insert;903 }904 905 return string.Format(CultureInfo.InvariantCulture, "#{0}{1}", insert, streamWriter.NewLine);906 }907 908 /// <summary>909 /// Generate the module manifest...910 /// </summary>911 protected override void EndProcessing()912 {913 // Win8: 264471 - Error message for New-ModuleManifest -ProcessorArchitecture is obsolete.914 // If an undefined value is passed for the ProcessorArchitecture parameter, the error message from parameter binder includes all the values from the enum.915 // The value 'IA64' for ProcessorArchitecture is not supported. But since we do not own the enum System.Reflection.ProcessorArchitecture, we cannot control the values in it.916 // So, we add a separate check in our code to give an error if user specifies IA64917 if (ProcessorArchitecture == ProcessorArchitecture.IA64)918 {919 string message = StringUtil.Format(Modules.InvalidProcessorArchitectureInManifest, ProcessorArchitecture);920 InvalidOperationException ioe = new InvalidOperationException(message);921 ErrorRecord er = new ErrorRecord(ioe, "Modules_InvalidProcessorArchitectureInManifest",922 ErrorCategory.InvalidArgument, ProcessorArchitecture);923 ThrowTerminatingError(er);924 }925 926 ProviderInfo provider = null;927 PSDriveInfo drive;928 string filePath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(_path, out provider, out drive);929 930 if (!provider.NameEquals(Context.ProviderNames.FileSystem) || !filePath.EndsWith(StringLiterals.PowerShellDataFileExtension, StringComparison.OrdinalIgnoreCase))931 {932 string message = StringUtil.Format(Modules.InvalidModuleManifestPath, _path);933 InvalidOperationException ioe = new InvalidOperationException(message);934 ErrorRecord er = new ErrorRecord(ioe, "Modules_InvalidModuleManifestPath",935 ErrorCategory.InvalidArgument, _path);936 ThrowTerminatingError(er);937 }938 939 // By default, we want to generate a module manifest the encourages the best practice of explicitly specifying940 // the commands exported (even if it's an empty array.) Unfortunately, changing the default breaks automation941 // (however unlikely, this cmdlet isn't really meant for automation). Instead of trying to detect interactive942 // use (which is quite hard), we infer interactive use if none of RootModule/NestedModules/RequiredModules is943 // specified - because the manifest needs to be edited to actually be of use in those cases.944 //945 // If one of these parameters has been specified, default back to the old behavior by specifying946 // wildcards for exported commands that weren't specified on the command line.947 if (_rootModule != null || _nestedModules != null || _requiredModules != null)948 {949 _exportedAliases ??= new string[] { "*" };950 _exportedCmdlets ??= new string[] { "*" };951 _exportedFunctions ??= new string[] { "*" };952 }953 954 ValidateUriParameterValue(ProjectUri, "ProjectUri");955 ValidateUriParameterValue(LicenseUri, "LicenseUri");956 ValidateUriParameterValue(IconUri, "IconUri");957 if (_helpInfoUri != null)958 {959 ValidateUriParameterValue(new Uri(_helpInfoUri), "HelpInfoUri");960 }961 962 if (CompatiblePSEditions != null && (CompatiblePSEditions.Distinct(StringComparer.OrdinalIgnoreCase).Count() != CompatiblePSEditions.Length))963 {964 string message = StringUtil.Format(Modules.DuplicateEntriesInCompatiblePSEditions, string.Join(',', CompatiblePSEditions));965 var ioe = new InvalidOperationException(message);966 var er = new ErrorRecord(ioe, "Modules_DuplicateEntriesInCompatiblePSEditions", ErrorCategory.InvalidArgument, CompatiblePSEditions);967 ThrowTerminatingError(er);968 }969 970 string action = StringUtil.Format(Modules.CreatingModuleManifestFile, filePath);971 972 if (ShouldProcess(filePath, action))973 {974 if (string.IsNullOrEmpty(_author))975 {976 _author = Environment.UserName;977 }978 979 if (string.IsNullOrEmpty(_companyName))980 {981 _companyName = Modules.DefaultCompanyName;982 }983 984 if (string.IsNullOrEmpty(_copyright))985 {986 _copyright = StringUtil.Format(Modules.DefaultCopyrightMessage, _author);987 }988 989 FileStream fileStream;990 StreamWriter streamWriter;991 FileInfo readOnlyFileInfo;992 993 // Now open the output file...994 PathUtils.MasterStreamOpen(995 cmdlet: this,996 filePath: filePath,997 resolvedEncoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false),998 defaultEncoding: false,999 Append: false,1000 Force: false,1001 NoClobber: false,1002 fileStream: out fileStream,1003 streamWriter: out streamWriter,1004 readOnlyFileInfo: out readOnlyFileInfo,1005 isLiteralPath: false1006 );1007 1008 try1009 {1010 StringBuilder result = new StringBuilder();1011 1012 // Insert the formatted manifest header...1013 result.Append(ManifestComment(string.Empty, streamWriter));1014 result.Append(ManifestComment(StringUtil.Format(Modules.ManifestHeaderLine1, System.IO.Path.GetFileNameWithoutExtension(filePath)),1015 streamWriter));1016 result.Append(ManifestComment(string.Empty, streamWriter));1017 result.Append(ManifestComment(StringUtil.Format(Modules.ManifestHeaderLine2, _author),1018 streamWriter));1019 result.Append(ManifestComment(string.Empty, streamWriter));1020 result.Append(ManifestComment(StringUtil.Format(Modules.ManifestHeaderLine3, DateTime.Now.ToString("d", CultureInfo.CurrentCulture)),1021 streamWriter));1022 result.Append(ManifestComment(string.Empty, streamWriter));1023 result.Append(streamWriter.NewLine);1024 result.Append("@{");1025 result.Append(streamWriter.NewLine);1026 result.Append(streamWriter.NewLine);1027 1028 _rootModule ??= string.Empty;1029 1030 BuildModuleManifest(result, nameof(RootModule), Modules.RootModule, !string.IsNullOrEmpty(_rootModule), () => QuoteName(_rootModule), streamWriter);1031 1032 BuildModuleManifest(result, nameof(ModuleVersion), Modules.ModuleVersion, _moduleVersion != null && !string.IsNullOrEmpty(_moduleVersion.ToString()), () => QuoteName(_moduleVersion), streamWriter);1033 1034 BuildModuleManifest(result, nameof(CompatiblePSEditions), Modules.CompatiblePSEditions, _compatiblePSEditions != null && _compatiblePSEditions.Length > 0, () => QuoteNames(_compatiblePSEditions, streamWriter), streamWriter);1035 1036 BuildModuleManifest(result, nameof(Modules.GUID), Modules.GUID, !string.IsNullOrEmpty(_guid.ToString()), () => QuoteName(_guid.ToString()), streamWriter);1037 1038 BuildModuleManifest(result, nameof(Author), Modules.Author, !string.IsNullOrEmpty(_author), () => QuoteName(Author), streamWriter);1039 1040 BuildModuleManifest(result, nameof(CompanyName), Modules.CompanyName, !string.IsNullOrEmpty(_companyName), () => QuoteName(_companyName), streamWriter);1041 1042 BuildModuleManifest(result, nameof(Copyright), Modules.Copyright, !string.IsNullOrEmpty(_copyright), () => QuoteName(_copyright), streamWriter);1043 1044 BuildModuleManifest(result, nameof(Description), Modules.Description, !string.IsNullOrEmpty(_description), () => QuoteName(_description), streamWriter);1045 1046 BuildModuleManifest(result, nameof(PowerShellVersion), Modules.PowerShellVersion, _powerShellVersion != null && !string.IsNullOrEmpty(_powerShellVersion.ToString()), () => QuoteName(_powerShellVersion), streamWriter);1047 1048 BuildModuleManifest(result, nameof(PowerShellHostName), Modules.PowerShellHostName, !string.IsNullOrEmpty(_PowerShellHostName), () => QuoteName(_PowerShellHostName), streamWriter);1049 1050 BuildModuleManifest(result, nameof(PowerShellHostVersion), Modules.PowerShellHostVersion, _PowerShellHostVersion != null && !string.IsNullOrEmpty(_PowerShellHostVersion.ToString()), () => QuoteName(_PowerShellHostVersion), streamWriter);1051 1052 BuildModuleManifest(result, nameof(DotNetFrameworkVersion), StringUtil.Format(Modules.DotNetFrameworkVersion, Modules.PrerequisiteForDesktopEditionOnly), _DotNetFrameworkVersion != null && !string.IsNullOrEmpty(_DotNetFrameworkVersion.ToString()), () => QuoteName(_DotNetFrameworkVersion), streamWriter);1053 1054 BuildModuleManifest(result, nameof(ClrVersion), StringUtil.Format(Modules.CLRVersion, Modules.PrerequisiteForDesktopEditionOnly), _ClrVersion != null && !string.IsNullOrEmpty(_ClrVersion.ToString()), () => QuoteName(_ClrVersion), streamWriter);1055 1056 BuildModuleManifest(result, nameof(ProcessorArchitecture), Modules.ProcessorArchitecture, _processorArchitecture.HasValue, () => QuoteName(_processorArchitecture.ToString()), streamWriter);1057 1058 BuildModuleManifest(result, nameof(RequiredModules), Modules.RequiredModules, _requiredModules != null && _requiredModules.Length > 0, () => QuoteModules(_requiredModules, streamWriter), streamWriter);1059 1060 BuildModuleManifest(result, nameof(RequiredAssemblies), Modules.RequiredAssemblies, _requiredAssemblies != null, () => QuoteFiles(_requiredAssemblies, streamWriter), streamWriter);1061 1062 BuildModuleManifest(result, nameof(ScriptsToProcess), Modules.ScriptsToProcess, _scripts != null, () => QuoteFiles(_scripts, streamWriter), streamWriter);1063 1064 BuildModuleManifest(result, nameof(TypesToProcess), Modules.TypesToProcess, _types != null, () => QuoteFiles(_types, streamWriter), streamWriter);1065 1066 BuildModuleManifest(result, nameof(FormatsToProcess), Modules.FormatsToProcess, _formats != null, () => QuoteFiles(_formats, streamWriter), streamWriter);1067 1068 BuildModuleManifest(result, nameof(NestedModules), Modules.NestedModules, _nestedModules != null, () => QuoteModules(PreProcessModuleSpec(_nestedModules), streamWriter), streamWriter);1069 1070 BuildModuleManifest(result, nameof(FunctionsToExport), Modules.FunctionsToExport, true, () => QuoteNames(_exportedFunctions, streamWriter), streamWriter);1071 1072 BuildModuleManifest(result, nameof(CmdletsToExport), Modules.CmdletsToExport, true, () => QuoteNames(_exportedCmdlets, streamWriter), streamWriter);1073 1074 BuildModuleManifest(result, nameof(VariablesToExport), Modules.VariablesToExport, _exportedVariables != null && _exportedVariables.Length > 0, () => QuoteNames(_exportedVariables, streamWriter), streamWriter);1075 1076 BuildModuleManifest(result, nameof(AliasesToExport), Modules.AliasesToExport, true, () => QuoteNames(_exportedAliases, streamWriter), streamWriter);1077 1078 BuildModuleManifest(result, nameof(DscResourcesToExport), Modules.DscResourcesToExport, _dscResourcesToExport != null && _dscResourcesToExport.Length > 0, () => QuoteNames(_dscResourcesToExport, streamWriter), streamWriter);1079 1080 BuildModuleManifest(result, nameof(ModuleList), Modules.ModuleList, _moduleList != null, () => QuoteModules(_moduleList, streamWriter), streamWriter);1081 1082 BuildModuleManifest(result, nameof(FileList), Modules.FileList, _miscFiles != null, () => QuoteFiles(_miscFiles, streamWriter), streamWriter);1083 1084 BuildPrivateDataInModuleManifest(result, streamWriter);1085 1086 BuildModuleManifest(result, nameof(Modules.HelpInfoURI), Modules.HelpInfoURI, !string.IsNullOrEmpty(_helpInfoUri), () => QuoteName((_helpInfoUri != null) ? new Uri(_helpInfoUri) : null), streamWriter);1087 1088 BuildModuleManifest(result, nameof(DefaultCommandPrefix), Modules.DefaultCommandPrefix, !string.IsNullOrEmpty(_defaultCommandPrefix), () => QuoteName(_defaultCommandPrefix), streamWriter);1089 1090 result.Append('}');1091 result.Append(streamWriter.NewLine);1092 result.Append(streamWriter.NewLine);1093 string strResult = result.ToString();1094 1095 if (_passThru)1096 {1097 WriteObject(strResult);1098 }1099 1100 streamWriter.Write(strResult);1101 }1102 finally1103 {1104 streamWriter.Dispose();1105 }1106 }1107 }1108 1109 private void BuildModuleManifest(StringBuilder result, string key, string keyDescription, bool hasValue, Func<string> action, StreamWriter streamWriter)1110 {1111 if (hasValue)1112 {1113 result.Append(ManifestFragment(key, keyDescription, action(), streamWriter));1114 }1115 else1116 {1117 result.Append(ManifestFragmentForNonSpecifiedManifestMember(key, keyDescription, action(), streamWriter));1118 }1119 }1120 1121 // PrivateData format in manifest file when PrivateData value is a HashTable or not specified.1122 // <#1123 // # Private data to pass to the module specified in RootModule/ModuleToProcess1124 // PrivateData = @{1125 //1126 // PSData = @{1127 // # Tags of this module1128 // Tags = @()1129 // # LicenseUri of this module1130 // LicenseUri = ''1131 // # ProjectUri of this module1132 // ProjectUri = ''1133 // # IconUri of this module1134 // IconUri = ''1135 // # ReleaseNotes of this module1136 // ReleaseNotes = ''1137 // }# end of PSData hashtable1138 //1139 // # User's private data keys1140 //1141 // }# end of PrivateData hashtable1142 // #>1143 private void BuildPrivateDataInModuleManifest(StringBuilder result, StreamWriter streamWriter)1144 {1145 var privateDataHashTable = PrivateData as Hashtable;1146 bool specifiedPSDataProperties = !(Tags == null && ReleaseNotes == null && ProjectUri == null && IconUri == null && LicenseUri == null);1147 1148 if (_privateData != null && privateDataHashTable == null)1149 {1150 if (specifiedPSDataProperties)1151 {1152 var ioe = new InvalidOperationException(Modules.PrivateDataValueTypeShouldBeHashTableError);1153 var er = new ErrorRecord(ioe, "PrivateDataValueTypeShouldBeHashTable", ErrorCategory.InvalidArgument, _privateData);1154 ThrowTerminatingError(er);1155 }1156 else1157 {1158 WriteWarning(Modules.PrivateDataValueTypeShouldBeHashTableWarning);1159 1160 BuildModuleManifest(result, nameof(PrivateData), Modules.PrivateData, _privateData != null,1161 () => QuoteName((string)LanguagePrimitives.ConvertTo(_privateData, typeof(string), CultureInfo.InvariantCulture)),1162 streamWriter);1163 }1164 }1165 else1166 {1167 result.Append(ManifestComment(Modules.PrivateData, streamWriter));1168 result.Append("PrivateData = @{");1169 result.Append(streamWriter.NewLine);1170 1171 result.Append(streamWriter.NewLine);1172 result.Append(" PSData = @{");1173 result.Append(streamWriter.NewLine);1174 result.Append(streamWriter.NewLine);1175 1176 _indent = " ";1177 1178 BuildModuleManifest(result, nameof(Tags), Modules.Tags, Tags != null && Tags.Length > 0, () => QuoteNames(Tags, streamWriter), streamWriter);1179 BuildModuleManifest(result, nameof(LicenseUri), Modules.LicenseUri, LicenseUri != null, () => QuoteName(LicenseUri), streamWriter);1180 BuildModuleManifest(result, nameof(ProjectUri), Modules.ProjectUri, ProjectUri != null, () => QuoteName(ProjectUri), streamWriter);1181 BuildModuleManifest(result, nameof(IconUri), Modules.IconUri, IconUri != null, () => QuoteName(IconUri), streamWriter);1182 BuildModuleManifest(result, nameof(ReleaseNotes), Modules.ReleaseNotes, !string.IsNullOrEmpty(ReleaseNotes), () => QuoteName(ReleaseNotes), streamWriter);1183 BuildModuleManifest(result, nameof(Prerelease), Modules.Prerelease, !string.IsNullOrEmpty(Prerelease), () => QuoteName(Prerelease), streamWriter);1184 BuildModuleManifest(result, nameof(RequireLicenseAcceptance), Modules.RequireLicenseAcceptance, RequireLicenseAcceptance.IsPresent, () => RequireLicenseAcceptance.IsPresent ? "$true" : "$false", streamWriter);1185 BuildModuleManifest(result, nameof(ExternalModuleDependencies), Modules.ExternalModuleDependencies, ExternalModuleDependencies != null && ExternalModuleDependencies.Length > 0, () => QuoteNames(ExternalModuleDependencies, streamWriter), streamWriter);1186 1187 result.Append(" } ");1188 result.Append(ManifestComment(StringUtil.Format(Modules.EndOfManifestHashTable, "PSData"), streamWriter));1189 result.Append(streamWriter.NewLine);1190 1191 _indent = " ";1192 if (privateDataHashTable != null)1193 {1194 result.Append(streamWriter.NewLine);1195 1196 foreach (DictionaryEntry entry in privateDataHashTable)1197 {1198 result.Append(ManifestFragment(entry.Key.ToString(), entry.Key.ToString(), QuoteName((string)LanguagePrimitives.ConvertTo(entry.Value, typeof(string), CultureInfo.InvariantCulture)), streamWriter));1199 }1200 }