MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Management.Automation;8using System.Management.Automation.Internal;9using System.Text;10 11using Microsoft.PowerShell.Commands;12 13namespace Microsoft.PowerShell.Commands.Internal.Format14{15 internal static class DefaultScalarTypes16 {17 internal static bool IsTypeInList(Collection<string> typeNames)18 {19 // NOTE: we do not use inheritance here, since we deal with20 // value types or with types where inheritance is not a factor for the selection21 string typeName = PSObjectHelper.PSObjectIsOfExactType(typeNames);22 23 if (string.IsNullOrEmpty(typeName))24 return false;25 26 string originalTypeName = Deserializer.MaskDeserializationPrefix(typeName);27 28 if (string.IsNullOrEmpty(originalTypeName))29 return false;30 31 // check if the type is derived from a System.Enum32 // e.g. in C#33 // enum Foo { Red, Black, Green}34 35 if (PSObjectHelper.PSObjectIsEnum(typeNames))36 return true;37 38 return s_defaultScalarTypesHash.Contains(originalTypeName);39 }40 41 static DefaultScalarTypes()42 {43 s_defaultScalarTypesHash.Add("System.String");44 s_defaultScalarTypesHash.Add("System.SByte");45 s_defaultScalarTypesHash.Add("System.Byte");46 s_defaultScalarTypesHash.Add("System.Int16");47 s_defaultScalarTypesHash.Add("System.UInt16");48 s_defaultScalarTypesHash.Add("System.Int32");49 s_defaultScalarTypesHash.Add("System.UInt32");50 s_defaultScalarTypesHash.Add("System.Int64");51 s_defaultScalarTypesHash.Add("System.UInt64");52 s_defaultScalarTypesHash.Add("System.Char");53 s_defaultScalarTypesHash.Add("System.Single");54 s_defaultScalarTypesHash.Add("System.Double");55 s_defaultScalarTypesHash.Add("System.Boolean");56 s_defaultScalarTypesHash.Add("System.Decimal");57 s_defaultScalarTypesHash.Add("System.IntPtr");58 s_defaultScalarTypesHash.Add("System.Security.SecureString");59 s_defaultScalarTypesHash.Add("System.Numerics.BigInteger");60 }61 62 private static readonly HashSet<string> s_defaultScalarTypesHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);63 }64 65 /// <summary>66 /// Class to manage the selection of a desired view type and67 /// manage state associated to the selected view.68 /// </summary>69 internal sealed class FormatViewManager70 {71 #region tracer72 [TraceSource("FormatViewBinding", "Format view binding")]73 private static readonly PSTraceSource s_formatViewBindingTracer = PSTraceSource.GetTracer("FormatViewBinding", "Format view binding", false);74 #endregion tracer75 76 private static string PSObjectTypeName(PSObject so)77 {78 // if so is not null, its TypeNames will not be null79 if (so != null)80 {81 var typeNames = so.InternalTypeNames;82 if (typeNames.Count > 0)83 {84 return typeNames[0];85 }86 }87 88 return string.Empty;89 }90 91 internal void Initialize(TerminatingErrorContext errorContext,92 PSPropertyExpressionFactory expressionFactory,93 TypeInfoDataBase db,94 PSObject so,95 FormatShape shape,96 FormattingCommandLineParameters parameters)97 {98 ViewDefinition view = null;99 const string findViewType = "FINDING VIEW TYPE: {0}";100 const string findViewShapeType = "FINDING VIEW {0} TYPE: {1}";101 const string findViewNameType = "FINDING VIEW NAME: {0} TYPE: {1}";102 const string viewFound = "An applicable view has been found";103 const string viewNotFound = "No applicable view has been found";104 try105 {106 DisplayDataQuery.SetTracer(s_formatViewBindingTracer);107 108 // shape not specified: we need to select one109 var typeNames = so.InternalTypeNames;110 if (shape == FormatShape.Undefined)111 {112 using (s_formatViewBindingTracer.TraceScope(findViewType, PSObjectTypeName(so)))113 {114 view = DisplayDataQuery.GetViewByShapeAndType(expressionFactory, db, shape, typeNames, null);115 }116 117 if (view != null)118 {119 // we got a matching view from the database120 // use this and we are done121 _viewGenerator = SelectViewGeneratorFromViewDefinition(122 errorContext,123 expressionFactory,124 db,125 view,126 parameters);127 s_formatViewBindingTracer.WriteLine(viewFound);128 PrepareViewForRemoteObjects(ViewGenerator, so);129 return;130 }131 132 s_formatViewBindingTracer.WriteLine(viewNotFound);133 // we did not get any default view (and shape), we need to force one134 // we just select properties out of the object itself, since they were not135 // specified on the command line136 _viewGenerator = SelectViewGeneratorFromProperties(shape, so, errorContext, expressionFactory, db, null);137 PrepareViewForRemoteObjects(ViewGenerator, so);138 139 return;140 }141 142 // we have a predefined shape: did the user specify properties on the command line?143 if (parameters != null && parameters.mshParameterList.Count > 0)144 {145 _viewGenerator = SelectViewGeneratorFromProperties(shape, so, errorContext, expressionFactory, db, parameters);146 return;147 }148 149 // predefined shape: did the user specify the name of a view?150 if (parameters != null && !string.IsNullOrEmpty(parameters.viewName))151 {152 using (s_formatViewBindingTracer.TraceScope(findViewNameType, parameters.viewName,153 PSObjectTypeName(so)))154 {155 view = DisplayDataQuery.GetViewByShapeAndType(expressionFactory, db, shape, typeNames, parameters.viewName);156 }157 158 if (view != null)159 {160 _viewGenerator = SelectViewGeneratorFromViewDefinition(161 errorContext,162 expressionFactory,163 db,164 view,165 parameters);166 s_formatViewBindingTracer.WriteLine(viewFound);167 return;168 }169 170 s_formatViewBindingTracer.WriteLine(viewNotFound);171 // illegal input, we have to terminate172 ProcessUnknownViewName(errorContext, parameters.viewName, so, db, shape);173 }174 175 // predefined shape: do we have a default view in format.ps1xml?176 using (s_formatViewBindingTracer.TraceScope(findViewShapeType, shape, PSObjectTypeName(so)))177 {178 view = DisplayDataQuery.GetViewByShapeAndType(expressionFactory, db, shape, typeNames, null);179 }180 181 if (view != null)182 {183 _viewGenerator = SelectViewGeneratorFromViewDefinition(184 errorContext,185 expressionFactory,186 db,187 view,188 parameters);189 s_formatViewBindingTracer.WriteLine(viewFound);190 PrepareViewForRemoteObjects(ViewGenerator, so);191 192 return;193 }194 195 s_formatViewBindingTracer.WriteLine(viewNotFound);196 // we just select properties out of the object itself197 _viewGenerator = SelectViewGeneratorFromProperties(shape, so, errorContext, expressionFactory, db, parameters);198 PrepareViewForRemoteObjects(ViewGenerator, so);199 }200 finally201 {202 DisplayDataQuery.ResetTracer();203 }204 }205 206 /// <summary>207 /// Prepares a given view for remote object processing ie., lets the view208 /// display (or not) ComputerName property. This will query the object to209 /// check if ComputerName property is present. If present, this will prepare210 /// the view.211 /// </summary>212 /// <param name="viewGenerator"></param>213 /// <param name="so"></param>214 private static void PrepareViewForRemoteObjects(ViewGenerator viewGenerator, PSObject so)215 {216 if (PSObjectHelper.ShouldShowComputerNameProperty(so))217 {218 viewGenerator.PrepareForRemoteObjects(so);219 }220 }221 222 /// <summary>223 /// Helper method to process Unknown error message.224 /// It helps is creating appropriate error message to225 /// be displayed to the user.226 /// </summary>227 /// <param name="errorContext">Error context.</param>228 /// <param name="viewName">Uses supplied view name.</param>229 /// <param name="so">Source object.</param>230 /// <param name="db">Types info database.</param>231 /// <param name="formatShape">Requested format shape.</param>232 private static void ProcessUnknownViewName(TerminatingErrorContext errorContext, string viewName, PSObject so, TypeInfoDataBase db, FormatShape formatShape)233 {234 string msg = null;235 bool foundValidViews = false;236 string formatTypeName = null;237 const string separator = ", ";238 StringBuilder validViewFormats = new StringBuilder();239 240 if (so != null && so.BaseObject != null &&241 db != null && db.viewDefinitionsSection != null &&242 db.viewDefinitionsSection.viewDefinitionList != null &&243 db.viewDefinitionsSection.viewDefinitionList.Count > 0)244 {245 StringBuilder validViews = new StringBuilder();246 string currentObjectTypeName = so.BaseObject.GetType().ToString();247 248 Type formatType = null;249 if (formatShape == FormatShape.Table)250 {251 formatType = typeof(TableControlBody);252 formatTypeName = "Table";253 }254 else if (formatShape == FormatShape.List)255 {256 formatType = typeof(ListControlBody);257 formatTypeName = "List";258 }259 else if (formatShape == FormatShape.Wide)260 {261 formatType = typeof(WideControlBody);262 formatTypeName = "Wide";263 }264 else if (formatShape == FormatShape.Complex)265 {266 formatType = typeof(ComplexControlBody);267 formatTypeName = "Custom";268 }269 270 if (formatType != null)271 {272 foreach (ViewDefinition currentViewDefinition in db.viewDefinitionsSection.viewDefinitionList)273 {274 if (currentViewDefinition.mainControl != null)275 {276 foreach (TypeOrGroupReference currentTypeOrGroupReference in currentViewDefinition.appliesTo.referenceList)277 {278 if (!string.IsNullOrEmpty(currentTypeOrGroupReference.name) &&279 string.Equals(currentObjectTypeName, currentTypeOrGroupReference.name, StringComparison.OrdinalIgnoreCase))280 {281 if (currentViewDefinition.mainControl.GetType() == formatType)282 {283 validViews.Append(currentViewDefinition.name);284 validViews.Append(separator);285 }286 else if (string.Equals(viewName, currentViewDefinition.name, StringComparison.OrdinalIgnoreCase))287 {288 string cmdletFormatName = null;289 if (currentViewDefinition.mainControl is TableControlBody)290 {291 cmdletFormatName = "Format-Table";292 }293 else if (currentViewDefinition.mainControl is ListControlBody)294 {295 cmdletFormatName = "Format-List";296 }297 else if (currentViewDefinition.mainControl is WideControlBody)298 {299 cmdletFormatName = "Format-Wide";300 }301 else if (currentViewDefinition.mainControl is ComplexControlBody)302 {303 cmdletFormatName = "Format-Custom";304 }305 306 if (validViewFormats.Length == 0)307 {308 string suggestValidViewNamePrefix = StringUtil.Format(FormatAndOut_format_xxx.SuggestValidViewNamePrefix);309 validViewFormats.Append(suggestValidViewNamePrefix);310 }311 else312 {313 validViewFormats.Append(", ");314 }315 316 validViewFormats.Append(cmdletFormatName);317 }318 }319 }320 }321 }322 }323 324 if (validViews.Length > 0)325 {326 validViews.Remove(validViews.Length - separator.Length, separator.Length);327 msg = StringUtil.Format(FormatAndOut_format_xxx.InvalidViewNameError, viewName, formatTypeName, validViews.ToString());328 foundValidViews = true;329 }330 }331 332 if (!foundValidViews)333 {334 StringBuilder unKnowViewFormatStringBuilder = new StringBuilder();335 if (validViewFormats.Length > 0)336 {337 // unKnowViewFormatStringBuilder.Append(StringUtil.Format(FormatAndOut_format_xxx.UnknownViewNameError, viewName));338 unKnowViewFormatStringBuilder.Append(StringUtil.Format(FormatAndOut_format_xxx.UnknownViewNameErrorSuffix, viewName, formatTypeName));339 unKnowViewFormatStringBuilder.Append(validViewFormats);340 }341 else342 {343 unKnowViewFormatStringBuilder.Append(StringUtil.Format(FormatAndOut_format_xxx.UnknownViewNameError, viewName));344 unKnowViewFormatStringBuilder.Append(StringUtil.Format(FormatAndOut_format_xxx.NonExistingViewNameError, formatTypeName, so.BaseObject.GetType()));345 }346 347 msg = unKnowViewFormatStringBuilder.ToString();348 }349 350 ErrorRecord errorRecord = new ErrorRecord(351 new PipelineStoppedException(),352 "FormatViewNotFound",353 ErrorCategory.ObjectNotFound,354 viewName);355 356 errorRecord.ErrorDetails = new ErrorDetails(msg);357 errorContext.ThrowTerminatingError(errorRecord);358 }359 360 internal ViewGenerator ViewGenerator361 {362 get363 {364 Diagnostics.Assert(_viewGenerator != null, "this.viewGenerator cannot be null");365 return _viewGenerator;366 }367 }368 369 private static ViewGenerator SelectViewGeneratorFromViewDefinition(370 TerminatingErrorContext errorContext,371 PSPropertyExpressionFactory expressionFactory,372 TypeInfoDataBase db,373 ViewDefinition view,374 FormattingCommandLineParameters parameters)375 {376 ViewGenerator viewGenerator = null;377 if (view.mainControl is TableControlBody)378 {379 viewGenerator = new TableViewGenerator();380 }381 else if (view.mainControl is ListControlBody)382 {383 viewGenerator = new ListViewGenerator();384 }385 else if (view.mainControl is WideControlBody)386 {387 viewGenerator = new WideViewGenerator();388 }389 else if (view.mainControl is ComplexControlBody)390 {391 viewGenerator = new ComplexViewGenerator();392 }393 394 Diagnostics.Assert(viewGenerator != null, "viewGenerator != null");395 viewGenerator.Initialize(errorContext, expressionFactory, db, view, parameters);396 return viewGenerator;397 }398 399 private static ViewGenerator SelectViewGeneratorFromProperties(FormatShape shape, PSObject so,400 TerminatingErrorContext errorContext,401 PSPropertyExpressionFactory expressionFactory,402 TypeInfoDataBase db,403 FormattingCommandLineParameters parameters)404 {405 // use some heuristics to determine the shape if none is specified406 if (shape == FormatShape.Undefined && parameters == null)407 {408 // check first if we have a known shape for a type409 var typeNames = so.InternalTypeNames;410 shape = DisplayDataQuery.GetShapeFromType(expressionFactory, db, typeNames);411 412 if (shape == FormatShape.Undefined)413 {414 // check if we can have a table:415 // we want to get the # of properties we are going to display416 List<PSPropertyExpression> expressionList = PSObjectHelper.GetDefaultPropertySet(so);417 if (expressionList.Count == 0)418 {419 // we failed to get anything from a property set420 // we just get the first properties out of the first object421 foreach (MshResolvedExpressionParameterAssociation mrepa in AssociationManager.ExpandAll(so))422 {423 expressionList.Add(mrepa.ResolvedExpression);424 }425 }426 427 // decide what shape we want for the given number of properties428 shape = DisplayDataQuery.GetShapeFromPropertyCount(db, expressionList.Count);429 }430 }431 432 ViewGenerator viewGenerator = null;433 if (shape == FormatShape.Table)434 {435 viewGenerator = new TableViewGenerator();436 }437 else if (shape == FormatShape.List)438 {439 viewGenerator = new ListViewGenerator();440 }441 else if (shape == FormatShape.Wide)442 {443 viewGenerator = new WideViewGenerator();444 }445 else if (shape == FormatShape.Complex)446 {447 viewGenerator = new ComplexViewGenerator();448 }449 450 Diagnostics.Assert(viewGenerator != null, "viewGenerator != null");451 452 viewGenerator.Initialize(errorContext, expressionFactory, so, db, parameters);453 return viewGenerator;454 }455 456 /// <summary>457 /// The view generator that produced data for a selected shape.458 /// </summary>459 private ViewGenerator _viewGenerator = null;460 }461 462 /// <summary>463 /// Class to manage the selection of a desired view type464 /// for out of band objects.465 /// </summary>466 internal static class OutOfBandFormatViewManager467 {468 private static bool IsNotRemotingProperty(string name)469 {470 var isRemotingPropertyName = name.Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase)471 || name.Equals(RemotingConstants.ShowComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase)472 || name.Equals(RemotingConstants.RunspaceIdNoteProperty, StringComparison.OrdinalIgnoreCase)473 || name.Equals(RemotingConstants.SourceJobInstanceId, StringComparison.OrdinalIgnoreCase);474 return !isRemotingPropertyName;475 }476 477 private static readonly MemberNamePredicate NameIsNotRemotingProperty = IsNotRemotingProperty;478 479 internal static bool HasNonRemotingProperties(PSObject so) => so.GetFirstPropertyOrDefault(NameIsNotRemotingProperty) != null;480 481 internal static FormatEntryData GenerateOutOfBandData(TerminatingErrorContext errorContext, PSPropertyExpressionFactory expressionFactory,482 TypeInfoDataBase db, PSObject so, int enumerationLimit, bool useToStringFallback, out List<ErrorRecord> errors)483 {484 errors = null;485 486 var typeNames = so.InternalTypeNames;487 ViewDefinition view = DisplayDataQuery.GetOutOfBandView(expressionFactory, db, typeNames);488 489 ViewGenerator outOfBandViewGenerator;490 if (view != null)491 {492 // process an out of band view retrieved from the display database493 if (view.mainControl is ComplexControlBody)494 {495 outOfBandViewGenerator = new ComplexViewGenerator();496 }497 else498 {499 outOfBandViewGenerator = new ListViewGenerator();500 }501 502 outOfBandViewGenerator.Initialize(errorContext, expressionFactory, db, view, null);503 }504 else505 {506 if (DefaultScalarTypes.IsTypeInList(typeNames)507 || !HasNonRemotingProperties(so))508 {509 // we force a ToString() on well known types510 return GenerateOutOfBandObjectAsToString(so);511 }512 513 if (!useToStringFallback)514 {515 return null;516 }517 518 // we must check we have enough properties for a list view519 if (new PSPropertyExpression("*").ResolveNames(so).Count == 0)520 {521 return null;522 }523 524 // we do not have a view, we default to list view525 // process an out of band view as a default526 outOfBandViewGenerator = new ListViewGenerator();527 outOfBandViewGenerator.Initialize(errorContext, expressionFactory, so, db, null);528 }529 530 FormatEntryData fed = outOfBandViewGenerator.GeneratePayload(so, enumerationLimit);531 fed.outOfBand = true;532 fed.writeStream = so.WriteStream;533 534 errors = outOfBandViewGenerator.ErrorManager.DrainFailedResultList();535 536 return fed;537 }538 539 internal static FormatEntryData GenerateOutOfBandObjectAsToString(PSObject so)540 {541 FormatEntryData fed = new FormatEntryData();542 fed.outOfBand = true;543 544 RawTextFormatEntry rawTextEntry = new RawTextFormatEntry();545 rawTextEntry.text = so.ToString();546 fed.formatEntryInfo = rawTextEntry;547 548 return fed;549 }550 }551 552 /// <summary>553 /// Helper class to manage the logging of errors resulting from554 /// evaluations of PSPropertyExpression instances555 ///556 /// Depending on settings, it queues the failing PSPropertyExpressionResult557 /// instances and generates a list of out-of-band FormatEntryData558 /// objects to be sent to the output pipeline.559 /// </summary>560 internal sealed class FormatErrorManager561 {562 internal FormatErrorManager(FormatErrorPolicy formatErrorPolicy)563 {564 _formatErrorPolicy = formatErrorPolicy;565 }566 567 /// <summary>568 /// Log a failed evaluation of an PSPropertyExpression.569 /// </summary>570 /// <param name="result">PSPropertyExpressionResult containing the failed evaluation data.</param>571 /// <param name="sourceObject">Object used to evaluate the PSPropertyExpression.</param>572 internal void LogPSPropertyExpressionFailedResult(PSPropertyExpressionResult result, object sourceObject)573 {574 if (!_formatErrorPolicy.ShowErrorsAsMessages)575 return;576 PSPropertyExpressionError error = new PSPropertyExpressionError();577 error.result = result;578 error.sourceObject = sourceObject;579 _formattingErrorList.Add(error);580 }581 582 /// <summary>583 /// Log a failed formatting operation.584 /// </summary>585 /// <param name="error">String format error object.</param>586 internal void LogStringFormatError(StringFormatError error)587 {588 if (!_formatErrorPolicy.ShowErrorsAsMessages)589 return;590 _formattingErrorList.Add(error);591 }592 593 internal bool DisplayErrorStrings594 {595 get { return _formatErrorPolicy.ShowErrorsInFormattedOutput; }596 }597 598 internal bool DisplayFormatErrorString599 {600 get601 {602 // NOTE: we key off the same flag603 return this.DisplayErrorStrings;604 }605 }606 607 internal string ErrorString608 {609 get { return _formatErrorPolicy.errorStringInFormattedOutput; }610 }611 612 internal string FormatErrorString613 {614 get { return _formatErrorPolicy.formatErrorStringInFormattedOutput; }615 }616 617 /// <summary>618 /// Provide a list of ErrorRecord entries619 /// to be written to the error pipeline and clear the list of pending620 /// errors.621 /// </summary>622 /// <returns>List of ErrorRecord objects.</returns>623 internal List<ErrorRecord> DrainFailedResultList()624 {625 if (!_formatErrorPolicy.ShowErrorsAsMessages)626 return null;627 628 List<ErrorRecord> retVal = new List<ErrorRecord>();629 foreach (FormattingError error in _formattingErrorList)630 {631 ErrorRecord errorRecord = GenerateErrorRecord(error);632 if (errorRecord != null)633 retVal.Add(errorRecord);634 }635 636 _formattingErrorList.Clear();637 return retVal;638 }639 640 /// <summary>641 /// Conversion between an error internal representation and ErrorRecord.642 /// </summary>643 /// <param name="error">Internal error object.</param>644 /// <returns>Corresponding ErrorRecord instance.</returns>645 private static ErrorRecord GenerateErrorRecord(FormattingError error)646 {647 ErrorRecord errorRecord = null;648 string msg = null;649 if (error is PSPropertyExpressionError psPropertyExpressionError)650 {651 errorRecord = new ErrorRecord(652 psPropertyExpressionError.result.Exception,653 "PSPropertyExpressionError",654 ErrorCategory.InvalidArgument,655 psPropertyExpressionError.sourceObject);656 657 msg = StringUtil.Format(FormatAndOut_format_xxx.PSPropertyExpressionError,658 psPropertyExpressionError.result.ResolvedExpression.ToString());659 errorRecord.ErrorDetails = new ErrorDetails(msg);660 }661 662 if (error is StringFormatError formattingError)663 {664 errorRecord = new ErrorRecord(665 formattingError.exception,666 "formattingError",667 ErrorCategory.InvalidArgument,668 formattingError.sourceObject);669 670 msg = StringUtil.Format(FormatAndOut_format_xxx.FormattingError,671 formattingError.formatString);672 errorRecord.ErrorDetails = new ErrorDetails(msg);673 }674 675 return errorRecord;676 }677 678 private readonly FormatErrorPolicy _formatErrorPolicy;679 680 /// <summary>681 /// Current list of failed PSPropertyExpression evaluations.682 /// </summary>683 private readonly List<FormattingError> _formattingErrorList = new List<FormattingError>();684 }685}686 