MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Management.Automation.Runspaces;5using System.Text;6using System.Threading;7 8using Dbg = System.Management.Automation.Diagnostics;9 10namespace System.Management.Automation.Remoting.Internal11{12 /// <summary>13 /// PSStreamObjectType is for internal (PowerShell) consumption and should not be treated as a public API.14 /// </summary>15 public enum PSStreamObjectType16 {17 /// <summary>18 /// </summary>19 Output = 1,20 21 /// <summary>22 /// </summary>23 Error = 2,24 25 /// <summary>26 /// </summary>27 MethodExecutor = 3,28 29 /// <summary>30 /// </summary>31 Warning = 4,32 33 /// <summary>34 /// </summary>35 BlockingError = 5,36 37 /// <summary>38 /// </summary>39 ShouldMethod = 6,40 41 /// <summary>42 /// </summary>43 WarningRecord = 7,44 45 /// <summary>46 /// </summary>47 Debug = 8,48 49 /// <summary>50 /// </summary>51 Progress = 9,52 53 /// <summary>54 /// </summary>55 Verbose = 10,56 57 /// <summary>58 /// </summary>59 Information = 11,60 61 /// <summary>62 /// </summary>63 Exception = 12,64 }65 66 /// <summary>67 /// Struct which describes whether an object written68 /// to an ObjectStream is of type - output, error,69 /// verbose, debug.70 /// PSStreamObject is for internal (PowerShell) consumption71 /// and should not be treated as a public API.72 /// </summary>73 public class PSStreamObject74 {75 /// <summary>76 /// </summary>77 public PSStreamObjectType ObjectType { get; set; }78 79 internal object Value { get; set; }80 81 internal Guid Id { get; set; }82 83 internal PSStreamObject(PSStreamObjectType objectType, object value, Guid id)84 {85 ObjectType = objectType;86 Value = value;87 Id = id;88 }89 90 /// <summary>91 /// </summary>92 /// <param name="objectType"></param>93 /// <param name="value"></param>94 public PSStreamObject(PSStreamObjectType objectType, object value)95 : this(objectType, value, Guid.Empty)96 {97 }98 99 /// <summary>100 /// Handle the object obtained from an ObjectStream's reader101 /// based on its type.102 /// </summary>103 /// <param name="cmdlet">Cmdlet to use for outputting the object.</param>104 /// <param name="overrideInquire">Used by Receive-Job to suppress inquire preference.</param>105 public void WriteStreamObject(Cmdlet cmdlet, bool overrideInquire = false)106 {107 if (cmdlet != null)108 {109 switch (this.ObjectType)110 {111 case PSStreamObjectType.Output:112 {113 cmdlet.WriteObject(this.Value);114 }115 116 break;117 118 case PSStreamObjectType.Error:119 {120 ErrorRecord errorRecord = (ErrorRecord)this.Value;121 errorRecord.PreserveInvocationInfoOnce = true;122 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;123 mshCommandRuntime?.WriteError(errorRecord, overrideInquire);124 }125 126 break;127 128 case PSStreamObjectType.Debug:129 {130 string debug = (string)Value;131 DebugRecord debugRecord = new DebugRecord(debug);132 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;133 mshCommandRuntime?.WriteDebug(debugRecord, overrideInquire);134 }135 136 break;137 138 case PSStreamObjectType.Warning:139 {140 string warning = (string)Value;141 WarningRecord warningRecord = new WarningRecord(warning);142 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;143 mshCommandRuntime?.WriteWarning(warningRecord, overrideInquire);144 }145 146 break;147 148 case PSStreamObjectType.Verbose:149 {150 string verbose = (string)Value;151 VerboseRecord verboseRecord = new VerboseRecord(verbose);152 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;153 mshCommandRuntime?.WriteVerbose(verboseRecord, overrideInquire);154 }155 156 break;157 158 case PSStreamObjectType.Progress:159 {160 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;161 mshCommandRuntime?.WriteProgress((ProgressRecord)Value, overrideInquire);162 }163 164 break;165 166 case PSStreamObjectType.Information:167 {168 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;169 mshCommandRuntime?.WriteInformation((InformationRecord)Value, overrideInquire);170 }171 172 break;173 174 case PSStreamObjectType.WarningRecord:175 {176 WarningRecord warningRecord = (WarningRecord)Value;177 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;178 mshCommandRuntime?.AppendWarningVarList(warningRecord);179 }180 181 break;182 183 case PSStreamObjectType.MethodExecutor:184 {185 Dbg.Assert(this.Value is ClientMethodExecutor,186 "Expected psstreamObject.value is ClientMethodExecutor");187 ClientMethodExecutor methodExecutor = (ClientMethodExecutor)Value;188 methodExecutor.Execute(cmdlet);189 }190 191 break;192 193 case PSStreamObjectType.BlockingError:194 {195 CmdletMethodInvoker<object> methodInvoker = (CmdletMethodInvoker<object>)Value;196 InvokeCmdletMethodAndWaitForResults(methodInvoker, cmdlet);197 }198 199 break;200 201 case PSStreamObjectType.ShouldMethod:202 {203 CmdletMethodInvoker<bool> methodInvoker = (CmdletMethodInvoker<bool>)Value;204 InvokeCmdletMethodAndWaitForResults(methodInvoker, cmdlet);205 }206 207 break;208 209 case PSStreamObjectType.Exception:210 {211 Exception e = (Exception)Value;212 throw e;213 }214 }215 }216 else if (ObjectType == PSStreamObjectType.Exception)217 {218 Exception e = (Exception)Value;219 throw e;220 }221 }222 223 private static void GetIdentifierInfo(string message, out Guid jobInstanceId, out string computerName)224 {225 jobInstanceId = Guid.Empty;226 computerName = string.Empty;227 228 if (message == null)229 {230 return;231 }232 233 string[] parts = message.Split(':', 3);234 235 if (parts.Length != 3)236 {237 return;238 }239 240 if (!Guid.TryParse(parts[0], out jobInstanceId))241 {242 jobInstanceId = Guid.Empty;243 }244 245 computerName = parts[1];246 }247 248 /// <summary>249 /// Handle the object obtained from an ObjectStream's reader250 /// based on its type.251 /// </summary>252 /// <param name="cmdlet">Cmdlet to use for outputting the object.</param>253 /// <param name="instanceId"></param>254 /// <param name="overrideInquire">Suppresses prompt on messages with Inquire preference.255 /// Needed for Receive-Job</param>256 internal void WriteStreamObject(Cmdlet cmdlet, Guid instanceId, bool overrideInquire = false)257 {258 switch (ObjectType)259 {260 case PSStreamObjectType.Output:261 {262 if (instanceId != Guid.Empty)263 {264 PSObject o = Value as PSObject;265 if (o != null)266 AddSourceJobNoteProperty(o, instanceId);267 }268 269 cmdlet.WriteObject(Value);270 }271 272 break;273 274 case PSStreamObjectType.Error:275 {276 ErrorRecord errorRecord = (ErrorRecord)this.Value;277 RemotingErrorRecord remoteErrorRecord = errorRecord as RemotingErrorRecord;278 279 if (remoteErrorRecord == null)280 {281 // if we get a base ErrorRecord object, check if the computerName is282 // populated in the RecommendedAction field283 if (errorRecord.ErrorDetails != null && !string.IsNullOrEmpty(errorRecord.ErrorDetails.RecommendedAction))284 {285 string computerName;286 Guid jobInstanceId;287 GetIdentifierInfo(errorRecord.ErrorDetails.RecommendedAction,288 out jobInstanceId, out computerName);289 290 errorRecord = new RemotingErrorRecord(errorRecord,291 new OriginInfo(computerName, Guid.Empty,292 jobInstanceId));293 }294 }295 else296 {297 errorRecord = remoteErrorRecord;298 }299 300 errorRecord.PreserveInvocationInfoOnce = true;301 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;302 mshCommandRuntime?.WriteError(errorRecord, overrideInquire);303 }304 305 break;306 307 case PSStreamObjectType.Warning:308 {309 string warning = (string)Value;310 WarningRecord warningRecord = new WarningRecord(warning);311 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;312 mshCommandRuntime?.WriteWarning(warningRecord, overrideInquire);313 }314 315 break;316 317 case PSStreamObjectType.Verbose:318 {319 string verbose = (string)Value;320 VerboseRecord verboseRecord = new VerboseRecord(verbose);321 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;322 mshCommandRuntime?.WriteVerbose(verboseRecord, overrideInquire);323 }324 325 break;326 327 case PSStreamObjectType.Progress:328 {329 ProgressRecord progressRecord = (ProgressRecord)Value;330 331 RemotingProgressRecord remotingProgressRecord = progressRecord as RemotingProgressRecord;332 if (remotingProgressRecord == null)333 {334 Guid jobInstanceId;335 string computerName;336 GetIdentifierInfo(progressRecord.CurrentOperation, out jobInstanceId,337 out computerName);338 OriginInfo info = new OriginInfo(computerName, Guid.Empty, jobInstanceId);339 progressRecord = new RemotingProgressRecord(progressRecord, info);340 }341 else342 {343 progressRecord = remotingProgressRecord;344 }345 346 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;347 mshCommandRuntime?.WriteProgress(progressRecord, overrideInquire);348 }349 350 break;351 352 case PSStreamObjectType.Debug:353 {354 string debug = (string)Value;355 DebugRecord debugRecord = new DebugRecord(debug);356 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;357 mshCommandRuntime?.WriteDebug(debugRecord, overrideInquire);358 }359 360 break;361 362 case PSStreamObjectType.Information:363 {364 InformationRecord informationRecord = (InformationRecord)this.Value;365 RemotingInformationRecord remoteInformationRecord = informationRecord as RemotingInformationRecord;366 367 if (remoteInformationRecord == null)368 {369 // if we get a base InformationRecord object, check if the computerName is370 // populated in the Source field371 if (!string.IsNullOrEmpty(informationRecord.Source))372 {373 string computerName;374 Guid jobInstanceId;375 GetIdentifierInfo(informationRecord.Source, out jobInstanceId, out computerName);376 informationRecord = new RemotingInformationRecord(informationRecord,377 new OriginInfo(computerName, Guid.Empty,378 jobInstanceId));379 }380 }381 else382 {383 informationRecord = remoteInformationRecord;384 }385 386 MshCommandRuntime mshCommandRuntime = cmdlet.CommandRuntime as MshCommandRuntime;387 mshCommandRuntime?.WriteInformation(informationRecord, overrideInquire);388 }389 390 break;391 392 case PSStreamObjectType.WarningRecord:393 case PSStreamObjectType.MethodExecutor:394 case PSStreamObjectType.BlockingError:395 case PSStreamObjectType.ShouldMethod:396 {397 WriteStreamObject(cmdlet, overrideInquire);398 }399 400 break;401 }402 }403 404 /// <summary>405 /// Handle the object obtained from an ObjectStream's reader406 /// based on its type.407 /// </summary>408 /// <param name="cmdlet">Cmdlet to use for outputting the object.</param>409 /// <param name="writeSourceIdentifier"></param>410 /// <param name="overrideInquire">Overrides the inquire preference, used in Receive-Job to suppress prompts.</param>411 internal void WriteStreamObject(Cmdlet cmdlet, bool writeSourceIdentifier, bool overrideInquire)412 {413 if (writeSourceIdentifier)414 WriteStreamObject(cmdlet, Id, overrideInquire);415 else416 WriteStreamObject(cmdlet, overrideInquire);417 }418 419 private static void InvokeCmdletMethodAndWaitForResults<T>(CmdletMethodInvoker<T> cmdletMethodInvoker, Cmdlet cmdlet)420 {421 Dbg.Assert(cmdletMethodInvoker != null, "Caller should verify cmdletMethodInvoker != null");422 423 cmdletMethodInvoker.MethodResult = default(T);424 try425 {426 T tmpMethodResult = cmdletMethodInvoker.Action(cmdlet);427 lock (cmdletMethodInvoker.SyncObject)428 {429 cmdletMethodInvoker.MethodResult = tmpMethodResult;430 }431 }432 catch (Exception e)433 {434 lock (cmdletMethodInvoker.SyncObject)435 {436 cmdletMethodInvoker.ExceptionThrownOnCmdletThread = e;437 }438 439 throw;440 }441 finally442 {443 cmdletMethodInvoker.Finished?.Set();444 }445 }446 447 internal static void AddSourceJobNoteProperty(PSObject psObj, Guid instanceId)448 {449 Dbg.Assert(psObj != null, "psObj is null trying to add a note property.");450 if (psObj.Properties[RemotingConstants.SourceJobInstanceId] != null)451 {452 psObj.Properties.Remove(RemotingConstants.SourceJobInstanceId);453 }454 455 psObj.Properties.Add(new PSNoteProperty(RemotingConstants.SourceJobInstanceId, instanceId));456 }457 458 internal static string CreateInformationalMessage(Guid instanceId, string message)459 {460 var newMessage = new StringBuilder(instanceId.ToString());461 newMessage.Append(':');462 newMessage.Append(message);463 464 return newMessage.ToString();465 }466 467 internal static ErrorRecord AddSourceTagToError(ErrorRecord errorRecord, Guid sourceId)468 {469 if (errorRecord == null)470 {471 return null;472 }473 474 errorRecord.ErrorDetails ??= new ErrorDetails(string.Empty);475 errorRecord.ErrorDetails.RecommendedAction = CreateInformationalMessage(sourceId, errorRecord.ErrorDetails.RecommendedAction);476 477 return errorRecord;478 }479 }480}481 482namespace System.Management.Automation.Remoting483{484 /// <summary>485 /// </summary>486 public class CmdletMethodInvoker<T>487 {488 /// <summary>489 /// </summary>490 public Func<Cmdlet, T> Action { get; set; }491 492 /// <summary>493 /// </summary>494 public Exception ExceptionThrownOnCmdletThread { get; set; }495 496 /// <summary>497 /// </summary>498 public ManualResetEventSlim Finished { get; set; }499 500 /// <summary>501 /// </summary>502 public object SyncObject { get; set; }503 504 /// <summary>505 /// </summary>506 public T MethodResult { get; set; }507 }508}509 