Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
PSClassSearcher.cs330 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.IO;8using System.Management.Automation.Internal;9using System.Management.Automation.Language;10 11using Dbg = System.Management.Automation.Diagnostics;12 13namespace System.Management.Automation14{15    /// <summary>16    /// Searcher class for finding PS classes on the system.17    /// </summary>18    internal class PSClassSearcher : IEnumerable<PSClassInfo>, IEnumerator<PSClassInfo>19    {20        internal PSClassSearcher(21            string className,22            bool useWildCards,23            ExecutionContext context)24        {25            Diagnostics.Assert(context != null, "caller to verify context is not null");26            _context = context;27 28            Diagnostics.Assert(className != null, "caller to verify className is not null");29            _className = className;30            _useWildCards = useWildCards;31            _moduleInfoCache = new Dictionary<string, PSModuleInfo>(StringComparer.OrdinalIgnoreCase);32        }33 34        #region private properties35 36        private readonly string _className = null;37        private readonly ExecutionContext _context = null;38        private PSClassInfo _currentMatch = null;39        private IEnumerator<PSClassInfo> _matchingClass = null;40        private Collection<PSClassInfo> _matchingClassList = null;41        private readonly bool _useWildCards = false;42        private readonly Dictionary<string, PSModuleInfo> _moduleInfoCache = null;43        private readonly object _lockObject = new object();44 45        #endregion46 47        #region public methods48 49        /// <summary>50        /// Reset the Iterator.51        /// </summary>52        public void Reset()53        {54            _currentMatch = null;55            _matchingClass = null;56        }57 58        /// <summary>59        /// Reset and dispose the Iterator.60        /// </summary>61        public void Dispose()62        {63            Reset();64            GC.SuppressFinalize(this);65        }66 67        /// <summary>68        /// Get the Enumerator.69        /// </summary>70        /// <returns></returns>71        IEnumerator<PSClassInfo> IEnumerable<PSClassInfo>.GetEnumerator()72        {73            return this;74        }75 76        /// <summary>77        /// Get the Enumerator.78        /// </summary>79        /// <returns></returns>80        IEnumerator IEnumerable.GetEnumerator()81        {82            return this;83        }84 85        /// <summary>86        /// Move to the Next value in the enumerator.87        /// </summary>88        /// <returns></returns>89        public bool MoveNext()90        {91            _currentMatch = GetNextClass();92 93            if (_currentMatch != null)94                return true;95 96            return false;97        }98 99        /// <summary>100        /// Return the current PSClassInfo.101        /// </summary>102        PSClassInfo IEnumerator<PSClassInfo>.Current103        {104            get105            {106                return _currentMatch;107            }108        }109 110        /// <summary>111        /// Return the current PSClassInfo as object.112        /// </summary>113        object IEnumerator.Current114        {115            get116            {117                return ((IEnumerator<PSClassInfo>)this).Current;118            }119        }120 121        #endregion122 123        #region private methods124 125        /// <summary>126        /// Get all modules and find the matching type127        /// When found add them to the enumerator. If we have already got it, return the next resource.128        /// </summary>129        /// <returns>Next PSClassInfo object or null if none are found.</returns>130        private PSClassInfo GetNextClass()131        {132            PSClassInfo returnValue = null;133            WildcardPattern classNameMatcher = WildcardPattern.Get(_className, WildcardOptions.IgnoreCase);134 135            if (_matchingClassList == null)136            {137                _matchingClassList = new Collection<PSClassInfo>();138 139                if (FindTypeByModulePath(classNameMatcher))140                    _matchingClass = _matchingClassList.GetEnumerator();141                else142                    return null;143            }144 145            if (!_matchingClass.MoveNext())146            {147                _matchingClass = null;148            }149            else150            {151                returnValue = _matchingClass.Current;152            }153 154            return returnValue;155        }156 157        private bool FindTypeByModulePath(WildcardPattern classNameMatcher)158        {159            bool matchFound = false;160 161            var moduleList = ModuleUtils.GetDefaultAvailableModuleFiles(isForAutoDiscovery: false, _context);162 163            foreach (var modulePath in moduleList)164            {165                string expandedModulePath = IO.Path.GetFullPath(modulePath);166                var cachedClasses = AnalysisCache.GetExportedClasses(expandedModulePath, _context);167 168                if (cachedClasses != null)169                {170                    // Exact match171                    if (!_useWildCards)172                    {173                        if (cachedClasses.ContainsKey(_className))174                        {175                            var classInfo = CachedItemToPSClassInfo(classNameMatcher, modulePath);176                            if (classInfo != null)177                            {178                                _matchingClassList.Add(classInfo);179                                matchFound = true;180                            }181                        }182                    }183                    else184                    {185                        foreach (var className in cachedClasses.Keys)186                        {187                            if (classNameMatcher.IsMatch(className))188                            {189                                var classInfo = CachedItemToPSClassInfo(classNameMatcher, modulePath);190                                if (classInfo != null)191                                {192                                    _matchingClassList.Add(classInfo);193                                    matchFound = true;194                                }195                            }196                        }197                    }198                }199            }200 201            return matchFound;202        }203 204        /// <summary>205        /// Convert the cacheItem to a PSClassInfo object.206        /// For this, we call Get-Module -List with module name.207        /// </summary>208        /// <param name="classNameMatcher">Wildcard pattern matcher for comparing class name.</param>209        /// <param name="modulePath">Path to the module where the class is defined.</param>210        /// <returns>Converted PSClassInfo object.</returns>211        private PSClassInfo CachedItemToPSClassInfo(WildcardPattern classNameMatcher, string modulePath)212        {213            foreach (var module in GetPSModuleInfo(modulePath))214            {215                var exportedTypes = module.GetExportedTypeDefinitions();216 217                ScriptBlockAst ast = null;218                TypeDefinitionAst typeAst = null;219 220                if (!_useWildCards)221                {222                    if (exportedTypes.TryGetValue(_className, out typeAst))223                    {224                        ast = typeAst.Parent.Parent as ScriptBlockAst;225                        if (ast != null)226                            return ConvertToClassInfo(module, ast, typeAst);227                    }228                }229                else230                {231                    foreach (var exportedType in exportedTypes)232                    {233                        if (exportedType.Value != null &&234                            classNameMatcher.IsMatch(exportedType.Value.Name) &&235                            exportedType.Value.IsClass)236                        {237                            ast = exportedType.Value.Parent.Parent as ScriptBlockAst;238                            if (ast != null)239                                return ConvertToClassInfo(module, ast, exportedType.Value);240                        }241                    }242                }243            }244 245            return null;246        }247 248        private Collection<PSModuleInfo> GetPSModuleInfo(string modulePath)249        {250            PSModuleInfo moduleInfo = null;251 252            lock (_lockObject)253            {254                _moduleInfoCache.TryGetValue(modulePath, out moduleInfo);255            }256 257            if (moduleInfo != null)258            {259                var returnValue = new Collection<PSModuleInfo>();260                returnValue.Add(moduleInfo);261                return returnValue;262            }263 264            CommandInfo commandInfo = new CmdletInfo("Get-Module", typeof(Microsoft.PowerShell.Commands.GetModuleCommand), null, null, _context);265            System.Management.Automation.Runspaces.Command getModuleCommand = new System.Management.Automation.Runspaces.Command(commandInfo);266 267            string moduleName = Path.GetFileNameWithoutExtension(modulePath);268 269            var modules = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)270                .AddCommand(getModuleCommand)271                    .AddParameter("List", true)272                    .AddParameter("Name", moduleName)273                    .AddParameter("ErrorAction", ActionPreference.Ignore)274                    .AddParameter("WarningAction", ActionPreference.Ignore)275                    .AddParameter("InformationAction", ActionPreference.Ignore)276                    .AddParameter("Verbose", false)277                    .AddParameter("Debug", false)278                    .Invoke<PSModuleInfo>();279 280            lock (_lockObject)281            {282                foreach (var module in modules)283                {284                    _moduleInfoCache.Add(module.Path, module);285                }286            }287 288            return modules;289        }290 291        private static PSClassInfo ConvertToClassInfo(PSModuleInfo module, ScriptBlockAst ast, TypeDefinitionAst statement)292        {293            PSClassInfo classInfo = new PSClassInfo(statement.Name);294            Dbg.Assert(statement.Name != null, "statement should have a name.");295            classInfo.Module = module;296            Collection<PSClassMemberInfo> properties = new Collection<PSClassMemberInfo>();297 298            foreach (var member in statement.Members)299            {300                if (member is PropertyMemberAst propAst && !propAst.PropertyAttributes.HasFlag(PropertyAttributes.Hidden))301                {302                    Dbg.Assert(propAst.Name != null, "PropName cannot be null");303                    Dbg.Assert(propAst.PropertyType != null, "PropertyType cannot be null");304                    Dbg.Assert(propAst.PropertyType.TypeName != null, "Property TypeName cannot be null");305                    Dbg.Assert(propAst.Extent != null, "Property Extent cannot be null");306                    Dbg.Assert(propAst.Extent.Text != null, "Property ExtentText cannot be null");307 308                    PSClassMemberInfo classProperty = new PSClassMemberInfo(propAst.Name,309                                                                          propAst.PropertyType.TypeName.FullName,310                                                                          propAst.Extent.Text);311                    properties.Add(classProperty);312                }313            }314 315            classInfo.UpdateMembers(properties);316 317            string mamlHelpFile = null;318            if (ast.GetHelpContent() != null)319                mamlHelpFile = ast.GetHelpContent().MamlHelpFile;320 321            if (!string.IsNullOrEmpty(mamlHelpFile))322                classInfo.HelpFile = mamlHelpFile;323 324            return classInfo;325        }326 327        #endregion328    }329}330