Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SaveHelpCommand.cs514 linesDownload Raw Back to help
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.Diagnostics;9using System.Diagnostics.CodeAnalysis;10using System.IO;11using System.Management.Automation;12using System.Management.Automation.Help;13using System.Management.Automation.Internal;14 15namespace Microsoft.PowerShell.Commands16{17    /// <summary>18    /// This class implements the Save-Help cmdlet.19    /// </summary>20    [Cmdlet(VerbsData.Save, "Help", DefaultParameterSetName = SaveHelpCommand.PathParameterSetName,21        HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096794")]22    public sealed class SaveHelpCommand : UpdatableHelpCommandBase23    {24        #region Constructor25 26        /// <summary>27        /// Class constructor.28        /// </summary>29        public SaveHelpCommand() : base(UpdatableHelpCommandType.SaveHelpCommand)30        {31        }32 33        #endregion34 35        private bool _alreadyCheckedOncePerDayPerModule = false;36 37        #region Parameters38 39        /// <summary>40        /// Specifies the paths to save updates to.41        /// </summary>42        [Parameter(Mandatory = true, Position = 0, ParameterSetName = PathParameterSetName)]43        [ValidateNotNull]44        [Alias("Path")]45        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]46        public string[] DestinationPath47        {48            get49            {50                return _path;51            }52 53            set54            {55                _path = value;56            }57        }58 59        private string[] _path;60 61        /// <summary>62        /// Specifies the literal path to save updates to.63        /// </summary>64        [Parameter(Mandatory = true, ParameterSetName = LiteralPathParameterSetName)]65        [Alias("PSPath", "LP")]66        [ValidateNotNull]67        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]68        public string[] LiteralPath69        {70            get71            {72                return _path;73            }74 75            set76            {77                _path = value;78                _isLiteralPath = true;79            }80        }81 82        private bool _isLiteralPath = false;83 84        /// <summary>85        /// Specifies the modules to update.86        /// </summary>87        [Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, ParameterSetName = PathParameterSetName)]88        [Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, ParameterSetName = LiteralPathParameterSetName)]89        [Alias("Name")]90        [ValidateNotNull]91        [ArgumentToModuleTransformation]92        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]93        public PSModuleInfo[] Module { get; set; }94 95        /// <summary>96        /// Specifies the Module Specifications to update.97        /// </summary>98        [Parameter(ParameterSetName = PathParameterSetName, ValueFromPipelineByPropertyName = true)]99        [Parameter(ParameterSetName = LiteralPathParameterSetName, ValueFromPipelineByPropertyName = true)]100        [ValidateNotNull]101        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]102        public ModuleSpecification[] FullyQualifiedModule { get; set; }103 104        #endregion105 106        #region Implementation107 108        /// <summary>109        /// </summary>110        protected override void ProcessRecord()111        {112            try113            {114                // Module and FullyQualifiedModule should not be specified at the same time.115                // Throw out terminating error if this is the case.116                if (Module != null && FullyQualifiedModule != null)117                {118                    string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "Module", "FullyQualifiedModule");119                    ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "ModuleAndFullyQualifiedModuleCannotBeSpecifiedTogether", ErrorCategory.InvalidOperation, null);120                    ThrowTerminatingError(error);121                }122 123                List<string> moduleNames = null;124                List<PSModuleInfo> moduleInfos = null;125 126                if (Module != null)127                {128                    moduleNames = new List<string>();129                    moduleInfos = new List<PSModuleInfo>();130 131                    foreach (PSModuleInfo moduleInfo in Module)132                    {133                        // WinBlue: 268863134                        // this check will cover the cases where135                        // user supplied just name with -Module parameter.136                        // In other cases, user must have supplied either137                        // PSModuleInfo or Deserialized PSModuleInfo138                        if (string.IsNullOrEmpty(moduleInfo.ModuleBase))139                        {140                            moduleNames.Add(moduleInfo.Name);141                        }142                        else143                        {144                            moduleInfos.Add(moduleInfo);145                        }146                    }147                }148 149                base.Process(moduleNames, FullyQualifiedModule);150                base.Process(moduleInfos);151            }152            finally153            {154                ProgressRecord progress = new ProgressRecord(activityId, HelpDisplayStrings.SaveProgressActivityForModule, HelpDisplayStrings.UpdateProgressInstalling);155 156                progress.PercentComplete = 100;157                progress.RecordType = ProgressRecordType.Completed;158 159                WriteProgress(progress);160            }161        }162 163        /// <summary>164        /// Process a single module with a given culture.165        /// </summary>166        /// <param name="module">Module to process.</param>167        /// <param name="culture">Culture to use.</param>168        /// <returns>True if the module has been processed, false if not.</returns>169        internal override bool ProcessModuleWithCulture(UpdatableHelpModuleInfo module, string culture)170        {171            Collection<string> resolvedPaths = new Collection<string>();172 173            // Search for the HelpInfo XML174            foreach (string path in _path)175            {176                UpdatableHelpSystemDrive helpInfoDrive = null;177 178                try179                {180                    if (string.IsNullOrEmpty(path))181                    {182                        PSArgumentException e = new PSArgumentException(StringUtil.Format(HelpDisplayStrings.PathNullOrEmpty));183                        WriteError(e.ErrorRecord);184                        return false;185                    }186 187                    string destPath = path;188 189                    if (_credential != null)190                    {191                        if (path.Contains('*'))192                        {193                            // Deal with wildcards194 195                            int index = path.IndexOf('*');196 197                            if (index == 0)198                            {199                                throw new UpdatableHelpSystemException("PathMustBeValidContainers",200                                    StringUtil.Format(HelpDisplayStrings.PathMustBeValidContainers, path), ErrorCategory.InvalidArgument,201                                    null, new ItemNotFoundException());202                            }203                            else204                            {205                                int i = index;206                                for (; i >= 0; i--)207                                {208                                    if (path[i].Equals('/') || path[i].Equals('\\'))209                                    {210                                        break;211                                    }212                                }213 214                                if (i == 0)215                                {216                                    throw new UpdatableHelpSystemException("PathMustBeValidContainers",217                                        StringUtil.Format(HelpDisplayStrings.PathMustBeValidContainers, path), ErrorCategory.InvalidArgument,218                                        null, new ItemNotFoundException());219                                }220 221                                helpInfoDrive = new UpdatableHelpSystemDrive(this, path.Substring(0, i), _credential);222                                destPath = Path.Combine(helpInfoDrive.DriveName, path.Substring(i + 1, path.Length - (i + 1)));223                            }224                        }225                        else226                        {227                            helpInfoDrive = new UpdatableHelpSystemDrive(this, path, _credential);228                            destPath = helpInfoDrive.DriveName;229                        }230                    }231 232                    if (_isLiteralPath)233                    {234                        string destinationPath = GetUnresolvedProviderPathFromPSPath(destPath);235                        if (!Directory.Exists(destinationPath))236                        {237                            throw new UpdatableHelpSystemException("PathMustBeValidContainers",238                                StringUtil.Format(HelpDisplayStrings.PathMustBeValidContainers, path), ErrorCategory.InvalidArgument,239                                null, new ItemNotFoundException());240                        }241 242                        resolvedPaths.Add(destinationPath);243                    }244                    else245                    {246                        try247                        {248                            // Expand wildcard characters249                            foreach (string tempPath in ResolvePath(destPath, false, false))250                            {251                                resolvedPaths.Add(tempPath);252                            }253                        }254                        catch (ItemNotFoundException e)255                        {256                            throw new UpdatableHelpSystemException("PathMustBeValidContainers",257                                StringUtil.Format(HelpDisplayStrings.PathMustBeValidContainers, path), ErrorCategory.InvalidArgument, null, e);258                        }259                    }260                }261                finally262                {263                    helpInfoDrive?.Dispose();264                }265            }266 267            if (resolvedPaths.Count == 0)268            {269                return true;270            }271 272            bool installed = false;273 274            foreach (string path in resolvedPaths)275            {276                UpdatableHelpInfo currentHelpInfo = null;277                UpdatableHelpInfo newHelpInfo = null;278                string helpInfoUri = null;279 280                // if -force is specified, no need to read from the current HelpInfo.xml file281                // because it won't be used for checking "IsUpdateNecessary"282                string xml = _force283                                 ? null284                                 : UpdatableHelpSystem.LoadStringFromPath(this,285                                                                          SessionState.Path.Combine(path, module.GetHelpInfoName()),286                                                                          _credential);287 288                if (xml != null)289                {290                    // constructing the helpinfo object from previous update help log xml..291                    // no need to resolve the uri's in this case.292                    currentHelpInfo = _helpSystem.CreateHelpInfo(xml, module.ModuleName, module.ModuleGuid,293                                                                 currentCulture: null, pathOverride: null, verbose: false,294                                                                 shouldResolveUri: false, ignoreValidationException: false);295                }296 297                // Don't update too frequently298                if (!_alreadyCheckedOncePerDayPerModule && !CheckOncePerDayPerModule(module.ModuleName, path, module.GetHelpInfoName(), DateTime.UtcNow, _force))299                {300                    return true;301                }302 303                _alreadyCheckedOncePerDayPerModule = true;304 305                // Form the actual HelpInfo.xml uri306                helpInfoUri = _helpSystem.GetHelpInfoUri(module, null).ResolvedUri;307                string uri = helpInfoUri + module.GetHelpInfoName();308 309                newHelpInfo = _helpSystem.GetHelpInfo(_commandType, uri, module.ModuleName, module.ModuleGuid, culture);310 311                if (newHelpInfo == null)312                {313                    throw new UpdatableHelpSystemException("UnableToRetrieveHelpInfoXml",314                        StringUtil.Format(HelpDisplayStrings.UnableToRetrieveHelpInfoXml, culture), ErrorCategory.ResourceUnavailable,315                        null, null);316                }317 318                string tempPath = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetTempFileName()));319                foreach (UpdatableHelpUri contentUri in newHelpInfo.HelpContentUriCollection)320                {321                    if (!IsUpdateNecessary(module, currentHelpInfo, newHelpInfo, contentUri.Culture, _force))322                    {323                        WriteVerbose(StringUtil.Format(HelpDisplayStrings.SuccessfullyUpdatedHelpContent, module.ModuleName, HelpDisplayStrings.NewestContentAlreadyDownloaded,324                            contentUri.Culture.Name, newHelpInfo.GetCultureVersion(contentUri.Culture)));325 326                        installed = true;327                        continue;328                    }329                    else330                    {331                        Debug.Assert(helpInfoUri != null, "If we are here, helpInfoUri must not be null");332 333                        string helpContentUri = contentUri.ResolvedUri;334                        string helpContentName = module.GetHelpContentName(contentUri.Culture);335 336                        UpdatableHelpSystemDrive helpContentDrive = null;337 338                        try339                        {340                            if (Directory.Exists(helpContentUri))341                            {342                                File.Copy(SessionState.Path.Combine(helpContentUri, helpContentName),343                                    SessionState.Path.Combine(path, helpContentName), true);344                            }345                            else346                            {347                                // Remote348 349                                if (_credential != null)350                                {351                                    try352                                    {353                                        helpContentDrive = new UpdatableHelpSystemDrive(this, path, _credential);354 355                                        if (!_helpSystem.DownloadHelpContent(_commandType, tempPath, helpContentUri, helpContentName, culture))356                                        {357                                            installed = false;358                                            continue;359                                        }360 361                                        InvokeProvider.Item.Copy(new string[1] { tempPath }, helpContentDrive.DriveName, true, CopyContainers.CopyChildrenOfTargetContainer,362                                            true, true);363                                    }364                                    catch (Exception e)365                                    {366                                        ProcessException(module.ModuleName, contentUri.Culture.Name, e);367                                        installed = false;368                                        continue;369                                    }370                                }371                                else372                                {373                                    if (!_helpSystem.DownloadHelpContent(_commandType, path, helpContentUri, helpContentName, culture))374                                    {375                                        installed = false;376                                        continue;377                                    }378                                }379                            }380 381                            if (_credential != null)382                            {383                                _helpSystem.GenerateHelpInfo(module.ModuleName, module.ModuleGuid, newHelpInfo.UnresolvedUri, contentUri.Culture.Name, newHelpInfo.GetCultureVersion(contentUri.Culture), tempPath,384                                    module.GetHelpInfoName(), _force);385 386                                InvokeProvider.Item.Copy(new string[1] { Path.Combine(tempPath, module.GetHelpInfoName()) }, Path.Combine(helpContentDrive.DriveName, module.GetHelpInfoName()), false,387                                    CopyContainers.CopyTargetContainer, true, true);388                            }389                            else390                            {391                                _helpSystem.GenerateHelpInfo(module.ModuleName, module.ModuleGuid, newHelpInfo.UnresolvedUri, contentUri.Culture.Name, newHelpInfo.GetCultureVersion(contentUri.Culture), path,392                                    module.GetHelpInfoName(), _force);393                            }394 395                            WriteVerbose(StringUtil.Format(HelpDisplayStrings.SuccessfullyUpdatedHelpContent, module.ModuleName,396                                StringUtil.Format(HelpDisplayStrings.SavedHelpContent, System.IO.Path.Combine(path, helpContentName)), contentUri.Culture.Name,397                                newHelpInfo.GetCultureVersion(contentUri.Culture)));398 399                            LogMessage(StringUtil.Format(HelpDisplayStrings.SaveHelpCompleted, path));400                        }401                        catch (Exception e)402                        {403                            ProcessException(module.ModuleName, contentUri.Culture.Name, e);404                        }405                        finally406                        {407                            helpContentDrive?.Dispose();408                        }409                    }410                }411 412                installed = true;413            }414 415            return installed;416        }417 418        #endregion419    }420 421    internal sealed class ArgumentToModuleTransformationAttribute : ArgumentTransformationAttribute422    {423        public override object Transform(EngineIntrinsics engineIntrinsics, object inputData)424        {425            object argument = PSObject.Base(inputData);426 427            // deal with scalar string argument428            var strArg = argument as string;429            if (strArg != null)430            {431                return new PSModuleInfo(name: strArg, path: null, context: null, sessionState: null);432            }433 434            // deal with IList argument435            IList iListArg = ParameterBinderBase.GetIList(argument);436            if (iListArg != null && iListArg.Count > 0)437            {438                int elementCount = iListArg.Count;439                int targetIndex = 0;440                var target = Array.CreateInstance(typeof(object), elementCount);441 442                foreach (object element in iListArg)443                {444                    var elementValue = PSObject.Base(element);445 446                    if (elementValue is PSModuleInfo)447                    {448                        target.SetValue(elementValue, targetIndex++);449                    }450                    else if (elementValue is string)451                    {452                        var elementAsModuleObj = new PSModuleInfo(name: (string)elementValue, path: null, context: null, sessionState: null);453                        target.SetValue(elementAsModuleObj, targetIndex++);454                    }455                    else456                    {457                        PSModuleInfo elementValueModuleInfo = null;458                        if (TryConvertFromDeserializedModuleInfo(elementValue, out elementValueModuleInfo))459                        {460                            target.SetValue(elementValueModuleInfo, targetIndex++);461                        }462                        else463                        {464                            target.SetValue(element, targetIndex++);465                        }466                    }467                }468 469                return target;470            }471 472            PSModuleInfo moduleInfo = null;473            if (TryConvertFromDeserializedModuleInfo(inputData, out moduleInfo))474            {475                return moduleInfo;476            }477 478            return inputData;479        }480 481        private static bool TryConvertFromDeserializedModuleInfo(object inputData, out PSModuleInfo moduleInfo)482        {483            moduleInfo = null;484            PSObject pso = inputData as PSObject;485            if (Deserializer.IsDeserializedInstanceOfType(pso, typeof(PSModuleInfo)))486            {487                string moduleName;488                LanguagePrimitives.TryConvertTo<string>(pso.Properties["Name"].Value, out moduleName);489 490                Guid moduleGuid;491                LanguagePrimitives.TryConvertTo<Guid>(pso.Properties["Guid"].Value, out moduleGuid);492 493                Version moduleVersion;494                LanguagePrimitives.TryConvertTo<Version>(pso.Properties["Version"].Value, out moduleVersion);495 496                string helpInfoUri;497                LanguagePrimitives.TryConvertTo<string>(pso.Properties["HelpInfoUri"].Value, out helpInfoUri);498 499                moduleInfo = new PSModuleInfo(name: moduleName, path: null, context: null, sessionState: null);500                moduleInfo.SetGuid(moduleGuid);501                moduleInfo.SetVersion(moduleVersion);502                moduleInfo.SetHelpInfoUri(helpInfoUri);503                // setting the base to temp directory as this is a deserialized504                // module info.505                moduleInfo.SetModuleBase(System.IO.Path.GetTempPath());506 507                return true;508            }509 510            return false;511        }512    }513}514