Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
CommandSearcher.cs1734 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#nullable enable5 6using System.Collections;7using System.Collections.Generic;8using System.Collections.ObjectModel;9using System.Diagnostics.CodeAnalysis;10using System.IO;11using System.Management.Automation.Internal;12using System.Management.Automation.Security;13 14using Dbg = System.Management.Automation.Diagnostics;15 16namespace System.Management.Automation17{18    /// <summary>19    /// Used to enumerate the commands on the system that match the specified20    /// command name.21    /// </summary>22    internal class CommandSearcher : IEnumerable<CommandInfo>, IEnumerator<CommandInfo>23    {24        /// <summary>25        /// Constructs a command searching enumerator that resolves the location26        /// to a command using a standard algorithm.27        /// </summary>28        /// <param name="commandName">The name of the command to look for.</param>29        /// <param name="options">Determines which types of commands glob resolution of the name will take place on.</param>30        /// <param name="commandTypes">The types of commands to look for.</param>31        /// <param name="context">The execution context for this engine instance.</param>32        /// <param name="fuzzyMatcher">The fuzzy matcher to use for fuzzy searching.</param>33        ///34        /// <exception cref="ArgumentNullException">If <paramref name="context"/> is null.</exception>35        /// <exception cref="PSArgumentException">If <paramref name="commandName"/> is null or empty.</exception>36        internal CommandSearcher(37            string commandName,38            SearchResolutionOptions options,39            CommandTypes commandTypes,40            ExecutionContext context,41            FuzzyMatcher? fuzzyMatcher = null)42        {43            Diagnostics.Assert(context != null, "caller to verify context is not null");44            Diagnostics.Assert(!string.IsNullOrEmpty(commandName), "caller to verify commandName is valid");45 46            _commandName = commandName;47            _context = context;48            _commandResolutionOptions = options;49            _commandTypes = commandTypes;50            _fuzzyMatcher = fuzzyMatcher;51 52            // Initialize the enumerators53            this.Reset();54        }55 56        /// <summary>57        /// Gets an instance of a command enumerator.58        /// </summary>59        /// <returns>60        /// An instance of this class as IEnumerator.61        /// </returns>62        IEnumerator<CommandInfo> IEnumerable<CommandInfo>.GetEnumerator()63        {64            return this;65        }66 67        IEnumerator IEnumerable.GetEnumerator()68        {69            return this;70        }71 72        /// <summary>73        /// Moves the enumerator to the next command match. Public for IEnumerable.74        /// </summary>75        /// <returns>76        /// true if there was another command that matches, false otherwise.77        /// </returns>78        public bool MoveNext()79        {80            _currentMatch = null;81 82            if (_currentState == SearchState.SearchingAliases)83            {84                _currentMatch = SearchForAliases();85 86                // Why don't we check IsVisible on other scoped items?87                if (_currentMatch != null && SessionState.IsVisible(_commandOrigin, _currentMatch))88                {89                    return true;90                }91 92                // Make sure Current doesn't return an alias that isn't visible93                _currentMatch = null;94 95                // Advance the state96                _currentState = SearchState.SearchingFunctions;97            }98 99            if (_currentState == SearchState.SearchingFunctions)100            {101                _currentMatch = SearchForFunctions();102                // Return the alias info only if it is visible. If not, then skip to the next103                // stage of command resolution...104                if (_currentMatch != null)105                {106                    return true;107                }108 109                // Advance the state110                _currentState = SearchState.SearchingCmdlets;111            }112 113            if (_currentState == SearchState.SearchingCmdlets)114            {115                _currentMatch = SearchForCmdlets();116                if (_currentMatch != null)117                {118                    return true;119                }120 121                // Advance the state122                _currentState = SearchState.StartSearchingForExternalCommands;123            }124 125            if (_currentState == SearchState.StartSearchingForExternalCommands)126            {127                if ((_commandTypes & (CommandTypes.Application | CommandTypes.ExternalScript)) == 0)128                {129                    // Since we are not requiring any path lookup in this search, just return false now130                    // because all the remaining searches do path lookup.131                    return false;132                }133 134                // For security reasons, if the command is coming from outside the runspace and it looks like a path,135                // we want to pre-check that path before doing any probing of the network or drives136                if (_commandOrigin == CommandOrigin.Runspace && _commandName.IndexOfAny(Utils.Separators.DirectoryOrDrive) >= 0)137                {138                    bool allowed = false;139 140                    // Ok - it looks like it might be a path, so we're going to check to see if the command is prefixed141                    // by any of the allowed paths. If so, then we allow the search to proceed...142 143                    // If either the Applications or Script lists contain just '*' the command is allowed144                    // at this point.145                    if ((_context.EngineSessionState.Applications.Count == 1 &&146                        _context.EngineSessionState.Applications[0].Equals("*", StringComparison.OrdinalIgnoreCase)) ||147                        (_context.EngineSessionState.Scripts.Count == 1 &&148                        _context.EngineSessionState.Scripts[0].Equals("*", StringComparison.OrdinalIgnoreCase)))149                    {150                        allowed = true;151                    }152                    else153                    {154                        // Ok, see if it's in the applications list155                        foreach (string path in _context.EngineSessionState.Applications)156                        {157                            if (checkPath(path, _commandName))158                            {159                                allowed = true;160                                break;161                            }162                        }163 164                        // If it wasn't in the applications list, see it's in the script list165                        if (!allowed)166                        {167                            foreach (string path in _context.EngineSessionState.Scripts)168                            {169                                if (checkPath(path, _commandName))170                                {171                                    allowed = true;172                                    break;173                                }174                            }175                        }176                    }177 178                    if (!allowed)179                    {180                        return false;181                    }182                }183 184                // Advance the state185 186                _currentState = SearchState.PowerShellPathResolution;187 188                _currentMatch = ProcessBuiltinScriptState();189 190                if (_currentMatch != null)191                {192                    // Set the current state to QualifiedFileSystemPath since193                    // we want to skip the qualified file system path search194                    // in the case where we found a PowerShell qualified path.195 196                    _currentState = SearchState.QualifiedFileSystemPath;197                    return true;198                }199            }200 201            if (_currentState == SearchState.PowerShellPathResolution)202            {203                _currentState = SearchState.QualifiedFileSystemPath;204 205                _currentMatch = ProcessPathResolutionState();206 207                if (_currentMatch != null)208                {209                    return true;210                }211            }212 213            // Search using CommandPathSearch214 215            if (_currentState == SearchState.QualifiedFileSystemPath ||216                    _currentState == SearchState.PathSearch)217            {218                _currentMatch = ProcessQualifiedFileSystemState();219 220                if (_currentMatch != null)221                {222                    return true;223                }224            }225 226            if (_currentState == SearchState.PathSearch)227            {228                _currentState = SearchState.PowerShellRelativePath;229 230                _currentMatch = ProcessPathSearchState();231 232                if (_currentMatch != null)233                {234                    return true;235                }236            }237 238            return false;239        }240 241        private CommandInfo? SearchForAliases()242        {243            CommandInfo? currentMatch = null;244 245            if (_context.EngineSessionState != null &&246                (_commandTypes & CommandTypes.Alias) != 0)247            {248                currentMatch = GetNextAlias();249            }250 251            return currentMatch;252        }253 254        private CommandInfo? SearchForFunctions()255        {256            CommandInfo? currentMatch = null;257 258            if (_context.EngineSessionState != null &&259                (_commandTypes & (CommandTypes.Function | CommandTypes.Filter | CommandTypes.Configuration)) != 0)260            {261                currentMatch = GetNextFunction();262            }263 264            return currentMatch;265        }266 267        private CommandInfo? SearchForCmdlets()268        {269            CommandInfo? currentMatch = null;270 271            if ((_commandTypes & CommandTypes.Cmdlet) != 0)272            {273                currentMatch = GetNextCmdlet();274            }275 276            return currentMatch;277        }278 279        private CommandInfo? ProcessBuiltinScriptState()280        {281            CommandInfo? currentMatch = null;282 283            // Check to see if the path is qualified284 285            if (_context.EngineSessionState != null &&286                _context.EngineSessionState.ProviderCount > 0 &&287                IsQualifiedPSPath(_commandName))288            {289                currentMatch = GetNextFromPath();290            }291 292            return currentMatch;293        }294 295        private CommandInfo? ProcessPathResolutionState()296        {297            CommandInfo? currentMatch = null;298 299            try300            {301                // Check to see if the path is a file system path that302                // is rooted.  If so that is the next match303                if (Path.IsPathRooted(_commandName) &&304                    File.Exists(_commandName))305                {306                    try307                    {308                        currentMatch = GetInfoFromPath(_commandName);309                    }310                    catch (FileLoadException)311                    {312                    }313                    catch (FormatException)314                    {315                    }316                    catch (MetadataException)317                    {318                    }319                }320            }321            catch (ArgumentException)322            {323                // If the path contains illegal characters that324                // weren't caught by the other APIs, IsPathRooted325                // will throw an exception.326                // For example, looking for a command called327                // `abcdef328                // The `a will be translated into the beep control character329                // which is not a legal file system character, though330                // Path.InvalidPathChars does not contain it as an invalid331                // character.332            }333 334            return currentMatch;335        }336 337        private CommandInfo? ProcessQualifiedFileSystemState()338        {339            try340            {341                setupPathSearcher();342            }343            catch (ArgumentException)344            {345                _currentState = SearchState.NoMoreMatches;346                throw;347            }348            catch (PathTooLongException)349            {350                _currentState = SearchState.NoMoreMatches;351                throw;352            }353 354            CommandInfo? currentMatch = null;355            _currentState = SearchState.PathSearch;356            if (_canDoPathLookup)357            {358                try359                {360                    // the previous call to setupPathSearcher ensures _pathSearcher != null361                    while (currentMatch == null && _pathSearcher!.MoveNext())362                    {363                        currentMatch = GetInfoFromPath(((IEnumerator<string>)_pathSearcher).Current);364                    }365                }366                catch (InvalidOperationException)367                {368                    // The enumerator may throw if there are no more matches369                }370            }371 372            return currentMatch;373        }374 375        private CommandInfo? ProcessPathSearchState()376        {377            CommandInfo? currentMatch = null;378            string? path = DoPowerShellRelativePathLookup();379 380            if (!string.IsNullOrEmpty(path))381            {382                currentMatch = GetInfoFromPath(path);383            }384 385            return currentMatch;386        }387 388        /// <summary>389        /// Gets the CommandInfo representing the current command match.390        /// </summary>391        /// <value></value>392        /// <exception cref="InvalidOperationException">393        /// The enumerator is positioned before the first element of394        /// the collection or after the last element.395        /// </exception>396        CommandInfo IEnumerator<CommandInfo>.Current397        {398            get399            {400                if ((_currentState == SearchState.SearchingAliases && _currentMatch == null) ||401                    _currentState == SearchState.NoMoreMatches ||402                    _currentMatch == null)403                {404                    throw PSTraceSource.NewInvalidOperationException();405                }406 407                return _currentMatch;408            }409        }410 411        object IEnumerator.Current412        {413            get414            {415                return ((IEnumerator<CommandInfo>)this).Current;416            }417        }418 419        /// <summary>420        /// Required by the IEnumerator generic interface.421        /// Resets the searcher.422        /// </summary>423        public void Dispose()424        {425            if (_pathSearcher != null)426            {427                _pathSearcher.Dispose();428                _pathSearcher = null;429            }430 431            Reset();432            GC.SuppressFinalize(this);433        }434 435        #region private members436 437        /// <summary>438        /// Gets the next command info using the command name as a path.439        /// </summary>440        /// <returns>441        /// A CommandInfo for the next command if it exists as a path, or null otherwise.442        /// </returns>443        private CommandInfo? GetNextFromPath()444        {445            CommandInfo? result = null;446 447            do // false loop448            {449                CommandDiscovery.discoveryTracer.WriteLine(450                    "The name appears to be a qualified path: {0}",451                    _commandName);452 453                CommandDiscovery.discoveryTracer.WriteLine(454                    "Trying to resolve the path as an PSPath");455 456                // Find the match if it is.457                // Try literal path resolution if it is set to run first458                if (_commandResolutionOptions.HasFlag(SearchResolutionOptions.ResolveLiteralThenPathPatterns))459                {460                    var path = GetNextLiteralPathThatExistsAndHandleExceptions(_commandName, out _);461 462                    if (path != null)463                    {464                        return GetInfoFromPath(path);465                    }466                }467 468                Collection<string> resolvedPaths = new Collection<string>();469                if (WildcardPattern.ContainsWildcardCharacters(_commandName))470                {471                    resolvedPaths = GetNextFromPathUsingWildcards(_commandName, out _);472                }473 474                // Try literal path resolution if wildcards are enable first and wildcard search failed475                if (!_commandResolutionOptions.HasFlag(SearchResolutionOptions.ResolveLiteralThenPathPatterns) &&476                    resolvedPaths.Count == 0)477                {478                    string? path = GetNextLiteralPathThatExistsAndHandleExceptions(_commandName, out _);479 480                    if (path != null)481                    {482                        return GetInfoFromPath(path);483                    }484                }485 486                if (resolvedPaths.Count > 1)487                {488                    CommandDiscovery.discoveryTracer.TraceError(489                        "The path resolved to more than one result so this path cannot be used.");490                    break;491                }492 493                // If the path was resolved, and it exists494                if (resolvedPaths.Count == 1 &&495                    File.Exists(resolvedPaths[0]))496                {497                    string path = resolvedPaths[0];498 499                    CommandDiscovery.discoveryTracer.WriteLine(500                        "Path resolved to: {0}",501                        path);502 503                    result = GetInfoFromPath(path);504                }505            } while (false);506 507            return result;508        }509 510        /// <summary>511        /// Gets the next path using WildCards.512        /// </summary>513        /// <param name="command">514        /// The command to search for.515        /// </param>516        /// <param name="provider">The provider that the command was found in.</param>517        /// <returns>518        /// A collection of full paths to the commands which were found.519        /// </returns>520        private Collection<string> GetNextFromPathUsingWildcards(string? command, out ProviderInfo? provider)521        {522            try523            {524                return _context.LocationGlobber.GetGlobbedProviderPathsFromMonadPath(path: command, allowNonexistingPaths: false, provider: out provider, providerInstance: out _);525            }526            catch (ItemNotFoundException)527            {528                CommandDiscovery.discoveryTracer.TraceError(529                    "The path could not be found: {0}",530                    command);531            }532            catch (DriveNotFoundException)533            {534                CommandDiscovery.discoveryTracer.TraceError(535                    "A drive could not be found for the path: {0}",536                    command);537            }538            catch (ProviderNotFoundException)539            {540                CommandDiscovery.discoveryTracer.TraceError(541                    "A provider could not be found for the path: {0}",542                    command);543            }544            catch (InvalidOperationException)545            {546                CommandDiscovery.discoveryTracer.TraceError(547                    "The path specified a home directory, but the provider home directory was not set. {0}",548                    command);549            }550            catch (ProviderInvocationException providerException)551            {552                CommandDiscovery.discoveryTracer.TraceError(553                    "The provider associated with the path '{0}' encountered an error: {1}",554                    command,555                    providerException.Message);556            }557            catch (PSNotSupportedException)558            {559                CommandDiscovery.discoveryTracer.TraceError(560                    "The provider associated with the path '{0}' does not implement ContainerCmdletProvider",561                    command);562            }563 564            provider = null;565            return new Collection<string>();566        }567 568        private static bool checkPath(string path, string commandName)569        {570            return path.StartsWith(commandName, StringComparison.OrdinalIgnoreCase);571        }572 573        /// <summary>574        /// Gets the appropriate CommandInfo instance given the specified path.575        /// </summary>576        /// <param name="path">577        /// The path to create the CommandInfo for.578        /// </param>579        /// <returns>580        /// An instance of the appropriate CommandInfo derivative given the specified path.581        /// </returns>582        /// <exception cref="FileLoadException">583        /// The <paramref name="path"/> refers to a cmdlet, or cmdletprovider584        /// and it could not be loaded as an XML document.585        /// </exception>586        /// <exception cref="FormatException">587        /// The <paramref name="path"/> refers to a cmdlet, or cmdletprovider588        /// that does not adhere to the appropriate file format for its extension.589        /// </exception>590        /// <exception cref="MetadataException">591        /// If <paramref name="path"/> refers to a cmdlet file that592        /// contains invalid metadata.593        /// </exception>594        private CommandInfo? GetInfoFromPath(string path)595        {596            CommandInfo? result = null;597 598            do // false loop599            {600                if (!File.Exists(path))601                {602                    CommandDiscovery.discoveryTracer.TraceError("The path does not exist: {0}", path);603                    break;604                }605 606                // Now create the appropriate CommandInfo using the extension607                string? extension = null;608 609                try610                {611                    extension = Path.GetExtension(path);612                }613                catch (ArgumentException)614                {615                    // If the path contains illegal characters that616                    // weren't caught by the other APIs, GetExtension617                    // will throw an exception.618                    // For example, looking for a command called619                    // `abcdef620                    // The `a will be translated into the beep control character621                    // which is not a legal file system character.622                }623 624                if (extension == null)625                {626                    result = null;627                    break;628                }629 630                if (string.Equals(extension, StringLiterals.PowerShellScriptFileExtension, StringComparison.OrdinalIgnoreCase))631                {632                    if ((_commandTypes & CommandTypes.ExternalScript) != 0)633                    {634                        string scriptName = Path.GetFileName(path);635 636                        CommandDiscovery.discoveryTracer.WriteLine(637                            "Command Found: path ({0}) is a script with name: {1}",638                            path,639                            scriptName);640 641                        // The path is to a PowerShell script642 643                        result = new ExternalScriptInfo(scriptName, path, _context);644                        break;645                    }646 647                    break;648                }649 650                if ((_commandTypes & CommandTypes.Application) != 0)651                {652                    // Anything else is treated like an application653 654                    string appName = Path.GetFileName(path);655 656                    CommandDiscovery.discoveryTracer.WriteLine(657                        "Command Found: path ({0}) is an application with name: {1}",658                        path,659                        appName);660 661                    result = new ApplicationInfo(appName, path, _context);662                    break;663                }664            } while (false);665 666            // Verify that this script is not untrusted, if we aren't constrained.667            if (ShouldSkipCommandResolutionForConstrainedLanguage(result, _context))668            {669                result = null;670            }671 672            return result;673        }674 675        /// <summary>676        /// Gets the next matching alias.677        /// </summary>678        /// <returns>679        /// A CommandInfo representing the next matching alias if found, otherwise null.680        /// </returns>681        private CommandInfo? GetNextAlias()682        {683            CommandInfo? result = null;684 685            if ((_commandResolutionOptions & SearchResolutionOptions.ResolveAliasPatterns) != 0)686            {687                if (_matchingAlias == null)688                {689                    // Generate the enumerator of matching alias names690 691                    Collection<AliasInfo> matchingAliases = new Collection<AliasInfo>();692 693                    WildcardPattern aliasMatcher =694                        WildcardPattern.Get(695                            _commandName,696                            WildcardOptions.IgnoreCase);697 698                    foreach (KeyValuePair<string, AliasInfo> aliasEntry in _context.EngineSessionState.GetAliasTable())699                    {700                        if (aliasMatcher.IsMatch(aliasEntry.Key) ||701                            (_fuzzyMatcher is not null && _fuzzyMatcher.IsFuzzyMatch(aliasEntry.Key, _commandName)))702                        {703                            matchingAliases.Add(aliasEntry.Value);704                        }705                    }706 707                    // Process alias from modules708                    AliasInfo? c = GetAliasFromModules(_commandName);709                    if (c != null)710                    {711                        matchingAliases.Add(c);712                    }713 714                    _matchingAlias = matchingAliases.GetEnumerator();715                }716 717                if (!_matchingAlias.MoveNext())718                {719                    // Advance the state720                    _currentState = SearchState.SearchingFunctions;721 722                    _matchingAlias = null;723                }724                else725                {726                    result = _matchingAlias.Current;727                }728            }729            else730            {731                // Advance the state732                _currentState = SearchState.SearchingFunctions;733 734                result = _context.EngineSessionState.GetAlias(_commandName) ?? GetAliasFromModules(_commandName);735            }736 737            // Verify that this alias was not created by an untrusted constrained language,738            // if we aren't constrained.739            if (ShouldSkipCommandResolutionForConstrainedLanguage(result, _context))740            {741                result = null;742            }743 744            if (result != null)745            {746                CommandDiscovery.discoveryTracer.WriteLine(747                    "Alias found: {0}  {1}",748                    result.Name,749                    result.Definition);750            }751 752            return result;753        }754 755        /// <summary>756        /// Gets the next matching function.757        /// </summary>758        /// <returns>759        /// A CommandInfo representing the next matching function if found, otherwise null.760        /// </returns>761        private CommandInfo? GetNextFunction()762        {763            CommandInfo? result = null;764 765            if (_commandResolutionOptions.HasFlag(SearchResolutionOptions.ResolveFunctionPatterns))766            {767                if (_matchingFunctionEnumerator == null)768                {769                    Collection<CommandInfo?> matchingFunction = new Collection<CommandInfo?>();770 771                    // Generate the enumerator of matching function names772                    WildcardPattern functionMatcher =773                        WildcardPattern.Get(774                            _commandName,775                            WildcardOptions.IgnoreCase);776 777                    foreach ((string functionName, FunctionInfo functionInfo) in _context.EngineSessionState.GetFunctionTable())778                    {779                        if (functionMatcher.IsMatch(functionName) ||780                            (_fuzzyMatcher is not null && _fuzzyMatcher.IsFuzzyMatch(functionName, _commandName)))781                        {782                            matchingFunction.Add(functionInfo);783                        }784                        else if (_commandResolutionOptions.HasFlag(SearchResolutionOptions.UseAbbreviationExpansion))785                        {786                            if (_commandName.Equals(ModuleUtils.AbbreviateName(functionName), StringComparison.OrdinalIgnoreCase))787                            {788                                matchingFunction.Add(functionInfo);789                            }790                        }791                    }792 793                    // Process functions from modules794                    CommandInfo? cmdInfo = GetFunctionFromModules(_commandName);795                    if (cmdInfo != null)796                    {797                        matchingFunction.Add(cmdInfo);798                    }799 800                    _matchingFunctionEnumerator = matchingFunction.GetEnumerator();801                }802 803                if (!_matchingFunctionEnumerator.MoveNext())804                {805                    // Advance the state806                    _currentState = SearchState.SearchingCmdlets;807 808                    _matchingFunctionEnumerator = null;809                }810                else811                {812                    result = _matchingFunctionEnumerator.Current;813                }814            }815            else816            {817                // Advance the state818                _currentState = SearchState.SearchingCmdlets;819 820                result = GetFunction(_commandName);821            }822 823            // Verify that this function was not created by an untrusted constrained language,824            // if we aren't constrained.825            if (ShouldSkipCommandResolutionForConstrainedLanguage(result, _context))826            {827                result = null;828            }829 830            return result;831        }832 833        // Don't return commands to the user if that might result in:834        //     - Trusted commands calling untrusted functions that the user has overridden835        //     - Debug prompts calling internal functions that are likely to have code injection836        private static bool ShouldSkipCommandResolutionForConstrainedLanguage(CommandInfo? result, ExecutionContext executionContext)837        {838            if (result == null)839            {840                return false;841            }842 843            // Don't return untrusted commands to trusted functions.844            if (result.DefiningLanguageMode == PSLanguageMode.ConstrainedLanguage && executionContext.LanguageMode == PSLanguageMode.FullLanguage)845            {846                if (SystemPolicy.GetSystemLockdownPolicy() != SystemEnforcementMode.Audit)847                {848                    return true;849                }850 851                // This audit log message is to inform the user that an expected command will not be available because it is not trusted852                // when the machine is in policy enforcement mode.853                SystemPolicy.LogWDACAuditMessage(854                    context: executionContext,855                    title: CommandBaseStrings.SearcherWDACLogTitle,856                    message: StringUtil.Format(CommandBaseStrings.SearcherWDACLogMessage, result.Name, result.ModuleName ?? string.Empty),857                    fqid: "CommandSearchFailureForUntrustedCommand");858            }859 860            // Don't allow invocation of trusted functions from debug breakpoints.861            // They were probably defined within a trusted script, and could be862            // susceptible to injection attacks. However, we do allow execution863            // of functions defined in the global scope (i.e.: "more",) as those864            // are intended to be exposed explicitly to users.865            if ((result is FunctionInfo) &&866                (executionContext.LanguageMode == PSLanguageMode.ConstrainedLanguage) &&867                (result.DefiningLanguageMode == PSLanguageMode.FullLanguage) &&868                (executionContext.Debugger != null) &&869                (executionContext.Debugger.InBreakpoint) &&870                (!(executionContext.TopLevelSessionState.GetFunctionTableAtScope("GLOBAL").ContainsKey(result.Name))))871            {872                return true;873            }874 875            return false;876        }877 878        private AliasInfo? GetAliasFromModules(string command)879        {880            AliasInfo? result = null;881 882            if (command.IndexOf('\\') > 0)883            {884                // See if it's a module qualified alias...885                PSSnapinQualifiedName? qualifiedName = PSSnapinQualifiedName.GetInstance(command);886                if (qualifiedName != null && !string.IsNullOrEmpty(qualifiedName.PSSnapInName))887                {888                    PSModuleInfo? module = GetImportedModuleByName(qualifiedName.PSSnapInName);889 890                    module?.ExportedAliases.TryGetValue(qualifiedName.ShortName, out result);891                }892            }893 894            return result;895        }896 897        private CommandInfo? GetFunctionFromModules(string command)898        {899            FunctionInfo? result = null;900 901            if (command.IndexOf('\\') > 0)902            {903                // See if it's a module qualified function call...904                PSSnapinQualifiedName? qualifiedName = PSSnapinQualifiedName.GetInstance(command);905                if (qualifiedName != null && !string.IsNullOrEmpty(qualifiedName.PSSnapInName))906                {907                    PSModuleInfo? module = GetImportedModuleByName(qualifiedName.PSSnapInName);908 909                    module?.ExportedFunctions.TryGetValue(qualifiedName.ShortName, out result);910                }911            }912 913            return result;914        }915 916        private PSModuleInfo? GetImportedModuleByName(string moduleName)917        {918            PSModuleInfo? module = null;919            List<PSModuleInfo> modules = _context.Modules.GetModules(new string[] { moduleName }, false);920 921            if (modules != null && modules.Count > 0)922            {923                foreach (PSModuleInfo m in modules)924                {925                    if (_context.previousModuleImported.ContainsKey(m.Name) && ((string?)_context.previousModuleImported[m.Name] == m.Path))926                    {927                        module = m;928                        break;929                    }930                }931 932                module ??= modules[0];933            }934 935            return module;936        }937 938        /// <summary>939        /// Gets the FunctionInfo or FilterInfo for the specified function name.940        /// </summary>941        /// <param name="function">942        /// The name of the function/filter to retrieve.943        /// </param>944        /// <returns>945        /// A FunctionInfo if the function name exists and is a function, a FilterInfo if946        /// the filter name exists and is a filter, or null otherwise.947        /// </returns>948        private CommandInfo? GetFunction(string function)949        {950            CommandInfo? result = _context.EngineSessionState.GetFunction(function);951 952            if (result != null)953            {954                var formatString = result switch955                {956                    FilterInfo => "Filter found: {0}",957                    ConfigurationInfo => "Configuration found: {0}",958                    _ => "Function found: {0}",959                };960                CommandDiscovery.discoveryTracer.WriteLine(formatString, function);961            }962            else963            {964                result = GetFunctionFromModules(function);965            }966 967            return result;968        }969 970        /// <summary>971        /// Gets the next cmdlet from the collection of matching cmdlets.972        /// If the collection doesn't exist yet it is created and the973        /// enumerator is moved to the first item in the collection.974        /// </summary>975        /// <returns>976        /// A CmdletInfo for the next matching Cmdlet or null if there are977        /// no more matches.978        /// </returns>979        private CmdletInfo? GetNextCmdlet()980        {981            CmdletInfo? result = null;982            bool useAbbreviationExpansion = _commandResolutionOptions.HasFlag(SearchResolutionOptions.UseAbbreviationExpansion);983 984            if (_matchingCmdlet == null)985            {986                if (_commandResolutionOptions.HasFlag(SearchResolutionOptions.CommandNameIsPattern) || useAbbreviationExpansion)987                {988                    Collection<CmdletInfo> matchingCmdletInfo = new Collection<CmdletInfo>();989 990                    PSSnapinQualifiedName? PSSnapinQualifiedCommandName =991                        PSSnapinQualifiedName.GetInstance(_commandName);992 993                    if (!useAbbreviationExpansion && PSSnapinQualifiedCommandName == null)994                    {995                        return null;996                    }997 998                    string? moduleName = PSSnapinQualifiedCommandName?.PSSnapInName;999 1000                    var cmdletShortName = PSSnapinQualifiedCommandName?.ShortName;1001                    WildcardPattern? cmdletMatcher = cmdletShortName != null1002                        ? WildcardPattern.Get(cmdletShortName, WildcardOptions.IgnoreCase)1003                        : null;1004 1005                    SessionStateInternal ss = _context.EngineSessionState;1006 1007                    foreach (List<CmdletInfo> cmdletList in ss.GetCmdletTable().Values)1008                    {1009                        foreach (CmdletInfo cmdlet in cmdletList)1010                        {1011                            if ((cmdletMatcher is not null && cmdletMatcher.IsMatch(cmdlet.Name)) ||1012                                (_fuzzyMatcher is not null && _fuzzyMatcher.IsFuzzyMatch(cmdlet.Name, _commandName)))1013                            {1014                                if (string.IsNullOrEmpty(moduleName) || moduleName.Equals(cmdlet.ModuleName, StringComparison.OrdinalIgnoreCase))1015                                {1016                                    // If PSSnapin is specified, make sure they match1017                                    matchingCmdletInfo.Add(cmdlet);1018                                }1019                            }1020                            else if (useAbbreviationExpansion)1021                            {1022                                if (_commandName.Equals(ModuleUtils.AbbreviateName(cmdlet.Name), StringComparison.OrdinalIgnoreCase))1023                                {1024                                    matchingCmdletInfo.Add(cmdlet);1025                                }1026                            }1027                        }1028                    }1029 1030                    _matchingCmdlet = matchingCmdletInfo.GetEnumerator();1031                }1032                else1033                {1034                    _matchingCmdlet = _context.CommandDiscovery.GetCmdletInfo(_commandName,1035                        _commandResolutionOptions.HasFlag(SearchResolutionOptions.SearchAllScopes));1036                }1037            }1038 1039            if (!_matchingCmdlet.MoveNext())1040            {1041                // Advance the state1042                _currentState = SearchState.StartSearchingForExternalCommands;1043 1044                _matchingCmdlet = null;1045            }1046            else1047            {1048                result = _matchingCmdlet.Current;1049            }1050 1051            return traceResult(result);1052        }1053 1054        private IEnumerator<CmdletInfo>? _matchingCmdlet;1055 1056        [return: NotNullIfNotNull("result")]1057        private static CmdletInfo? traceResult(CmdletInfo? result)1058        {1059            if (result != null)1060            {1061                CommandDiscovery.discoveryTracer.WriteLine(1062                    "Cmdlet found: {0}  {1}",1063                    result.Name,1064                    result.ImplementingType);1065            }1066 1067            return result;1068        }1069 1070        private string? DoPowerShellRelativePathLookup()1071        {1072            string? result = null;1073 1074            if (_context.EngineSessionState != null &&1075                _context.EngineSessionState.ProviderCount > 0 && _commandName.Length != 0)1076            {1077                // NTRAID#Windows OS Bugs-1009294-2004/02/04-JeffJon1078                // This is really slow.  Maybe since we are only allowing FS paths right1079                // now we should use the file system APIs to verify the existence of the file.1080 1081                // Since the path to the command was not found using the PATH variable,1082                // maybe it is relative to the current location. Try resolving the1083                // path.1084                // Relative Path:       ".\command.exe"1085                // Home Path:           "~\command.exe"1086                // Drive Relative Path: "\Users\User\AppData\Local\Temp\command.exe"1087 1088                char firstChar = _commandName[0];1089                if (firstChar == '.' || firstChar == '~' || firstChar == '\\')1090                {1091                    using (CommandDiscovery.discoveryTracer.TraceScope(1092                        "{0} appears to be a relative path. Trying to resolve relative path",1093                        _commandName))1094                    {1095                        result = ResolvePSPath(_commandName);1096                    }1097                }1098            }1099 1100            return result;1101        }1102 1103        /// <summary>1104        /// Resolves the given path as an PSPath and ensures that it was resolved1105        /// by the FileSystemProvider.1106        /// </summary>1107        /// <param name="path">1108        /// The path to resolve.1109        /// </param>1110        /// <returns>1111        /// The path that was resolved. Null if the path couldn't be resolved or was1112        /// not resolved by the FileSystemProvider.1113        /// </returns>1114        private string? ResolvePSPath(string? path)1115        {1116            string? result = null;1117 1118            try1119            {1120                ProviderInfo? provider = null;1121                string? resolvedPath = null;1122 1123                // Try literal path resolution if it is set to run first1124                if (_commandResolutionOptions.HasFlag(SearchResolutionOptions.ResolveLiteralThenPathPatterns))1125                {1126                    // Cannot return early as this code path only expects1127                    // The file system provider and the final check for that1128                    // must verify this before we return.1129                    resolvedPath = GetNextLiteralPathThatExists(path, out provider);1130                }1131 1132                if (WildcardPattern.ContainsWildcardCharacters(path) &&1133                    ((resolvedPath == null) || (provider == null)))1134                {1135                    // Let PowerShell resolve relative path with wildcards.1136                    Collection<string> resolvedPaths = GetNextFromPathUsingWildcards(path, out provider);1137 1138                    if (resolvedPaths.Count == 0)1139                    {1140                        resolvedPath = null;1141 1142                        CommandDiscovery.discoveryTracer.TraceError(1143                           "The relative path with wildcard did not resolve to valid path. {0}",1144                           path);1145                    }1146                    else if (resolvedPaths.Count > 1)1147                    {1148                        resolvedPath = null;1149 1150                        CommandDiscovery.discoveryTracer.TraceError(1151                        "The relative path with wildcard resolved to multiple paths. {0}",1152                        path);1153                    }1154                    else1155                    {1156                        resolvedPath = resolvedPaths[0];1157                    }1158                }1159 1160                // Try literal path resolution if wildcards are enabled first and wildcard search failed1161                if (!_commandResolutionOptions.HasFlag(SearchResolutionOptions.ResolveLiteralThenPathPatterns) &&1162                    ((resolvedPath == null) || (provider == null)))1163                {1164                    resolvedPath = GetNextLiteralPathThatExists(path, out provider);1165                }1166 1167                // Verify the path was resolved to a file system path1168                if (provider != null && provider.NameEquals(_context.ProviderNames.FileSystem))1169                {1170                    result = resolvedPath;1171 1172                    CommandDiscovery.discoveryTracer.WriteLine(1173                        "The relative path was resolved to: {0}",1174                        result);1175                }1176                else1177                {1178                    // The path was not to the file system1179                    CommandDiscovery.discoveryTracer.TraceError(1180                        "The relative path was not a file system path. {0}",1181                        path);1182                }1183            }1184            catch (InvalidOperationException)1185            {1186                CommandDiscovery.discoveryTracer.TraceError(1187                    "The home path was not specified for the provider. {0}",1188                    path);1189            }1190            catch (ProviderInvocationException providerInvocationException)1191            {1192                CommandDiscovery.discoveryTracer.TraceError(1193                    "While resolving the path, \"{0}\", an error was encountered by the provider: {1}",1194                    path,1195                    providerInvocationException.Message);1196            }1197            catch (ItemNotFoundException)1198            {1199                CommandDiscovery.discoveryTracer.TraceError(1200                    "The path does not exist: {0}",

Showing the first 1,200 of 1734 lines. Download the file for the rest.