Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
RemoteDiscoveryHelper.cs1106 linesDownload Raw Back to Modules
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Concurrent;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Globalization;9using System.IO;10using System.Linq;11using System.Management.Automation.Language;12using System.Management.Automation.Runspaces;13using System.Net;14using System.Runtime.CompilerServices;15using System.Text.RegularExpressions;16using System.Threading;17using System.Xml;18 19using Microsoft.Management.Infrastructure;20using Microsoft.Management.Infrastructure.Options;21using Microsoft.PowerShell;22using Microsoft.PowerShell.Commands;23 24using Dbg = System.Management.Automation.Diagnostics;25 26namespace System.Management.Automation27{28    internal static class RemoteDiscoveryHelper29    {30        #region PSRP31 32        private static Collection<string> RehydrateHashtableKeys(PSObject pso, string propertyName)33        {34            const DeserializingTypeConverter.RehydrationFlags rehydrationFlags = DeserializingTypeConverter.RehydrationFlags.NullValueOk |35                                   DeserializingTypeConverter.RehydrationFlags.MissingPropertyOk;36            Hashtable hashtable = DeserializingTypeConverter.GetPropertyValue<Hashtable>(pso, propertyName, rehydrationFlags);37            if (hashtable == null)38            {39                return new Collection<string>();40            }41            else42            {43                List<string> list = hashtable44                    .Keys45                    .Cast<object>()46                    .Where(static k => k != null)47                    .Select(static k => k.ToString())48                    .Where(static s => s != null)49                    .ToList();50                return new Collection<string>(list);51            }52        }53 54        internal static PSModuleInfo RehydratePSModuleInfo(PSObject deserializedModuleInfo)55        {56            const DeserializingTypeConverter.RehydrationFlags rehydrationFlags = DeserializingTypeConverter.RehydrationFlags.NullValueOk |57                                   DeserializingTypeConverter.RehydrationFlags.MissingPropertyOk;58            string name = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "Name", rehydrationFlags);59            string path = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "Path", rehydrationFlags);60            PSModuleInfo moduleInfo = new PSModuleInfo(name, path, context: null, sessionState: null);61 62            moduleInfo.SetGuid(DeserializingTypeConverter.GetPropertyValue<Guid>(deserializedModuleInfo, "Guid", rehydrationFlags));63            moduleInfo.SetModuleType(DeserializingTypeConverter.GetPropertyValue<ModuleType>(deserializedModuleInfo, "ModuleType", rehydrationFlags));64            moduleInfo.SetVersion(DeserializingTypeConverter.GetPropertyValue<Version>(deserializedModuleInfo, "Version", rehydrationFlags));65            moduleInfo.SetHelpInfoUri(DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "HelpInfoUri", rehydrationFlags));66 67            moduleInfo.AccessMode = DeserializingTypeConverter.GetPropertyValue<ModuleAccessMode>(deserializedModuleInfo, "AccessMode", rehydrationFlags);68            moduleInfo.Author = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "Author", rehydrationFlags);69            moduleInfo.ClrVersion = DeserializingTypeConverter.GetPropertyValue<Version>(deserializedModuleInfo, "ClrVersion", rehydrationFlags);70            moduleInfo.CompanyName = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "CompanyName", rehydrationFlags);71            moduleInfo.Copyright = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "Copyright", rehydrationFlags);72            moduleInfo.Description = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "Description", rehydrationFlags);73            moduleInfo.DotNetFrameworkVersion = DeserializingTypeConverter.GetPropertyValue<Version>(deserializedModuleInfo, "DotNetFrameworkVersion", rehydrationFlags);74            moduleInfo.PowerShellHostName = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "PowerShellHostName", rehydrationFlags);75            moduleInfo.PowerShellHostVersion = DeserializingTypeConverter.GetPropertyValue<Version>(deserializedModuleInfo, "PowerShellHostVersion", rehydrationFlags);76            moduleInfo.PowerShellVersion = DeserializingTypeConverter.GetPropertyValue<Version>(deserializedModuleInfo, "PowerShellVersion", rehydrationFlags);77            moduleInfo.ProcessorArchitecture = DeserializingTypeConverter.GetPropertyValue<Reflection.ProcessorArchitecture>(deserializedModuleInfo, "ProcessorArchitecture", rehydrationFlags);78 79            moduleInfo.DeclaredAliasExports = RehydrateHashtableKeys(deserializedModuleInfo, "ExportedAliases");80            moduleInfo.DeclaredCmdletExports = RehydrateHashtableKeys(deserializedModuleInfo, "ExportedCmdlets");81            moduleInfo.DeclaredFunctionExports = RehydrateHashtableKeys(deserializedModuleInfo, "ExportedFunctions");82            moduleInfo.DeclaredVariableExports = RehydrateHashtableKeys(deserializedModuleInfo, "ExportedVariables");83 84            var compatiblePSEditions = DeserializingTypeConverter.GetPropertyValue<string[]>(deserializedModuleInfo, "CompatiblePSEditions", rehydrationFlags);85            if (compatiblePSEditions != null && compatiblePSEditions.Length > 0)86            {87                foreach (var edition in compatiblePSEditions)88                {89                    moduleInfo.AddToCompatiblePSEditions(edition);90                }91            }92 93            // PowerShellGet related properties94            var tags = DeserializingTypeConverter.GetPropertyValue<string[]>(deserializedModuleInfo, "Tags", rehydrationFlags);95            if (tags != null && tags.Length > 0)96            {97                foreach (var tag in tags)98                {99                    moduleInfo.AddToTags(tag);100                }101            }102 103            moduleInfo.ReleaseNotes = DeserializingTypeConverter.GetPropertyValue<string>(deserializedModuleInfo, "ReleaseNotes", rehydrationFlags);104            moduleInfo.ProjectUri = DeserializingTypeConverter.GetPropertyValue<Uri>(deserializedModuleInfo, "ProjectUri", rehydrationFlags);105            moduleInfo.LicenseUri = DeserializingTypeConverter.GetPropertyValue<Uri>(deserializedModuleInfo, "LicenseUri", rehydrationFlags);106            moduleInfo.IconUri = DeserializingTypeConverter.GetPropertyValue<Uri>(deserializedModuleInfo, "IconUri", rehydrationFlags);107            moduleInfo.RepositorySourceLocation = DeserializingTypeConverter.GetPropertyValue<Uri>(deserializedModuleInfo, "RepositorySourceLocation", rehydrationFlags);108 109            return moduleInfo;110        }111 112        private static EventHandler<DataAddedEventArgs> GetStreamForwarder<T>(Action<T> forwardingAction, bool swallowInvalidOperationExceptions = false)113        {114            // TODO/FIXME: ETW event for extended semantics streams115            return (object sender, DataAddedEventArgs eventArgs) =>116            {117                var psDataCollection = (PSDataCollection<T>)sender;118                foreach (T t in psDataCollection.ReadAll())119                {120                    try121                    {122                        forwardingAction(t);123                    }124                    catch (InvalidOperationException)125                    {126                        if (!swallowInvalidOperationExceptions)127                        {128                            throw;129                        }130                    }131                }132            };133        }134 135        // This is a static field (instead of a constant) to make it possible to set through tests (and/or by customers if needed for a workaround)136        private static readonly int s_blockingCollectionCapacity = 1000;137 138        private static IEnumerable<PSObject> InvokeTopLevelPowerShell(139            PowerShell powerShell,140            PSCmdlet cmdlet,141            PSInvocationSettings invocationSettings,142            string errorMessageTemplate,143            CancellationToken cancellationToken)144        {145            using (var mergedOutput = new BlockingCollection<Func<PSCmdlet, IEnumerable<PSObject>>>(s_blockingCollectionCapacity))146            {147                var asyncOutput = new PSDataCollection<PSObject>();148                EventHandler<DataAddedEventArgs> outputHandler = GetStreamForwarder<PSObject>(149                    output => mergedOutput.Add(_ => new[] { output }),150                    swallowInvalidOperationExceptions: true);151 152                EventHandler<DataAddedEventArgs> errorHandler = GetStreamForwarder<ErrorRecord>(153                    errorRecord => mergedOutput.Add(154                        (PSCmdlet c) =>155                        {156                            errorRecord = GetErrorRecordForRemotePipelineInvocation(errorRecord, errorMessageTemplate);157                            HandleErrorFromPipeline(c, errorRecord, powerShell);158                            return Enumerable.Empty<PSObject>();159                        }),160                     swallowInvalidOperationExceptions: true);161 162                EventHandler<DataAddedEventArgs> warningHandler = GetStreamForwarder<WarningRecord>(163                    warningRecord => mergedOutput.Add(164                        (PSCmdlet c) =>165                        {166                            c.WriteWarning(warningRecord.Message);167                            return Enumerable.Empty<PSObject>();168                        }),169                     swallowInvalidOperationExceptions: true);170 171                EventHandler<DataAddedEventArgs> verboseHandler = GetStreamForwarder<VerboseRecord>(172                    verboseRecord => mergedOutput.Add(173                        (PSCmdlet c) =>174                        {175                            c.WriteVerbose(verboseRecord.Message);176                            return Enumerable.Empty<PSObject>();177                        }),178                     swallowInvalidOperationExceptions: true);179 180                EventHandler<DataAddedEventArgs> debugHandler = GetStreamForwarder<DebugRecord>(181                    debugRecord => mergedOutput.Add(182                        (PSCmdlet c) =>183                        {184                            c.WriteDebug(debugRecord.Message);185                            return Enumerable.Empty<PSObject>();186                        }),187                     swallowInvalidOperationExceptions: true);188 189                EventHandler<DataAddedEventArgs> informationHandler = GetStreamForwarder<InformationRecord>(190                    informationRecord => mergedOutput.Add(191                        (PSCmdlet c) =>192                        {193                            c.WriteInformation(informationRecord);194                            return Enumerable.Empty<PSObject>();195                        }),196                     swallowInvalidOperationExceptions: true);197 198                asyncOutput.DataAdded += outputHandler;199                powerShell.Streams.Error.DataAdded += errorHandler;200                powerShell.Streams.Warning.DataAdded += warningHandler;201                powerShell.Streams.Verbose.DataAdded += verboseHandler;202                powerShell.Streams.Debug.DataAdded += debugHandler;203                powerShell.Streams.Information.DataAdded += informationHandler;204 205                try206                {207                    // TODO/FIXME: ETW event for PowerShell invocation208 209                    var asyncResult = powerShell.BeginInvoke<PSObject, PSObject>(210                        input: null,211                        output: asyncOutput,212                        settings: invocationSettings,213                        callback: delegate214                                  {215                                      try216                                      {217                                          mergedOutput.CompleteAdding();218                                      }219                                      catch (InvalidOperationException)220                                      // ignore exceptions thrown because mergedOutput.CompleteAdding was called221                                      {222                                      }223                                  },224                        state: null);225 226                    using (cancellationToken.Register(powerShell.Stop))227                    {228                        try229                        {230                            foreach (Func<PSCmdlet, IEnumerable<PSObject>> mergedOutputItem in mergedOutput.GetConsumingEnumerable())231                            {232                                foreach (PSObject outputObject in mergedOutputItem(cmdlet))233                                {234                                    yield return outputObject;235                                }236                            }237                        }238                        finally239                        {240                            mergedOutput.CompleteAdding();241                            powerShell.EndInvoke(asyncResult);242                        }243                    }244                }245                finally246                {247                    asyncOutput.DataAdded -= outputHandler;248                    powerShell.Streams.Error.DataAdded -= errorHandler;249                    powerShell.Streams.Warning.DataAdded -= warningHandler;250                    powerShell.Streams.Verbose.DataAdded -= verboseHandler;251                    powerShell.Streams.Debug.DataAdded -= debugHandler;252                    powerShell.Streams.Information.DataAdded -= informationHandler;253                }254            }255        }256 257        private static IEnumerable<PSObject> InvokeNestedPowerShell(258            PowerShell powerShell,259            PSCmdlet cmdlet,260            PSInvocationSettings invocationSettings,261            string errorMessageTemplate,262            CancellationToken cancellationToken)263        {264            EventHandler<DataAddedEventArgs> errorHandler = GetStreamForwarder<ErrorRecord>(265                (ErrorRecord errorRecord) =>266                {267                    errorRecord = GetErrorRecordForRemotePipelineInvocation(errorRecord, errorMessageTemplate);268                    HandleErrorFromPipeline(cmdlet, errorRecord, powerShell);269                });270            powerShell.Streams.Error.DataAdded += errorHandler;271 272            try273            {274                using (cancellationToken.Register(powerShell.Stop))275                {276                    // TODO/FIXME: ETW event for PowerShell invocation277 278                    foreach (PSObject outputObject in powerShell.Invoke<PSObject>(null, invocationSettings))279                    {280                        yield return outputObject;281                    }282                }283            }284            finally285            {286                powerShell.Streams.Error.DataAdded -= errorHandler;287            }288        }289 290        private static void CopyParameterFromCmdletToPowerShell(Cmdlet cmdlet, PowerShell powerShell, string parameterName)291        {292            object parameterValue;293            if (!cmdlet.MyInvocation.BoundParameters.TryGetValue(parameterName, out parameterValue))294            {295                return;296            }297 298            var commandParameter = new CommandParameter(parameterName, parameterValue);299            foreach (var command in powerShell.Commands.Commands)300            {301                if (command.Parameters.Any(existingParameter => existingParameter.Name.Equals(parameterName, StringComparison.OrdinalIgnoreCase)))302                {303                    continue;304                }305 306                command.Parameters.Add(commandParameter);307            }308        }309 310        internal static ErrorRecord GetErrorRecordForProcessingOfCimModule(Exception innerException, string moduleName)311        {312            string errorMessage = string.Format(313                CultureInfo.InvariantCulture,314                Modules.RemoteDiscoveryFailedToProcessRemoteModule,315                moduleName,316                innerException.Message);317 318            Exception outerException = new InvalidOperationException(errorMessage, innerException);319            ErrorRecord errorRecord = new ErrorRecord(outerException, innerException.GetType().Name, ErrorCategory.NotSpecified, moduleName);320            return errorRecord;321        }322 323        private const string DiscoveryProviderNotFoundErrorId = "DiscoveryProviderNotFound";324 325        private static ErrorRecord GetErrorRecordForRemoteDiscoveryProvider(Exception innerException)326        {327            CimException cimException = innerException as CimException;328            if ((cimException != null) &&329                ((cimException.NativeErrorCode == NativeErrorCode.InvalidNamespace) ||330                 (cimException.NativeErrorCode == NativeErrorCode.InvalidClass) ||331                 (cimException.NativeErrorCode == NativeErrorCode.MethodNotFound) ||332                 (cimException.NativeErrorCode == NativeErrorCode.MethodNotAvailable)))333            {334                string errorMessage = string.Format(335                    CultureInfo.InvariantCulture,336                    Modules.RemoteDiscoveryProviderNotFound,337                    innerException.Message);338                Exception outerException = new InvalidOperationException(errorMessage, innerException);339                ErrorRecord errorRecord = new ErrorRecord(outerException, DiscoveryProviderNotFoundErrorId, ErrorCategory.NotImplemented, null);340                return errorRecord;341            }342            else343            {344                string errorMessage = string.Format(345                    CultureInfo.InvariantCulture,346                    Modules.RemoteDiscoveryFailureFromDiscoveryProvider,347                    innerException.Message);348                Exception outerException = new InvalidOperationException(errorMessage, innerException);349                ErrorRecord errorRecord = new ErrorRecord(outerException, "DiscoveryProviderFailure", ErrorCategory.NotSpecified, null);350                return errorRecord;351            }352        }353 354        private static ErrorRecord GetErrorRecordForRemotePipelineInvocation(Exception innerException, string errorMessageTemplate)355        {356            string errorMessage = string.Format(357                CultureInfo.InvariantCulture,358                errorMessageTemplate,359                innerException.Message);360            Exception outerException = new InvalidOperationException(errorMessage, innerException);361 362            RemoteException remoteException = innerException as RemoteException;363            ErrorRecord remoteErrorRecord = remoteException?.ErrorRecord;364            string errorId = remoteErrorRecord != null ? remoteErrorRecord.FullyQualifiedErrorId : innerException.GetType().Name;365            ErrorCategory errorCategory = remoteErrorRecord != null ? remoteErrorRecord.CategoryInfo.Category : ErrorCategory.NotSpecified;366            ErrorRecord errorRecord = new ErrorRecord(outerException, errorId, errorCategory, null);367 368            return errorRecord;369        }370 371        private static ErrorRecord GetErrorRecordForRemotePipelineInvocation(ErrorRecord innerErrorRecord, string errorMessageTemplate)372        {373            string innerErrorMessage;374            if (innerErrorRecord.ErrorDetails != null && innerErrorRecord.ErrorDetails.Message != null)375            {376                innerErrorMessage = innerErrorRecord.ErrorDetails.Message;377            }378            else if (innerErrorRecord.Exception != null && innerErrorRecord.Exception.Message != null)379            {380                innerErrorMessage = innerErrorRecord.Exception.Message;381            }382            else383            {384                innerErrorMessage = innerErrorRecord.ToString();385            }386 387            string errorMessage = string.Format(388                CultureInfo.InvariantCulture,389                errorMessageTemplate,390                innerErrorMessage);391 392            ErrorRecord outerErrorRecord = new ErrorRecord(innerErrorRecord, null /* null means: do not replace the exception */);393            ErrorDetails outerErrorDetails = new ErrorDetails(errorMessage);394            outerErrorRecord.ErrorDetails = outerErrorDetails;395 396            return outerErrorRecord;397        }398 399        private static IEnumerable<T> EnumerateWithCatch<T>(IEnumerable<T> enumerable, Action<Exception> exceptionHandler)400        {401            IEnumerator<T> enumerator = null;402            try403            {404                enumerator = enumerable.GetEnumerator();405            }406            catch (Exception e)407            {408                exceptionHandler(e);409            }410 411            if (enumerator != null)412                using (enumerator)413                {414                    bool gotResults = false;415                    do416                    {417                        try418                        {419                            gotResults = false;420                            gotResults = enumerator.MoveNext();421                        }422                        catch (Exception e)423                        {424                            exceptionHandler(e);425                        }426 427                        if (gotResults)428                        {429                            T currentItem = default(T);430                            bool gotCurrentItem = false;431                            try432                            {433                                currentItem = enumerator.Current;434                                gotCurrentItem = true;435                            }436                            catch (Exception e)437                            {438                                exceptionHandler(e);439                            }440 441                            if (gotCurrentItem)442                            {443                                yield return currentItem;444                            }445                            else446                            {447                                yield break;448                            }449                        }450                    } while (gotResults);451                }452        }453 454        private static void HandleErrorFromPipeline(Cmdlet cmdlet, ErrorRecord errorRecord, PowerShell powerShell)455        {456            if (!cmdlet.MyInvocation.ExpectingInput)457            {458                if (((powerShell.Runspace != null) && (powerShell.Runspace.RunspaceStateInfo.State != RunspaceState.Opened)) ||459                    ((powerShell.RunspacePool != null) && (powerShell.RunspacePool.RunspacePoolStateInfo.State != RunspacePoolState.Opened)))460                {461                    cmdlet.ThrowTerminatingError(errorRecord);462                }463            }464 465            cmdlet.WriteError(errorRecord);466        }467 468        internal static IEnumerable<PSObject> InvokePowerShell(469            PowerShell powerShell,470            PSCmdlet cmdlet,471            string errorMessageTemplate,472            CancellationToken cancellationToken)473        {474            CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "ErrorAction");475            CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "WarningAction");476            CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "InformationAction");477            CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "Verbose");478            CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "Debug");479 480            var invocationSettings = new PSInvocationSettings { Host = cmdlet.Host };481 482            // TODO/FIXME: ETW events for the output stream483            IEnumerable<PSObject> outputStream = powerShell.IsNested484                ? InvokeNestedPowerShell(powerShell, cmdlet, invocationSettings, errorMessageTemplate, cancellationToken)485                : InvokeTopLevelPowerShell(powerShell, cmdlet, invocationSettings, errorMessageTemplate, cancellationToken);486 487            return EnumerateWithCatch(488                outputStream,489                (Exception exception) =>490                {491                    ErrorRecord errorRecord = GetErrorRecordForRemotePipelineInvocation(exception, errorMessageTemplate);492                    HandleErrorFromPipeline(cmdlet, errorRecord, powerShell);493                });494        }495 496        #endregion PSRP497 498        #region CIM499 500        private const string DiscoveryProviderNamespace = "root/Microsoft/Windows/Powershellv3";501        private const string DiscoveryProviderModuleClass = "PS_Module";502        private const string DiscoveryProviderFileClass = "PS_ModuleFile";503        private const string DiscoveryProviderAssociationClass = "PS_ModuleToModuleFile";504 505        private static T GetPropertyValue<T>(CimInstance cimInstance, string propertyName, T defaultValue)506        {507            CimProperty cimProperty = cimInstance.CimInstanceProperties[propertyName];508            if (cimProperty == null)509            {510                return defaultValue;511            }512 513            object propertyValue = cimProperty.Value;514            if (propertyValue is T)515            {516                return (T)propertyValue;517            }518 519            if (propertyValue is string)520            {521                string stringValue = (string)propertyValue;522                try523                {524                    if (typeof(T) == typeof(bool))525                    {526                        return (T)(object)XmlConvert.ToBoolean(stringValue);527                    }528                    else if (typeof(T) == typeof(UInt16))529                    {530                        return (T)(object)UInt16.Parse(stringValue, CultureInfo.InvariantCulture);531                    }532                    else if (typeof(T) == typeof(byte[]))533                    {534                        byte[] contentBytes = Convert.FromBase64String(stringValue);535                        byte[] lengthBytes = BitConverter.GetBytes(contentBytes.Length + 4);536                        if (BitConverter.IsLittleEndian)537                        {538                            Array.Reverse(lengthBytes);539                        }540 541                        return (T)(object)(lengthBytes.Concat(contentBytes).ToArray());542                    }543                }544                catch (Exception)545                {546                    return defaultValue;547                }548            }549 550            return defaultValue;551        }552 553        internal enum CimFileCode554        {555            Unknown = 0,556            PsdV1,557            TypesV1,558            FormatV1,559            CmdletizationV1,560        }561 562        internal abstract class CimModuleFile563        {564            public CimFileCode FileCode565            {566                get567                {568                    if (this.FileName.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase))569                    {570                        return CimFileCode.PsdV1;571                    }572 573                    if (this.FileName.EndsWith(".cdxml", StringComparison.OrdinalIgnoreCase))574                    {575                        return CimFileCode.CmdletizationV1;576                    }577 578                    if (this.FileName.EndsWith(".types.ps1xml", StringComparison.OrdinalIgnoreCase))579                    {580                        return CimFileCode.TypesV1;581                    }582 583                    if (this.FileName.EndsWith(".format.ps1xml", StringComparison.OrdinalIgnoreCase))584                    {585                        return CimFileCode.FormatV1;586                    }587 588                    return CimFileCode.Unknown;589                }590            }591 592            public abstract string FileName { get; }593 594            internal abstract byte[] RawFileDataCore { get; }595 596            public byte[] RawFileData597            {598                get { return this.RawFileDataCore.Skip(4).ToArray(); }599            }600 601            public string FileData602            {603                get604                {605                    if (_fileData == null)606                    {607                        using (var ms = new MemoryStream(this.RawFileData))608                        using (var sr = new StreamReader(ms, detectEncodingFromByteOrderMarks: true))609                        {610                            _fileData = sr.ReadToEnd();611                        }612                    }613 614                    return _fileData;615                }616            }617 618            private string _fileData;619        }620 621        internal class CimModule622        {623            private readonly CimInstance _baseObject;624 625            internal CimModule(CimInstance baseObject)626            {627                Dbg.Assert(baseObject != null, "Caller should make sure baseObject != null");628                Dbg.Assert(629                    baseObject.CimSystemProperties.ClassName.Equals(DiscoveryProviderModuleClass, StringComparison.OrdinalIgnoreCase),630                    "Caller should make sure baseObject is an instance of the right CIM class");631 632                _baseObject = baseObject;633            }634 635            public string ModuleName636            {637                get638                {639                    var rawModuleName = GetPropertyValue<string>(_baseObject, "ModuleName", string.Empty);640                    return Path.GetFileName(rawModuleName);641                }642            }643 644            private enum DiscoveredModuleType : ushort645            {646                Unknown = 0,647                Cim = 1,648            }649 650            public bool IsPsCimModule651            {652                get653                {654                    UInt16 moduleTypeInt = GetPropertyValue<UInt16>(_baseObject, "ModuleType", 0);655                    DiscoveredModuleType moduleType = (DiscoveredModuleType)moduleTypeInt;656                    bool isPsCimModule = (moduleType == DiscoveredModuleType.Cim);657                    return isPsCimModule;658                }659            }660 661            public CimModuleFile MainManifest662            {663                get664                {665                    byte[] rawFileData = GetPropertyValue<byte[]>(_baseObject, "moduleManifestFileData", Array.Empty<byte>());666                    return new CimModuleManifestFile(this.ModuleName + ".psd1", rawFileData);667                }668            }669 670            public IEnumerable<CimModuleFile> ModuleFiles671            {672                get { return _moduleFiles; }673            }674 675            internal void FetchAllModuleFiles(CimSession cimSession, string cimNamespace, CimOperationOptions operationOptions)676            {677                IEnumerable<CimInstance> associatedInstances = cimSession.EnumerateAssociatedInstances(678                    cimNamespace,679                    _baseObject,680                    DiscoveryProviderAssociationClass,681                    DiscoveryProviderFileClass,682                    "Antecedent",683                    "Dependent",684                    operationOptions);685 686                IEnumerable<CimModuleFile> associatedFiles = associatedInstances.Select(static i => new CimModuleImplementationFile(i));687                _moduleFiles = associatedFiles.ToList();688            }689 690            private List<CimModuleFile> _moduleFiles;691 692            private sealed class CimModuleManifestFile : CimModuleFile693            {694                internal CimModuleManifestFile(string fileName, byte[] rawFileData)695                {696                    Dbg.Assert(fileName != null, "Caller should make sure fileName != null");697                    Dbg.Assert(rawFileData != null, "Caller should make sure rawFileData != null");698 699                    FileName = fileName;700                    RawFileDataCore = rawFileData;701                }702 703                public override string FileName { get; }704 705                internal override byte[] RawFileDataCore { get; }706            }707 708            private sealed class CimModuleImplementationFile : CimModuleFile709            {710                private readonly CimInstance _baseObject;711 712                internal CimModuleImplementationFile(CimInstance baseObject)713                {714                    Dbg.Assert(baseObject != null, "Caller should make sure baseObject != null");715                    Dbg.Assert(716                        baseObject.CimSystemProperties.ClassName.Equals(DiscoveryProviderFileClass, StringComparison.OrdinalIgnoreCase),717                        "Caller should make sure baseObject is an instance of the right CIM class");718 719                    _baseObject = baseObject;720                }721 722                public override string FileName723                {724                    get725                    {726                        string rawFileName = GetPropertyValue<string>(_baseObject, "FileName", string.Empty);727                        return Path.GetFileName(rawFileName);728                    }729                }730 731                internal override byte[] RawFileDataCore732                {733                    get { return GetPropertyValue<byte[]>(_baseObject, "FileData", Array.Empty<byte>()); }734                }735            }736        }737 738        internal static IEnumerable<CimModule> GetCimModules(739            CimSession cimSession,740            Uri resourceUri,741            string cimNamespace,742            IEnumerable<string> moduleNamePatterns,743            bool onlyManifests,744            Cmdlet cmdlet,745            CancellationToken cancellationToken)746        {747            moduleNamePatterns ??= new[] { "*" };748            HashSet<string> alreadyEmittedNamesOfCimModules = new HashSet<string>(StringComparer.OrdinalIgnoreCase);749 750            IEnumerable<CimModule> remoteModules = moduleNamePatterns751                .SelectMany(moduleNamePattern =>752                    RemoteDiscoveryHelper.GetCimModules(cimSession, resourceUri, cimNamespace, moduleNamePattern, onlyManifests, cmdlet, cancellationToken));753            foreach (CimModule remoteModule in remoteModules)754            {755                if (!alreadyEmittedNamesOfCimModules.Contains(remoteModule.ModuleName))756                {757                    alreadyEmittedNamesOfCimModules.Add(remoteModule.ModuleName);758                    yield return remoteModule;759                }760            }761        }762 763        private static IEnumerable<CimModule> GetCimModules(764            CimSession cimSession,765            Uri resourceUri,766            string cimNamespace,767            string moduleNamePattern,768            bool onlyManifests,769            Cmdlet cmdlet,770            CancellationToken cancellationToken)771        {772            Dbg.Assert(cimSession != null, "Caller should verify cimSession != null");773            Dbg.Assert(moduleNamePattern != null, "Caller should verify that moduleNamePattern != null");774 775            const WildcardOptions wildcardOptions = WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant;776            var wildcardPattern = WildcardPattern.Get(moduleNamePattern, wildcardOptions);777            string dosWildcard = WildcardPatternToDosWildcardParser.Parse(wildcardPattern);778 779            var options = new CimOperationOptions { CancellationToken = cancellationToken };780            options.SetCustomOption("PS_ModuleNamePattern", dosWildcard, mustComply: false);781            if (resourceUri != null)782            {783                options.ResourceUri = resourceUri;784            }785 786            if (string.IsNullOrEmpty(cimNamespace) && (resourceUri == null))787            {788                cimNamespace = DiscoveryProviderNamespace;789            }790 791            // TODO/FIXME: ETW for method invocation792            IEnumerable<CimInstance> syncResults = cimSession.EnumerateInstances(793                cimNamespace,794                DiscoveryProviderModuleClass,795                options);796            // TODO/FIXME: ETW for method results797            IEnumerable<CimModule> cimModules = syncResults798                .Select(static cimInstance => new CimModule(cimInstance))799                .Where(cimModule => wildcardPattern.IsMatch(cimModule.ModuleName));800 801            if (!onlyManifests)802            {803                cimModules = cimModules.Select(804                    (CimModule cimModule) =>805                    {806                        cimModule.FetchAllModuleFiles(cimSession, cimNamespace, options);807                        return cimModule;808                    });809            }810 811            return EnumerateWithCatch(812                cimModules,813                (Exception exception) =>814                {815                    ErrorRecord errorRecord = GetErrorRecordForRemoteDiscoveryProvider(exception);816                    if (!cmdlet.MyInvocation.ExpectingInput)817                    {818                        if (errorRecord.FullyQualifiedErrorId.Contains(DiscoveryProviderNotFoundErrorId, StringComparison.OrdinalIgnoreCase)819                            || cancellationToken.IsCancellationRequested820                            || exception is OperationCanceledException821                            || !cimSession.TestConnection())822                        {823                            cmdlet.ThrowTerminatingError(errorRecord);824                        }825                    }826 827                    cmdlet.WriteError(errorRecord);828                });829        }830 831        internal static Hashtable RewriteManifest(Hashtable originalManifest)832        {833            return RewriteManifest(originalManifest, null, null, null);834        }835 836        private static readonly string[] s_manifestEntriesToKeepAsString = new[] {837            "GUID",838            "Author",839            "CompanyName",840            "Copyright",841            "ModuleVersion",842            "Description",843            "HelpInfoURI",844        };845 846        private static readonly string[] s_manifestEntriesToKeepAsStringArray = new[] {847            "FunctionsToExport",848            "VariablesToExport",849            "AliasesToExport",850            "CmdletsToExport",851        };852 853        internal static Hashtable RewriteManifest(854            Hashtable originalManifest,855            IEnumerable<string> nestedModules,856            IEnumerable<string> typesToProcess,857            IEnumerable<string> formatsToProcess)858        {859            nestedModules ??= Array.Empty<string>();860            typesToProcess ??= Array.Empty<string>();861            formatsToProcess ??= Array.Empty<string>();862 863            var newManifest = new Hashtable(StringComparer.OrdinalIgnoreCase);864            newManifest["NestedModules"] = nestedModules;865            newManifest["TypesToProcess"] = typesToProcess;866            newManifest["FormatsToProcess"] = formatsToProcess;867            newManifest["PrivateData"] = originalManifest["PrivateData"];868 869            foreach (DictionaryEntry entry in originalManifest)870            {871                if (s_manifestEntriesToKeepAsString.Contains(entry.Key as string, StringComparer.OrdinalIgnoreCase))872                {873                    var value = (string)LanguagePrimitives.ConvertTo(entry.Value, typeof(string), CultureInfo.InvariantCulture);874                    newManifest[entry.Key] = value;875                }876                else if (s_manifestEntriesToKeepAsStringArray.Contains(entry.Key as string, StringComparer.OrdinalIgnoreCase))877                {878                    var values = (string[])LanguagePrimitives.ConvertTo(entry.Value, typeof(string[]), CultureInfo.InvariantCulture);879                    newManifest[entry.Key] = values;880                }881            }882 883            return newManifest;884        }885 886        private static CimCredential GetCimCredentials(PasswordAuthenticationMechanism authenticationMechanism, PSCredential credential)887        {888            NetworkCredential networkCredential = credential.GetNetworkCredential();889            return new CimCredential(authenticationMechanism, networkCredential.Domain, networkCredential.UserName, credential.Password);890        }891 892        private static Exception GetExceptionWhenAuthenticationRequiresCredential(string authentication)893        {894            string errorMessage = string.Format(895                CultureInfo.InvariantCulture,896                RemotingErrorIdStrings.AuthenticationMechanismRequiresCredential,897                authentication);898            throw new ArgumentException(errorMessage);899        }900 901        private static CimCredential GetCimCredentials(string authentication, PSCredential credential)902        {903            if (authentication == null || (authentication.Equals("Default", StringComparison.OrdinalIgnoreCase)))904            {905                if (credential == null)906                {907                    return null;908                }909                else910                {911                    return GetCimCredentials(PasswordAuthenticationMechanism.Default, credential);912                }913            }914 915            if (authentication.Equals("Basic", StringComparison.OrdinalIgnoreCase))916            {917                if (credential == null)918                {919                    throw GetExceptionWhenAuthenticationRequiresCredential(authentication);920                }921                else922                {923                    return GetCimCredentials(PasswordAuthenticationMechanism.Basic, credential);924                }925            }926 927            if (authentication.Equals("Negotiate", StringComparison.OrdinalIgnoreCase))928            {929                if (credential == null)930                {931                    return new CimCredential(ImpersonatedAuthenticationMechanism.Negotiate);932                }933                else934                {935                    return GetCimCredentials(PasswordAuthenticationMechanism.Negotiate, credential);936                }937            }938 939            if (authentication.Equals("CredSSP", StringComparison.OrdinalIgnoreCase))940            {941                if (credential == null)942                {943                    throw GetExceptionWhenAuthenticationRequiresCredential(authentication);944                }945                else946                {947                    return GetCimCredentials(PasswordAuthenticationMechanism.CredSsp, credential);948                }949            }950 951            if (authentication.Equals("Digest", StringComparison.OrdinalIgnoreCase))952            {953                if (credential == null)954                {955                    throw GetExceptionWhenAuthenticationRequiresCredential(authentication);956                }957                else958                {959                    return GetCimCredentials(PasswordAuthenticationMechanism.Digest, credential);960                }961            }962 963            if (authentication.Equals("Kerberos", StringComparison.OrdinalIgnoreCase))964            {965                if (credential == null)966                {967                    return new CimCredential(ImpersonatedAuthenticationMechanism.Kerberos);968                }969                else970                {971                    return GetCimCredentials(PasswordAuthenticationMechanism.Kerberos, credential);972                }973            }974 975            Dbg.Assert(false, "Unrecognized authentication mechanism [ValidateSet should prevent that from happening]");976            throw new ArgumentOutOfRangeException(nameof(authentication));977        }978 979        internal static CimSession CreateCimSession(980            string computerName,981            PSCredential credential,982            string authentication,983            bool isLocalHost,984            PSCmdlet cmdlet,985            CancellationToken cancellationToken)986        {987            if (isLocalHost)988            {989                return CimSession.Create(null);990            }991 992            var sessionOptions = new CimSessionOptions();993 994            CimCredential cimCredentials = GetCimCredentials(authentication, credential);995            if (cimCredentials != null)996            {997                sessionOptions.AddDestinationCredentials(cimCredentials);998            }999 1000            CimSession cimSession = CimSession.Create(computerName, sessionOptions);1001            return cimSession;1002        }1003 1004        internal static Hashtable ConvertCimModuleFileToManifestHashtable(RemoteDiscoveryHelper.CimModuleFile cimModuleFile, string temporaryModuleManifestPath, ModuleCmdletBase cmdlet, ref bool containedErrors)1005        {1006            Dbg.Assert(cimModuleFile.FileCode == RemoteDiscoveryHelper.CimFileCode.PsdV1, "Caller should verify the file is of the right type");1007 1008            ScriptBlockAst scriptBlockAst = null;1009            if (!containedErrors)1010            {1011                System.Management.Automation.Language.Token[] throwAwayTokens;1012                ParseError[] parseErrors;1013                scriptBlockAst = System.Management.Automation.Language.Parser.ParseInput(cimModuleFile.FileData, temporaryModuleManifestPath, out throwAwayTokens, out parseErrors);1014                if ((scriptBlockAst == null) || (parseErrors != null && parseErrors.Length > 0))1015                {1016                    containedErrors = true;1017                }1018            }1019 1020            Hashtable data = null;1021            if (!containedErrors)1022            {1023                ScriptBlock scriptBlock = new ScriptBlock(scriptBlockAst, isFilter: false);1024                data = cmdlet.LoadModuleManifestData(1025                    temporaryModuleManifestPath,1026                    scriptBlock,1027                    ModuleCmdletBase.ModuleManifestMembers,1028                    0 /* - don't write errors, don't load elements, don't return null on first error */,1029                    ref containedErrors);1030            }1031 1032            return data;1033        }1034 1035        #endregion CIM1036 1037        #region Protocol/transport agnostic functionality1038 1039        internal static string GetModulePath(string remoteModuleName, Version remoteModuleVersion, string computerName, Runspace localRunspace)1040        {1041            computerName ??= string.Empty;1042 1043            string sanitizedRemoteModuleName = Regex.Replace(remoteModuleName, "[^a-zA-Z0-9]", string.Empty);1044            string sanitizedComputerName = Regex.Replace(computerName, "[^a-zA-Z0-9]", string.Empty);1045            string moduleName = string.Format(1046                CultureInfo.InvariantCulture,1047                "remoteIpMoProxy_{0}_{1}_{2}_{3}",1048                sanitizedRemoteModuleName.Substring(0, Math.Min(sanitizedRemoteModuleName.Length, 100)),1049                remoteModuleVersion,1050                sanitizedComputerName.Substring(0, Math.Min(sanitizedComputerName.Length, 100)),1051                localRunspace.InstanceId);1052            string modulePath = Path.Combine(Path.GetTempPath(), moduleName);1053            return modulePath;1054        }1055 1056        internal static void AssociatePSModuleInfoWithSession(PSModuleInfo moduleInfo, CimSession cimSession, Uri resourceUri, string cimNamespace)1057        {1058            AssociatePSModuleInfoWithSession(moduleInfo, (object)new Tuple<CimSession, Uri, string>(cimSession, resourceUri, cimNamespace));1059        }1060 1061        internal static void AssociatePSModuleInfoWithSession(PSModuleInfo moduleInfo, PSSession psSession)1062        {1063            AssociatePSModuleInfoWithSession(moduleInfo, (object)psSession);1064        }1065 1066        private static void AssociatePSModuleInfoWithSession(PSModuleInfo moduleInfo, object weaklyTypedSession)1067        {1068            s_moduleInfoToSession.Add(moduleInfo, weaklyTypedSession);1069        }1070 1071        private static readonly ConditionalWeakTable<PSModuleInfo, object> s_moduleInfoToSession = new ConditionalWeakTable<PSModuleInfo, object>();1072 1073        internal static void DispatchModuleInfoProcessing(1074            PSModuleInfo moduleInfo,1075            Action localAction,1076            Action<CimSession, Uri, string> cimSessionAction,1077            Action<PSSession> psSessionAction)1078        {1079            object weaklyTypeSession;1080            if (!s_moduleInfoToSession.TryGetValue(moduleInfo, out weaklyTypeSession))1081            {1082                localAction();1083                return;1084            }1085 1086            Tuple<CimSession, Uri, string> cimSessionInfo = weaklyTypeSession as Tuple<CimSession, Uri, string>;1087            if (cimSessionInfo != null)1088            {1089                cimSessionAction(cimSessionInfo.Item1, cimSessionInfo.Item2, cimSessionInfo.Item3);1090                return;1091            }1092 1093            PSSession psSession = weaklyTypeSession as PSSession;1094            if (psSession != null)1095            {1096                psSessionAction(psSession);1097                return;1098            }1099 1100            Dbg.Assert(false, "PSModuleInfo was associated with an unrecognized session type");1101        }1102 1103        #endregion1104    }1105}1106