Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
UpdateHelpCommand.cs517 linesDownload Raw Back to help
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.ObjectModel;6using System.Diagnostics;7using System.Diagnostics.CodeAnalysis;8using System.Globalization;9using System.IO;10using System.Linq;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 Update-Help cmdlet.19    /// </summary>20    [Cmdlet(VerbsData.Update, "Help", DefaultParameterSetName = PathParameterSetName,21        SupportsShouldProcess = true,22        HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096805")]23    public sealed class UpdateHelpCommand : UpdatableHelpCommandBase24    {25        #region Constructor26 27        /// <summary>28        /// Class constructor.29        /// </summary>30        public UpdateHelpCommand() : base(UpdatableHelpCommandType.UpdateHelpCommand)31        {32        }33 34        #endregion35 36        private bool _alreadyCheckedOncePerDayPerModule = false;37 38        #region Parameters39 40        /// <summary>41        /// Specifies the modules to update.42        /// </summary>43        [Parameter(Position = 0, ParameterSetName = PathParameterSetName, ValueFromPipelineByPropertyName = true)]44        [Parameter(Position = 0, ParameterSetName = LiteralPathParameterSetName, ValueFromPipelineByPropertyName = true)]45        [Alias("Name")]46        [ValidateNotNull]47        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]48        public string[] Module49        {50            get51            {52                return _module;53            }54 55            set56            {57                _module = value;58            }59        }60 61        private string[] _module;62 63        /// <summary>64        /// Specifies the Module Specifications to update.65        /// </summary>66        [Parameter(ParameterSetName = PathParameterSetName, ValueFromPipelineByPropertyName = true)]67        [Parameter(ParameterSetName = LiteralPathParameterSetName, ValueFromPipelineByPropertyName = true)]68        [ValidateNotNull]69        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]70        public ModuleSpecification[] FullyQualifiedModule { get; set; }71 72        /// <summary>73        /// Specifies the paths to update from.74        /// </summary>75        [Parameter(Position = 1, ParameterSetName = PathParameterSetName)]76        [ValidateNotNull]77        [Alias("Path")]78        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]79        public string[] SourcePath80        {81            get82            {83                return _path;84            }85 86            set87            {88                _path = value;89            }90        }91 92        private string[] _path;93 94        /// <summary>95        /// Specifies the literal path to save updates to.96        /// </summary>97        [Parameter(ParameterSetName = LiteralPathParameterSetName, ValueFromPipelineByPropertyName = true)]98        [Alias("PSPath", "LP")]99        [ValidateNotNull]100        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]101        public string[] LiteralPath102        {103            get104            {105                return _path;106            }107 108            set109            {110                _path = value;111                _isLiteralPath = true;112            }113        }114 115        private bool _isLiteralPath = false;116 117        /// <summary>118        /// Scans paths recursively.119        /// </summary>120        [Parameter]121        public SwitchParameter Recurse122        {123            get124            {125                return _recurse;126            }127 128            set129            {130                _recurse = value;131            }132        }133 134        private bool _recurse;135 136        #endregion137 138        private bool _isInitialized = false;139 140        #region Implementation141 142        /// <summary>143        /// Begin processing.144        /// </summary>145        protected override void BeginProcessing()146        {147            if (_path == null)148            {149                // Pull default source path from GP150                string defaultSourcePath = _helpSystem.GetDefaultSourcePath();151 152                if (defaultSourcePath != null)153                {154                    _path = new string[1] { defaultSourcePath };155                }156            }157        }158 159        /// <summary>160        /// Main cmdlet logic.161        /// </summary>162        protected override void ProcessRecord()163        {164            try165            {166                // Module and FullyQualifiedModule should not be specified at the same time.167                // Throw out terminating error if this is the case.168                if (Module != null && FullyQualifiedModule != null)169                {170                    string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "Module", "FullyQualifiedModule");171                    ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "ModuleAndFullyQualifiedModuleCannotBeSpecifiedTogether", ErrorCategory.InvalidOperation, null);172                    ThrowTerminatingError(error);173                }174 175                if (!_isInitialized)176                {177                    if (_path == null && Recurse.IsPresent)178                    {179                        PSArgumentException e = new PSArgumentException(StringUtil.Format(HelpDisplayStrings.CannotSpecifyRecurseWithoutPath));180                        ThrowTerminatingError(e.ErrorRecord);181                    }182 183                    _isInitialized = true;184                }185                186                // check if there is an UI, if not Throw out terminating error. 187                var cultures = _language ?? _helpSystem.GetCurrentUICulture();188                if (!cultures.Any()) 189                {                    190                    string cultureString = string.IsNullOrEmpty(CultureInfo.CurrentCulture.Name) ? CultureInfo.CurrentCulture.DisplayName : CultureInfo.CurrentCulture.Name;191                    string errMsg = StringUtil.Format(HelpDisplayStrings.FailedToUpdateHelpWithLocaleNoUICulture, cultureString);192                    ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "FailedToUpdateHelpWithLocaleNoUICulture", ErrorCategory.InvalidOperation, targetObject: null);                    193                    ThrowTerminatingError(error);194                }195 196                base.Process(_module, FullyQualifiedModule);197 198                // Reset the per-runspace help cache199                foreach (HelpProvider provider in Context.HelpSystem.HelpProviders)200                {201                    if (_stopping)202                    {203                        break;204                    }205 206                    provider.Reset();207                }208            }209            finally210            {211                ProgressRecord progress = new ProgressRecord(activityId, HelpDisplayStrings.UpdateProgressActivityForModule, HelpDisplayStrings.UpdateProgressInstalling);212 213                progress.PercentComplete = 100;214                progress.RecordType = ProgressRecordType.Completed;215 216                WriteProgress(progress);217            }218        }219 220        /// <summary>221        /// Process a single module with a given culture.222        /// </summary>223        /// <param name="module">Module to process.</param>224        /// <param name="culture">Culture to use.</param>225        /// <returns>True if the module has been processed, false if not.</returns>226        internal override bool ProcessModuleWithCulture(UpdatableHelpModuleInfo module, string culture)227        {228            // Simulate culture not found229            if (InternalTestHooks.ThrowHelpCultureNotSupported)230            {231                throw new UpdatableHelpSystemException("HelpCultureNotSupported",232                    StringUtil.Format(HelpDisplayStrings.HelpCultureNotSupported, culture, "en-US"),233                    ErrorCategory.InvalidOperation, null, null);234            }235 236            UpdatableHelpInfo currentHelpInfo = null;237            UpdatableHelpInfo newHelpInfo = null;238            string helpInfoUri = null;239 240            string moduleBase = module.ModuleBase;241 242            if (this.Scope == UpdateHelpScope.CurrentUser)243            {244                moduleBase = HelpUtils.GetModuleBaseForUserHelp(moduleBase, module.ModuleName);245            }246 247            // reading the xml file even if force is specified248            // Reason: we need the current version for ShouldProcess249            string xml = UpdatableHelpSystem.LoadStringFromPath(this,250                 SessionState.Path.Combine(moduleBase, module.GetHelpInfoName()),251                 null);252 253            if (xml != null)254            {255                // constructing the helpinfo object from previous update help log xml..256                // no need to resolve the uri's in this case.257                currentHelpInfo = _helpSystem.CreateHelpInfo(xml, module.ModuleName, module.ModuleGuid,258                                                             currentCulture: null, pathOverride: null, verbose: false,259                                                             shouldResolveUri: false,260                                                             // ignore validation exception if _force is true261                                                             ignoreValidationException: _force);262            }263 264            // Don't update too frequently265            if (!_alreadyCheckedOncePerDayPerModule && !CheckOncePerDayPerModule(module.ModuleName, moduleBase, module.GetHelpInfoName(), DateTime.UtcNow, _force))266            {267                return true;268            }269 270            _alreadyCheckedOncePerDayPerModule = true;271 272            if (_path != null)273            {274                UpdatableHelpSystemDrive helpInfoDrive = null;275                try276                {277                    Collection<string> resolvedPaths = new Collection<string>();278 279                    // Search for the HelpInfo XML280                    foreach (string path in _path)281                    {282                        if (string.IsNullOrEmpty(path))283                        {284                            PSArgumentException e = new PSArgumentException(StringUtil.Format(HelpDisplayStrings.PathNullOrEmpty));285                            WriteError(e.ErrorRecord);286                            return false;287                        }288 289                        try290                        {291                            string sourcePath = path;292 293                            if (_credential != null)294                            {295                                UpdatableHelpSystemDrive drive = new UpdatableHelpSystemDrive(this, path, _credential);296                                sourcePath = drive.DriveName;297                            }298 299                            // Expand wildcard characters300                            foreach (string tempPath in ResolvePath(sourcePath, _recurse, _isLiteralPath))301                            {302                                resolvedPaths.Add(tempPath);303                            }304                        }305                        catch (System.Management.Automation.DriveNotFoundException e)306                        {307                            ThrowPathMustBeValidContainersException(path, e);308                        }309                        catch (ItemNotFoundException e)310                        {311                            ThrowPathMustBeValidContainersException(path, e);312                        }313                    }314 315                    if (resolvedPaths.Count == 0)316                    {317                        return true;318                    }319 320                    // Everything in resolvedPaths is a container321                    foreach (string resolvedPath in resolvedPaths)322                    {323                        string literalPath = SessionState.Path.Combine(resolvedPath, module.GetHelpInfoName());324 325                        xml = UpdatableHelpSystem.LoadStringFromPath(this, literalPath, _credential);326 327                        if (xml != null)328                        {329                            newHelpInfo = _helpSystem.CreateHelpInfo(xml, module.ModuleName, module.ModuleGuid, culture, resolvedPath,330                                                                     verbose: false, shouldResolveUri: true, ignoreValidationException: false);331                            helpInfoUri = resolvedPath;332                            break;333                        }334                    }335                }336                catch (Exception e)337                {338                    throw new UpdatableHelpSystemException("UnableToRetrieveHelpInfoXml",339                        StringUtil.Format(HelpDisplayStrings.UnableToRetrieveHelpInfoXml, culture), ErrorCategory.ResourceUnavailable,340                        null, e);341                }342                finally343                {344                    helpInfoDrive?.Dispose();345                }346            }347            else348            {349                // Form the actual HelpInfo.xml uri350                helpInfoUri = _helpSystem.GetHelpInfoUri(module, null).ResolvedUri;351                string uri = helpInfoUri + module.GetHelpInfoName();352 353                newHelpInfo = _helpSystem.GetHelpInfo(UpdatableHelpCommandType.UpdateHelpCommand, uri, module.ModuleName, module.ModuleGuid, culture);354            }355 356            if (newHelpInfo == null)357            {358                throw new UpdatableHelpSystemException("UnableToRetrieveHelpInfoXml",359                    StringUtil.Format(HelpDisplayStrings.UnableToRetrieveHelpInfoXml, culture), ErrorCategory.ResourceUnavailable,360                    null, null);361            }362 363            bool installed = false;364 365            foreach (UpdatableHelpUri contentUri in newHelpInfo.HelpContentUriCollection)366            {367                Version currentHelpVersion = currentHelpInfo?.GetCultureVersion(contentUri.Culture);368                string updateHelpShouldProcessAction = string.Format(CultureInfo.InvariantCulture,369                    HelpDisplayStrings.UpdateHelpShouldProcessActionMessage,370                    module.ModuleName,371                    (currentHelpVersion != null) ? currentHelpVersion.ToString() : "0.0.0.0",372                    newHelpInfo.GetCultureVersion(contentUri.Culture),373                    contentUri.Culture);374                if (!this.ShouldProcess(updateHelpShouldProcessAction, "Update-Help"))375                {376                    continue;377                }378 379                if (Utils.IsUnderProductFolder(moduleBase) && (!Utils.IsAdministrator()))380                {381                    string message = StringUtil.Format(HelpErrors.UpdatableHelpRequiresElevation);382                    ProcessException(module.ModuleName, null, new UpdatableHelpSystemException("UpdatableHelpSystemRequiresElevation",383                            message, ErrorCategory.InvalidOperation, null, null));384                    return false;385                }386 387                if (!IsUpdateNecessary(module, _force ? null : currentHelpInfo, newHelpInfo, contentUri.Culture, _force))388                {389                    WriteVerbose(StringUtil.Format(HelpDisplayStrings.SuccessfullyUpdatedHelpContent, module.ModuleName, HelpDisplayStrings.NewestContentAlreadyInstalled,390                        contentUri.Culture.Name, newHelpInfo.GetCultureVersion(contentUri.Culture)));391 392                    installed = true;393                    continue;394                }395                else396                {397                    try398                    {399                        Debug.Assert(helpInfoUri != null, "If we are here, helpInfoUri must not be null");400 401                        string helpContentUri = contentUri.ResolvedUri;402                        string xsdPath = SessionState.Path.Combine(Utils.GetApplicationBase(Context.ShellID), "Schemas\\PSMaml\\maml.xsd"); // TODO: Edit the maml XSDs and change this403 404                        // Gather destination paths405                        Collection<string> destPaths = new Collection<string>();406 407                        if (!Directory.Exists(moduleBase))408                        {409                            Directory.CreateDirectory(moduleBase);410                        }411 412                        destPaths.Add(moduleBase);413 414#if !CORECLR // Side-By-Side directories are not present in OneCore environments.415                        if (IsSystemModule(module.ModuleName) && Environment.Is64BitOperatingSystem)416                        {417                            string path = Utils.DefaultPowerShellAppBase.Replace("System32", "SysWOW64");418 419                            destPaths.Add(path);420                        }421#endif422 423                        Collection<string> filesInstalled;424 425                        if (Directory.Exists(helpContentUri))426                        {427                            if (_credential != null)428                            {429                                string helpContentName = module.GetHelpContentName(contentUri.Culture);430                                string tempContentPath = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));431 432                                try433                                {434                                    using (UpdatableHelpSystemDrive drive = new UpdatableHelpSystemDrive(this, helpContentUri, _credential))435                                    {436                                        if (!Directory.Exists(tempContentPath))437                                        {438                                            Directory.CreateDirectory(tempContentPath);439                                        }440 441                                        InvokeProvider.Item.Copy(new string[1] { Path.Combine(drive.DriveName, helpContentName) },442                                            Path.Combine(tempContentPath, helpContentName), false, CopyContainers.CopyTargetContainer, true, true);443 444                                        // Local445                                        _helpSystem.InstallHelpContent(UpdatableHelpCommandType.UpdateHelpCommand, Context, tempContentPath,446                                            destPaths, module.GetHelpContentName(contentUri.Culture),447                                            Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName())),448                                            contentUri.Culture, xsdPath, out filesInstalled);449                                    }450                                }451                                catch (Exception e)452                                {453                                    throw new UpdatableHelpSystemException("HelpContentNotFound", StringUtil.Format(HelpDisplayStrings.HelpContentNotFound),454                                        ErrorCategory.ResourceUnavailable, null, e);455                                }456                            }457                            else458                            {459                                _helpSystem.InstallHelpContent(UpdatableHelpCommandType.UpdateHelpCommand, Context, helpContentUri,460                                    destPaths, module.GetHelpContentName(contentUri.Culture),461                                    Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName())),462                                    contentUri.Culture, xsdPath, out filesInstalled);463                            }464                        }465                        else466                        {467                            // Remote468 469                            // Download and install help content470                            if (!_helpSystem.DownloadAndInstallHelpContent(UpdatableHelpCommandType.UpdateHelpCommand, Context,471                                destPaths, module.GetHelpContentName(contentUri.Culture), contentUri.Culture, helpContentUri, xsdPath, out filesInstalled))472                            {473                                installed = false;474                                continue;475                            }476                        }477 478                        _helpSystem.GenerateHelpInfo(module.ModuleName, module.ModuleGuid, newHelpInfo.UnresolvedUri, contentUri.Culture.Name, newHelpInfo.GetCultureVersion(contentUri.Culture),479                            moduleBase, module.GetHelpInfoName(), _force);480 481                        foreach (string fileInstalled in filesInstalled)482                        {483                            WriteVerbose(StringUtil.Format(HelpDisplayStrings.SuccessfullyUpdatedHelpContent, module.ModuleName,484                                StringUtil.Format(HelpDisplayStrings.UpdatedHelpContent, fileInstalled), contentUri.Culture.Name,485                                newHelpInfo.GetCultureVersion(contentUri.Culture)));486                        }487 488                        LogMessage(StringUtil.Format(HelpDisplayStrings.UpdateHelpCompleted));489 490                        installed = true;491                    }492                    catch (Exception e)493                    {494                        ProcessException(module.ModuleName, contentUri.Culture.Name, e);495                    }496                }497            }498 499            return installed;500        }501 502        /// <summary>503        /// Throws PathMustBeValidContainers exception.504        /// </summary>505        /// <param name="path"></param>506        /// <param name="e"></param>507        private static void ThrowPathMustBeValidContainersException(string path, Exception e)508        {509            throw new UpdatableHelpSystemException("PathMustBeValidContainers",510                StringUtil.Format(HelpDisplayStrings.PathMustBeValidContainers, path), ErrorCategory.InvalidArgument,511                null, e);512        }513 514        #endregion515    }516}517