Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
InternalCommands.cs2846 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Dynamic;8using System.Globalization;9using System.Linq.Expressions;10using System.Management.Automation;11using System.Management.Automation.Internal;12using System.Management.Automation.Language;13using System.Management.Automation.PSTasks;14using System.Management.Automation.Security;15using System.Runtime.CompilerServices;16using System.Text;17using System.Threading;18 19using CommonParamSet = System.Management.Automation.Internal.CommonParameters;20using Dbg = System.Management.Automation.Diagnostics;21using NotNullWhen = System.Diagnostics.CodeAnalysis.NotNullWhenAttribute;22 23namespace Microsoft.PowerShell.Commands24{25    /// <summary>26    /// A thin wrapper over a property-getting Callsite, to allow reuse when possible.27    /// </summary>28    internal struct DynamicPropertyGetter29    {30        private CallSite<Func<CallSite, object, object>> _getValueDynamicSite;31 32        // For the wildcard case, lets us know if we can reuse the callsite:33        private string _lastUsedPropertyName;34 35        public object GetValue(PSObject inputObject, string propertyName)36        {37            Dbg.Assert(!WildcardPattern.ContainsWildcardCharacters(propertyName), "propertyName should be pre-resolved by caller");38 39            // If wildcards are involved, the resolved property name could potentially40            // be different on every object... but probably not, so we'll attempt to41            // reuse the callsite if possible.42            if (!propertyName.Equals(_lastUsedPropertyName, StringComparison.OrdinalIgnoreCase))43            {44                _lastUsedPropertyName = propertyName;45                _getValueDynamicSite = CallSite<Func<CallSite, object, object>>.Create(46                        PSGetMemberBinder.Get(47                            propertyName,48                            classScope: (Type)null,49                            @static: false));50            }51 52            return _getValueDynamicSite.Target.Invoke(_getValueDynamicSite, inputObject);53        }54    }55 56    #region Built-in cmdlets that are used by or require direct access to the engine.57 58    /// <summary>59    /// Implements a cmdlet that applies a script block60    /// to each element of the pipeline.61    /// </summary>62    [Cmdlet("ForEach", "Object", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low,63        DefaultParameterSetName = ForEachObjectCommand.ScriptBlockSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096867",64        RemotingCapability = RemotingCapability.None)]65    public sealed class ForEachObjectCommand : PSCmdlet, IDisposable66    {67        #region Private Members68 69        private const string ParallelParameterSet = "ParallelParameterSet";70        private const string ScriptBlockSet = "ScriptBlockSet";71        private const string PropertyAndMethodSet = "PropertyAndMethodSet";72 73        #endregion74 75        #region Common Parameters76 77        /// <summary>78        /// This parameter specifies the current pipeline object.79        /// </summary>80        [Parameter(ValueFromPipeline = true, ParameterSetName = ForEachObjectCommand.ScriptBlockSet)]81        [Parameter(ValueFromPipeline = true, ParameterSetName = ForEachObjectCommand.PropertyAndMethodSet)]82        [Parameter(ValueFromPipeline = true, ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]83        public PSObject InputObject84        {85            get { return _inputObject; }86 87            set { _inputObject = value; }88        }89 90        private PSObject _inputObject = AutomationNull.Value;91 92        #endregion93 94        #region ScriptBlockSet95 96        private readonly List<ScriptBlock> _scripts = new List<ScriptBlock>();97 98        /// <summary>99        /// Gets or sets the script block to apply in begin processing.100        /// </summary>101        [Parameter(ParameterSetName = ForEachObjectCommand.ScriptBlockSet)]102        public ScriptBlock Begin103        {104            get105            {106                return null;107            }108 109            set110            {111                _scripts.Insert(0, value);112            }113        }114 115        /// <summary>116        /// Gets or sets the script block to apply.117        /// </summary>118        [Parameter(Mandatory = true, Position = 0, ParameterSetName = ForEachObjectCommand.ScriptBlockSet)]119        [AllowNull]120        [AllowEmptyCollection]121        public ScriptBlock[] Process122        {123            get124            {125                return null;126            }127 128            set129            {130                if (value == null)131                {132                    _scripts.Add(null);133                }134                else135                {136                    _scripts.AddRange(value);137                }138            }139        }140 141        private ScriptBlock _endScript;142        private bool _setEndScript;143 144        /// <summary>145        /// Gets or sets the script block to apply in complete processing.146        /// </summary>147        [Parameter(ParameterSetName = ForEachObjectCommand.ScriptBlockSet)]148        public ScriptBlock End149        {150            get151            {152                return _endScript;153            }154 155            set156            {157                _endScript = value;158                _setEndScript = true;159            }160        }161 162        /// <summary>163        /// Gets or sets the remaining script blocks to apply.164        /// </summary>165        [Parameter(ParameterSetName = ForEachObjectCommand.ScriptBlockSet, ValueFromRemainingArguments = true)]166        [AllowNull]167        [AllowEmptyCollection]168        public ScriptBlock[] RemainingScripts169        {170            get171            {172                return null;173            }174 175            set176            {177                if (value == null)178                {179                    _scripts.Add(null);180                }181                else182                {183                    _scripts.AddRange(value);184                }185            }186        }187 188        private int _start, _end;189 190        #endregion ScriptBlockSet191 192        #region PropertyAndMethodSet193 194        /// <summary>195        /// Gets or sets the property or method name.196        /// </summary>197        [Parameter(Mandatory = true, Position = 0, ParameterSetName = ForEachObjectCommand.PropertyAndMethodSet)]198        [ValidateTrustedData]199        [ValidateNotNullOrEmpty]200        public string MemberName201        {202            get203            {204                return _propertyOrMethodName;205            }206 207            set208            {209                _propertyOrMethodName = value;210            }211        }212 213        private string _propertyOrMethodName;214        private string _targetString;215        private DynamicPropertyGetter _propGetter;216 217        /// <summary>218        /// The arguments passed to a method invocation.219        /// </summary>220        [Parameter(ParameterSetName = ForEachObjectCommand.PropertyAndMethodSet, ValueFromRemainingArguments = true)]221        [ValidateTrustedData]222        [Alias("Args")]223        public object[] ArgumentList224        {225            get { return _arguments; }226 227            set { _arguments = value; }228        }229 230        private object[] _arguments;231 232        #endregion PropertyAndMethodSet233 234        #region ParallelParameterSet235 236        /// <summary>237        /// Gets or sets a script block to run in parallel for each pipeline object.238        /// </summary>239        [Parameter(Mandatory = true, ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]240        public ScriptBlock Parallel { get; set; }241 242        /// <summary>243        /// Gets or sets the maximum number of concurrently running scriptblocks on separate threads.244        /// The default number is 5.245        /// </summary>246        [Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]247        [ValidateRange(1, Int32.MaxValue)]248        public int ThrottleLimit { get; set; } = 5;249 250        /// <summary>251        /// Gets or sets a timeout time in seconds, after which the parallel running scripts will be stopped252        /// The default value is 0, indicating no timeout.253        /// </summary>254        [Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]255        [ValidateRange(0, (Int32.MaxValue / 1000))]256        public int TimeoutSeconds { get; set; }257 258        /// <summary>259        /// Gets or sets a flag that returns a job object immediately for the parallel operation, instead of returning after260        /// all foreach processing is completed.261        /// </summary>262        [Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]263        public SwitchParameter AsJob { get; set; }264 265        /// <summary>266        /// Gets or sets a flag so that a new runspace object is created for each loop iteration, instead of reusing objects267        /// from the runspace pool.268        /// By default, runspaces are reused from a runspace pool.269        /// </summary>270        [Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]271        public SwitchParameter UseNewRunspace { get; set; }272 273        #endregion274 275        #region Overrides276 277        /// <summary>278        /// Execute the begin scriptblock at the start of processing.279        /// </summary>280        /// <exception cref="ParseException">Could not parse script.</exception>281        /// <exception cref="RuntimeException">See Pipeline.Invoke.</exception>282        /// <exception cref="ParameterBindingException">See Pipeline.Invoke.</exception>283        protected override void BeginProcessing()284        {285            switch (ParameterSetName)286            {287                case ForEachObjectCommand.ScriptBlockSet:288                    InitScriptBlockParameterSet();289                    break;290 291                case ForEachObjectCommand.ParallelParameterSet:292                    InitParallelParameterSet();293                    break;294            }295        }296 297        /// <summary>298        /// Execute the processing script blocks on the current pipeline object299        /// which is passed as it's only parameter.300        /// </summary>301        /// <exception cref="ParseException">Could not parse script.</exception>302        /// <exception cref="RuntimeException">See Pipeline.Invoke.</exception>303        /// <exception cref="ParameterBindingException">See Pipeline.Invoke.</exception>304        protected override void ProcessRecord()305        {306            switch (ParameterSetName)307            {308                case ForEachObjectCommand.ScriptBlockSet:309                    ProcessScriptBlockParameterSet();310                    break;311 312                case ForEachObjectCommand.PropertyAndMethodSet:313                    ProcessPropertyAndMethodParameterSet();314                    break;315 316                case ForEachObjectCommand.ParallelParameterSet:317                    ProcessParallelParameterSet();318                    break;319            }320        }321 322        /// <summary>323        /// Execute the end scriptblock when the pipeline is complete.324        /// </summary>325        /// <exception cref="ParseException">Could not parse script.</exception>326        /// <exception cref="RuntimeException">See Pipeline.Invoke.</exception>327        /// <exception cref="ParameterBindingException">See Pipeline.Invoke.</exception>328        protected override void EndProcessing()329        {330            switch (ParameterSetName)331            {332                case ForEachObjectCommand.ScriptBlockSet:333                    EndBlockParameterSet();334                    break;335 336                case ForEachObjectCommand.ParallelParameterSet:337                    EndParallelParameterSet();338                    break;339            }340        }341 342        /// <summary>343        /// Handle pipeline stop signal.344        /// </summary>345        protected override void StopProcessing()346        {347            switch (ParameterSetName)348            {349                case ForEachObjectCommand.ParallelParameterSet:350                    StopParallelProcessing();351                    break;352            }353        }354 355        #endregion356 357        #region IDisposable358 359        /// <summary>360        /// Dispose cmdlet instance.361        /// </summary>362        public void Dispose()363        {364            // Ensure all parallel task objects are disposed365            _taskTimer?.Dispose();366            _taskDataStreamWriter?.Dispose();367            _taskPool?.Dispose();368            _taskCollection?.Dispose();369        }370 371        #endregion372 373        #region Private Methods374 375        #region PSTasks376 377        private PSTaskPool _taskPool;378        private PSTaskDataStreamWriter _taskDataStreamWriter;379        private Dictionary<string, object> _usingValuesMap;380        private Timer _taskTimer;381        private PSTaskJob _taskJob;382        private PSDataCollection<System.Management.Automation.PSTasks.PSTask> _taskCollection;383        private Exception _taskCollectionException;384        private string _currentLocationPath;385 386        private void InitParallelParameterSet()387        {388            // The following common parameters are not (yet) supported in this parameter set.389            //  ErrorAction, WarningAction, InformationAction, ProgressAction, PipelineVariable.390            if (MyInvocation.BoundParameters.ContainsKey(nameof(CommonParamSet.ErrorAction)) ||391                MyInvocation.BoundParameters.ContainsKey(nameof(CommonParamSet.WarningAction)) ||392                MyInvocation.BoundParameters.ContainsKey(nameof(CommonParamSet.InformationAction)) ||393                MyInvocation.BoundParameters.ContainsKey(nameof(CommonParamSet.ProgressAction)) ||394                MyInvocation.BoundParameters.ContainsKey(nameof(CommonParamSet.PipelineVariable)))395            {396                ThrowTerminatingError(397                        new ErrorRecord(398                            new PSNotSupportedException(InternalCommandStrings.ParallelCommonParametersNotSupported),399                            "ParallelCommonParametersNotSupported",400                            ErrorCategory.NotImplemented,401                            this));402            }403 404            // Get the current working directory location, if available.405            try406            {407                _currentLocationPath = SessionState.Internal.CurrentLocation.Path;408            }409            catch (PSInvalidOperationException)410            {411            }412 413            var allowUsingExpression = this.Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage;414            _usingValuesMap = ScriptBlockToPowerShellConverter.GetUsingValuesForEachParallel(415                scriptBlock: Parallel,416                isTrustedInput: allowUsingExpression,417                context: this.Context);418 419            // Validate using values map, which is a map of '$using:' variables referenced in the script.420            // Script block variables are not allowed since their behavior is undefined outside the runspace421            // in which they were created.422            foreach (object item in _usingValuesMap.Values)423            {424                if (item is ScriptBlock or PSObject { BaseObject: ScriptBlock })425                {426                    ThrowTerminatingError(427                        new ErrorRecord(428                            new PSArgumentException(InternalCommandStrings.ParallelUsingVariableCannotBeScriptBlock),429                            "ParallelUsingVariableCannotBeScriptBlock",430                            ErrorCategory.InvalidType,431                            this));432                }433            }434 435            if (AsJob)436            {437                // Set up for returning a job object.438                if (MyInvocation.BoundParameters.ContainsKey(nameof(TimeoutSeconds)))439                {440                    ThrowTerminatingError(441                        new ErrorRecord(442                            new PSArgumentException(InternalCommandStrings.ParallelCannotUseTimeoutWithJob),443                            "ParallelCannotUseTimeoutWithJob",444                            ErrorCategory.InvalidOperation,445                            this));446                }447 448                _taskJob = new PSTaskJob(449                    Parallel.ToString(),450                    ThrottleLimit,451                    UseNewRunspace);452 453                return;454            }455 456            // Set up for synchronous processing and data streaming.457            _taskCollection = new PSDataCollection<System.Management.Automation.PSTasks.PSTask>();458            _taskDataStreamWriter = new PSTaskDataStreamWriter(this);459            _taskPool = new PSTaskPool(ThrottleLimit, UseNewRunspace);460            _taskPool.PoolComplete += (sender, args) => _taskDataStreamWriter.Close();461 462            // Create timeout timer if requested.463            if (TimeoutSeconds != 0)464            {465                _taskTimer = new Timer(466                    callback: (_) => { _taskCollection.Complete(); _taskPool.StopAll(); },467                    state: null,468                    dueTime: TimeoutSeconds * 1000,469                    period: Timeout.Infinite);470            }471 472            // Task collection handler.473            System.Threading.ThreadPool.QueueUserWorkItem(474                (_) =>475                {476                    // As piped input are converted to PSTasks and added to the _taskCollection,477                    // transfer the task to the _taskPool on this dedicated thread.478                    // The _taskPool will block this thread when it is full, and allow more tasks to479                    // be added only when a currently running task completes and makes space in the pool.480                    // Continue adding any tasks appearing in _taskCollection until the collection is closed.481                    while (true)482                    {483                        // This handle will unblock the thread when a new task is available or the _taskCollection484                        // is closed.485                        _taskCollection.WaitHandle.WaitOne();486 487                        // Task collection open state is volatile.488                        // Record current task collection open state here, to be checked after processing.489                        bool isOpen = _taskCollection.IsOpen;490 491                        try492                        {493                            // Read all tasks in the collection.494                            foreach (var task in _taskCollection.ReadAll())495                            {496                                // This _taskPool method will block if the pool is full and will unblock497                                // only after a task completes making more space.498                                _taskPool.Add(task);499                            }500                        }501                        catch (Exception ex)502                        {503                            _taskCollection.Complete();504                            _taskCollectionException = ex;505                            _taskDataStreamWriter.Close();506 507                            break;508                        }509 510                        // Loop is exited only when task collection is closed and all task511                        // collection tasks are processed.512                        if (!isOpen)513                        {514                            break;515                        }516                    }517 518                    // We are done adding tasks and can close the task pool.519                    _taskPool.Close();520                });521        }522 523        private void ProcessParallelParameterSet()524        {525            // Validate piped InputObject526            if (_inputObject != null &&527                _inputObject.BaseObject is ScriptBlock)528            {529                WriteError(530                    new ErrorRecord(531                            new PSArgumentException(InternalCommandStrings.ParallelPipedInputObjectCannotBeScriptBlock),532                            "ParallelPipedInputObjectCannotBeScriptBlock",533                            ErrorCategory.InvalidType,534                            this));535 536                return;537            }538 539            if (AsJob)540            {541                // Add child task job.542                var taskChildJob = new PSTaskChildJob(543                    Parallel,544                    _usingValuesMap,545                    InputObject,546                    _currentLocationPath);547 548                _taskJob.AddJob(taskChildJob);549 550                return;551            }552 553            // Write any streaming data554            _taskDataStreamWriter.WriteImmediate();555 556            // Add to task collection for processing.557            if (_taskCollection.IsOpen)558            {559                try560                {561                    // Create a PSTask based on this piped input and add it to the task collection.562                    // A dedicated thread will add it to the PSTask pool in a performant manner.563                    _taskCollection.Add(564                        new System.Management.Automation.PSTasks.PSTask(565                            Parallel,566                            _usingValuesMap,567                            InputObject,568                            _currentLocationPath,569                            _taskDataStreamWriter));570                }571                catch (InvalidOperationException)572                {573                    // This exception is thrown if the task collection is closed, which should not happen.574                    Dbg.Assert(false, "Should not add to a closed PSTask collection");575                }576            }577        }578 579        private void EndParallelParameterSet()580        {581            if (AsJob)582            {583                // Start and return parent job object.584                _taskJob.Start();585                JobRepository.Add(_taskJob);586                WriteObject(_taskJob);587 588                return;589            }590 591            // Close task collection and wait for processing to complete while streaming data.592            _taskDataStreamWriter.WriteImmediate();593            _taskCollection.Complete();594            _taskDataStreamWriter.WaitAndWrite();595 596            // Check for an unexpected error from the _taskCollection handler thread and report here.597            var ex = _taskCollectionException;598            if (ex != null)599            {600                var msg = string.Format(CultureInfo.InvariantCulture, InternalCommandStrings.ParallelPipedInputProcessingError, ex);601                WriteError(602                    new ErrorRecord(603                        exception: new InvalidOperationException(msg),604                        errorId: "ParallelPipedInputProcessingError",605                        errorCategory: ErrorCategory.InvalidOperation,606                        targetObject: this));607            }608        }609 610        private void StopParallelProcessing()611        {612            _taskCollection?.Complete();613            _taskPool?.StopAll();614        }615 616        #endregion617 618        private void EndBlockParameterSet()619        {620            if (_endScript == null)621            {622                return;623            }624 625            var emptyArray = Array.Empty<object>();626            _endScript.InvokeUsingCmdlet(627                contextCmdlet: this,628                useLocalScope: false,629                errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe,630                dollarUnder: AutomationNull.Value,631                input: emptyArray,632                scriptThis: AutomationNull.Value,633                args: emptyArray);634        }635 636        private void ProcessPropertyAndMethodParameterSet()637        {638            _targetString = string.Format(CultureInfo.InvariantCulture, InternalCommandStrings.ForEachObjectTarget, GetStringRepresentation(InputObject));639 640            if (LanguagePrimitives.IsNull(InputObject))641            {642                if (_arguments != null && _arguments.Length > 0)643                {644                    WriteError(GenerateNameParameterError("InputObject", ParserStrings.InvokeMethodOnNull,645                                                          "InvokeMethodOnNull", _inputObject));646                }647                else648                {649                    // should process650                    string propertyAction = string.Format(CultureInfo.InvariantCulture,651                        InternalCommandStrings.ForEachObjectPropertyAction, _propertyOrMethodName);652 653                    if (ShouldProcess(_targetString, propertyAction))654                    {655                        if (Context.IsStrictVersion(2))656                        {657                            WriteError(GenerateNameParameterError("InputObject", InternalCommandStrings.InputObjectIsNull,658                                                                  "InputObjectIsNull", _inputObject));659                        }660                        else661                        {662                            // we write null out because:663                            // PS C:\> $null | ForEach-object {$_.aa} | ForEach-Object {$_ + 3}664                            // 3665                            // so we also want666                            // PS C:\> $null | ForEach-object aa | ForEach-Object {$_ + 3}667                            // 3668                            // But if we don't write anything to the pipeline when _inputObject is null,669                            // the result 3 will not be generated.670                            WriteObject(null);671                        }672                    }673                }674 675                return;676            }677 678            ErrorRecord errorRecord = null;679 680            // if args exist, this is explicitly a method invocation681            if (_arguments != null && _arguments.Length > 0)682            {683                MethodCallWithArguments();684            }685            // no arg provided686            else687            {688                // if inputObject is of IDictionary, get the value689                if (GetValueFromIDictionaryInput())690                {691                    return;692                }693 694                PSMemberInfo member = null;695                if (WildcardPattern.ContainsWildcardCharacters(_propertyOrMethodName))696                {697                    // get the matched member(s)698                    ReadOnlyPSMemberInfoCollection<PSMemberInfo> members =699                        _inputObject.Members.Match(_propertyOrMethodName, PSMemberTypes.All);700                    Dbg.Assert(members != null, "The return value of Members.Match should never be null");701 702                    if (members.Count > 1)703                    {704                        // write error record: property method ambiguous705                        StringBuilder possibleMatches = new StringBuilder();706                        foreach (PSMemberInfo item in members)707                        {708                            possibleMatches.Append(CultureInfo.InvariantCulture, $" {item.Name}");709                        }710 711                        WriteError(GenerateNameParameterError("Name", InternalCommandStrings.AmbiguousPropertyOrMethodName,712                                                              "AmbiguousPropertyOrMethodName", _inputObject,713                                                              _propertyOrMethodName, possibleMatches));714                        return;715                    }716 717                    if (members.Count == 1)718                    {719                        member = members[0];720                    }721                }722                else723                {724                    member = _inputObject.Members[_propertyOrMethodName];725                }726 727                // member is a method728                if (member is PSMethodInfo)729                {730                    // first we check if the member is a ParameterizedProperty731                    PSParameterizedProperty targetParameterizedProperty = member as PSParameterizedProperty;732                    if (targetParameterizedProperty != null)733                    {734                        // should process735                        string propertyAction = string.Format(CultureInfo.InvariantCulture,736                            InternalCommandStrings.ForEachObjectPropertyAction, targetParameterizedProperty.Name);737 738                        // ParameterizedProperty always take parameters, so we output the member.Value directly739                        if (ShouldProcess(_targetString, propertyAction))740                        {741                            WriteObject(member.Value);742                        }743 744                        return;745                    }746 747                    PSMethodInfo targetMethod = member as PSMethodInfo;748                    Dbg.Assert(targetMethod != null, "targetMethod should not be null here.");749                    try750                    {751                        // should process752                        string methodAction = string.Format(CultureInfo.InvariantCulture,753                            InternalCommandStrings.ForEachObjectMethodActionWithoutArguments, targetMethod.Name);754 755                        if (ShouldProcess(_targetString, methodAction))756                        {757                            if (!BlockMethodInLanguageMode(InputObject))758                            {759                                object result = targetMethod.Invoke(Array.Empty<object>());760                                WriteToPipelineWithUnrolling(result);761                            }762                        }763                    }764                    catch (PipelineStoppedException)765                    {766                        // PipelineStoppedException can be caused by select-object767                        throw;768                    }769                    catch (Exception ex)770                    {771                        MethodException mex = ex as MethodException;772                        if (mex != null && mex.ErrorRecord != null && mex.ErrorRecord.FullyQualifiedErrorId == "MethodCountCouldNotFindBest")773                        {774                            WriteObject(targetMethod.Value);775                        }776                        else777                        {778                            WriteError(new ErrorRecord(ex, "MethodInvocationError", ErrorCategory.InvalidOperation, _inputObject));779                        }780                    }781                }782                else783                {784                    string resolvedPropertyName = null;785                    bool isBlindDynamicAccess = false;786                    if (member == null)787                    {788                        if ((_inputObject.BaseObject is IDynamicMetaObjectProvider) &&789                            !WildcardPattern.ContainsWildcardCharacters(_propertyOrMethodName))790                        {791                            // Let's just try a dynamic property access. Note that if it792                            // comes to depending on dynamic access, we are assuming it is a793                            // property; we don't have ETS info to tell us up front if it794                            // even exists or not, let alone if it is a method or something795                            // else.796                            //797                            // Note that this is "truly blind"--the name did not show up in798                            // GetDynamicMemberNames(), else it would show up as a dynamic799                            // member.800 801                            resolvedPropertyName = _propertyOrMethodName;802                            isBlindDynamicAccess = true;803                        }804                        else805                        {806                            errorRecord = GenerateNameParameterError("Name", InternalCommandStrings.PropertyOrMethodNotFound,807                                                                     "PropertyOrMethodNotFound", _inputObject,808                                                                     _propertyOrMethodName);809                        }810                    }811                    else812                    {813                        // member is [presumably] a property (note that it could be a814                        // dynamic property, if it shows up in GetDynamicMemberNames())815                        resolvedPropertyName = member.Name;816                    }817 818                    if (!string.IsNullOrEmpty(resolvedPropertyName))819                    {820                        // should process821                        string propertyAction = string.Format(CultureInfo.InvariantCulture,822                            InternalCommandStrings.ForEachObjectPropertyAction, resolvedPropertyName);823 824                        if (ShouldProcess(_targetString, propertyAction))825                        {826                            try827                            {828                                WriteToPipelineWithUnrolling(_propGetter.GetValue(InputObject, resolvedPropertyName));829                            }830                            catch (TerminateException) // The debugger is terminating the execution831                            {832                                throw;833                            }834                            catch (MethodException)835                            {836                                throw;837                            }838                            catch (PipelineStoppedException)839                            {840                                // PipelineStoppedException can be caused by select-object841                                throw;842                            }843                            catch (Exception ex)844                            {845                                // For normal property accesses, we do not generate an error846                                // here. The problem for truly blind dynamic accesses (the847                                // member did not show up in GetDynamicMemberNames) is that848                                // we can't tell the difference between "it failed because849                                // the property does not exist" (let's call this case 1) and850                                // "it failed because accessing it actually threw some851                                // exception" (let's call that case 2).852                                //853                                // PowerShell behavior for normal (non-dynamic) properties854                                // is different for these two cases: case 1 gets an error855                                // (which is possible because the ETS tells us up front if856                                // the property exists or not), and case 2 does not. (For857                                // normal properties, this catch block /is/ case 2.)858                                //859                                // For IDMOPs, we have the chance to attempt a "blind"860                                // access, but the cost is that we must have the same861                                // response to both cases (because we cannot distinguish862                                // between the two). So we have to make a choice: we can863                                // either swallow ALL errors (including "The property864                                // 'Blarg' does not exist"), or expose them all.865                                //866                                // Here, for truly blind dynamic access, we choose to867                                // preserve the behavior of showing "The property 'Blarg'868                                // does not exist" (case 1) errors than to suppress869                                // "FooException thrown when accessing Bloop property" (case870                                // 2) errors.871 872                                if (isBlindDynamicAccess)873                                {874                                    errorRecord = new ErrorRecord(ex,875                                                                  "DynamicPropertyAccessFailed_" + _propertyOrMethodName,876                                                                  ErrorCategory.InvalidOperation,877                                                                  InputObject);878                                }879                                else880                                {881                                    // When the property is not gettable or it throws an exception.882                                    // e.g. when trying to access an assembly's location property, since dynamic assemblies are not backed up by a file,883                                    // an exception will be thrown when accessing its location property. In this case, return null.884                                    WriteObject(null);885                                }886                            }887                        }888                    }889                }890            }891 892            if (errorRecord != null)893            {894                string propertyAction = string.Format(CultureInfo.InvariantCulture,895                    InternalCommandStrings.ForEachObjectPropertyAction, _propertyOrMethodName);896 897                if (ShouldProcess(_targetString, propertyAction))898                {899                    if (Context.IsStrictVersion(2))900                    {901                        WriteError(errorRecord);902                    }903                    else904                    {905                        // we write null out because:906                        // PS C:\> "string" | ForEach-Object {$_.aa} | ForEach-Object {$_ + 3}907                        // 3908                        // so we also want909                        // PS C:\> "string" | ForEach-Object aa | ForEach-Object {$_ + 3}910                        // 3911                        // But if we don't write anything to the pipeline when no member is found,912                        // the result 3 will not be generated.913                        WriteObject(null);914                    }915                }916            }917        }918 919        private void ProcessScriptBlockParameterSet()920        {921            for (int i = _start; i < _end; i++)922            {923                // Only execute scripts that aren't null. This isn't treated as an error924                // because it allows you to parameterize a command - for example you might allow925                // for actions before and after the main processing script. They could be null926                // by default and therefore ignored then filled in later...927                _scripts[i]?.InvokeUsingCmdlet(928                    contextCmdlet: this,929                    useLocalScope: false,930                    errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe,931                    dollarUnder: InputObject,932                    input: new object[] { InputObject },933                    scriptThis: AutomationNull.Value,934                    args: Array.Empty<object>());935            }936        }937 938        private void InitScriptBlockParameterSet()939        {940            // Win8: 176403: ScriptCmdlets sets the global WhatIf and Confirm preferences941            // This effects the new W8 foreach-object cmdlet with -whatif and -confirm942            // implemented. -whatif and -confirm needed only for PropertyAndMethodSet943            // parameter set. So erring out in cases where these are used with ScriptBlockSet.944            // Not using MshCommandRuntime, as those variables will be affected by ScriptCmdlet945            // infrastructure (wherein ScriptCmdlet modifies the global preferences).946            Dictionary<string, object> psBoundParameters = this.MyInvocation.BoundParameters;947            if (psBoundParameters != null)948            {949                SwitchParameter whatIf = false;950                SwitchParameter confirm = false;951 952                object argument;953                if (psBoundParameters.TryGetValue("whatif", out argument))954                {955                    whatIf = (SwitchParameter)argument;956                }957 958                if (psBoundParameters.TryGetValue("confirm", out argument))959                {960                    confirm = (SwitchParameter)argument;961                }962 963                if (whatIf || confirm)964                {965                    string message = InternalCommandStrings.NoShouldProcessForScriptBlockSet;966 967                    ErrorRecord errorRecord = new ErrorRecord(968                        new InvalidOperationException(message),969                        "NoShouldProcessForScriptBlockSet",970                        ErrorCategory.InvalidOperation,971                        null);972                    ThrowTerminatingError(errorRecord);973                }974            }975 976            // Calculate the start and end indexes for the processRecord script blocks977            _end = _scripts.Count;978            _start = _scripts.Count > 1 ? 1 : 0;979 980            // and set the end script if it wasn't explicitly set with a named parameter.981            if (!_setEndScript)982            {983                if (_scripts.Count > 2)984                {985                    _end = _scripts.Count - 1;986                    _endScript = _scripts[_end];987                }988            }989 990            // only process the start script if there is more than one script...991            if (_end < 2)992                return;993 994            if (_scripts[0] == null)995                return;996 997            var emptyArray = Array.Empty<object>();998            _scripts[0].InvokeUsingCmdlet(999                contextCmdlet: this,1000                useLocalScope: false,1001                errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe,1002                dollarUnder: AutomationNull.Value,1003                input: emptyArray,1004                scriptThis: AutomationNull.Value,1005                args: emptyArray);1006        }1007 1008        /// <summary>1009        /// Do method invocation with arguments.1010        /// </summary>1011        private void MethodCallWithArguments()1012        {1013            // resolve the name1014            ReadOnlyPSMemberInfoCollection<PSMemberInfo> methods =1015                _inputObject.Members.Match(1016                    _propertyOrMethodName,1017                    PSMemberTypes.Methods | PSMemberTypes.ParameterizedProperty);1018 1019            Dbg.Assert(methods != null, "The return value of Members.Match should never be null.");1020            if (methods.Count > 1)1021            {1022                // write error record: method ambiguous1023                StringBuilder possibleMatches = new StringBuilder();1024                foreach (PSMemberInfo item in methods)1025                {1026                    possibleMatches.Append(CultureInfo.InvariantCulture, $" {item.Name}");1027                }1028 1029                WriteError(GenerateNameParameterError(1030                    "Name",1031                    InternalCommandStrings.AmbiguousMethodName,1032                    "AmbiguousMethodName",1033                    _inputObject,1034                    _propertyOrMethodName,1035                    possibleMatches));1036            }1037            else if (methods.Count == 0 || methods[0] is not PSMethodInfo)1038            {1039                // write error record: method no found1040                WriteError(GenerateNameParameterError(1041                    "Name",1042                    InternalCommandStrings.MethodNotFound,1043                    "MethodNotFound",1044                    _inputObject,1045                    _propertyOrMethodName));1046            }1047            else1048            {1049                PSMethodInfo targetMethod = methods[0] as PSMethodInfo;1050                Dbg.Assert(targetMethod != null, "targetMethod should not be null here.");1051 1052                // should process1053                StringBuilder arglist = new StringBuilder(GetStringRepresentation(_arguments[0]));1054                for (int i = 1; i < _arguments.Length; i++)1055                {1056                    arglist.Append(CultureInfo.InvariantCulture, $", {GetStringRepresentation(_arguments[i])}");1057                }1058 1059                string methodAction = string.Format(CultureInfo.InvariantCulture,1060                    InternalCommandStrings.ForEachObjectMethodActionWithArguments,1061                    targetMethod.Name, arglist);1062 1063                try1064                {1065                    if (ShouldProcess(_targetString, methodAction))1066                    {1067                        if (!BlockMethodInLanguageMode(InputObject))1068                        {1069                            object result = targetMethod.Invoke(_arguments);1070                            WriteToPipelineWithUnrolling(result);1071                        }1072                    }1073                }1074                catch (PipelineStoppedException)1075                {1076                    // PipelineStoppedException can be caused by select-object1077                    throw;1078                }1079                catch (Exception ex)1080                {1081                    WriteError(new ErrorRecord(ex, "MethodInvocationError", ErrorCategory.InvalidOperation, _inputObject));1082                }1083            }1084        }1085 1086        /// <summary>1087        /// Get the string representation of the passed-in object.1088        /// </summary>1089        /// <param name="obj">Source object.</param>1090        /// <returns>String representation of the source object.</returns>1091        private static string GetStringRepresentation(object obj)1092        {1093            string objInString;1094            try1095            {1096                // The "ToString()" method could throw an exception1097                objInString = LanguagePrimitives.IsNull(obj) ? "null" : obj.ToString();1098            }1099            catch (Exception)1100            {1101                objInString = null;1102            }1103 1104            if (string.IsNullOrEmpty(objInString))1105            {1106                var psobj = obj as PSObject;1107                objInString = psobj != null ? psobj.BaseObject.GetType().FullName : obj.GetType().FullName;1108            }1109 1110            return objInString;1111        }1112 1113        /// <summary>1114        /// Get the value by taking _propertyOrMethodName as the key, if the1115        /// input object is a IDictionary.1116        /// </summary>1117        /// <returns>True if success.</returns>1118        private bool GetValueFromIDictionaryInput()1119        {1120            object target = PSObject.Base(_inputObject);1121            IDictionary hash = target as IDictionary;1122 1123            try1124            {1125                if (hash != null && hash.Contains(_propertyOrMethodName))1126                {1127                    string keyAction = string.Format(1128                        CultureInfo.InvariantCulture,1129                        InternalCommandStrings.ForEachObjectKeyAction,1130                        _propertyOrMethodName);1131                    if (ShouldProcess(_targetString, keyAction))1132                    {1133                        object result = hash[_propertyOrMethodName];1134                        WriteToPipelineWithUnrolling(result);1135                    }1136 1137                    return true;1138                }1139            }1140            catch (InvalidOperationException)1141            {1142                // Ignore invalid operation exception, it can happen if the dictionary1143                // has keys that can't be compared to property.1144            }1145 1146            return false;1147        }1148 1149        /// <summary>1150        /// Unroll the object to be output. If it's of type IEnumerator, unroll and output it1151        /// by calling WriteOutIEnumerator. If it's not, unroll and output it by calling WriteObject(obj, true)1152        /// </summary>1153        /// <param name="obj">Source object.</param>1154        private void WriteToPipelineWithUnrolling(object obj)1155        {1156            IEnumerator objAsEnumerator = LanguagePrimitives.GetEnumerator(obj);1157            if (objAsEnumerator != null)1158            {1159                WriteOutIEnumerator(objAsEnumerator);1160            }1161            else1162            {1163                WriteObject(obj, true);1164            }1165        }1166 1167        /// <summary>1168        /// Unroll an IEnumerator and output all entries.1169        /// </summary>1170        /// <param name="list">Source list.</param>1171        private void WriteOutIEnumerator(IEnumerator list)1172        {1173            if (list != null)1174            {1175                while (ParserOps.MoveNext(this.Context, null, list))1176                {1177                    object val = ParserOps.Current(null, list);1178 1179                    if (val != AutomationNull.Value)1180                    {1181                        WriteObject(val);1182                    }1183                }1184            }1185        }1186 1187        /// <summary>1188        /// Check if the language mode is the restrictedLanguageMode before invoking a method.1189        /// Write out error message and return true if we are in restrictedLanguageMode.1190        /// </summary>1191        /// <param name="inputObject">Source object.</param>1192        /// <returns>True if we are in restrictedLanguageMode.</returns>1193        private bool BlockMethodInLanguageMode(object inputObject)1194        {1195            // Cannot invoke a method in RestrictedLanguage mode1196            if (Context.LanguageMode == PSLanguageMode.RestrictedLanguage)1197            {1198                PSInvalidOperationException exception =1199                    new PSInvalidOperationException(InternalCommandStrings.NoMethodInvocationInRestrictedLanguageMode);1200 

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