MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#region Using directives5 6using System;7using System.Globalization;8using System.Management.Automation;9using System.Threading;10 11#endregion12 13namespace Microsoft.Management.Infrastructure.CimCmdlets14{15 /// <summary>16 /// <para>17 /// Subscription result event args18 /// </para>19 /// </summary>20 internal abstract class CimSubscriptionEventArgs : EventArgs21 {22 /// <summary>23 /// <para>24 /// Returns an Object value for an operation context25 /// </para>26 /// </summary>27 public object Context28 {29 get30 {31 return context;32 }33 }34 35 protected object context;36 }37 38 /// <summary>39 /// <para>40 /// Subscription result event args41 /// </para>42 /// </summary>43 internal class CimSubscriptionResultEventArgs : CimSubscriptionEventArgs44 {45 /// <summary>46 /// <para>47 /// subscription result48 /// </para>49 /// </summary>50 public CimSubscriptionResult Result { get; }51 52 /// <summary>53 /// Initializes a new instance of the <see cref="CimSubscriptionResultEventArgs"/> class.54 /// </summary>55 /// <param name="theResult"></param>56 public CimSubscriptionResultEventArgs(57 CimSubscriptionResult theResult)58 {59 this.context = null;60 this.Result = theResult;61 }62 }63 64 /// <summary>65 /// <para>66 /// Subscription result event args67 /// </para>68 /// </summary>69 internal class CimSubscriptionExceptionEventArgs : CimSubscriptionEventArgs70 {71 /// <summary>72 /// <para>73 /// subscription result74 /// </para>75 /// </summary>76 public Exception Exception { get; }77 78 /// <summary>79 /// Initializes a new instance of the <see cref="CimSubscriptionExceptionEventArgs"/> class.80 /// </summary>81 /// <param name="theResult"></param>82 public CimSubscriptionExceptionEventArgs(83 Exception theException)84 {85 this.context = null;86 this.Exception = theException;87 }88 }89 90 /// <summary>91 /// <para>92 /// Implements operations of register-cimindication cmdlet.93 /// </para>94 /// </summary>95 internal sealed class CimRegisterCimIndication : CimAsyncOperation96 {97 /// <summary>98 /// <para>99 /// New subscription result event100 /// </para>101 /// </summary>102 public event EventHandler<CimSubscriptionEventArgs> OnNewSubscriptionResult;103 104 /// <summary>105 /// Initializes a new instance of the <see cref="CimRegisterCimIndication"/> class.106 /// </summary>107 public CimRegisterCimIndication()108 : base()109 {110 this.ackedEvent = new ManualResetEventSlim(false);111 }112 113 /// <summary>114 /// Start an indication subscription target to the given computer.115 /// </summary>116 /// <param name="computerName">Null stands for localhost.</param>117 /// <param name="nameSpace"></param>118 /// <param name="queryDialect"></param>119 /// <param name="queryExpression"></param>120 /// <param name="operationTimeout"></param>121 public void RegisterCimIndication(122 string computerName,123 string nameSpace,124 string queryDialect,125 string queryExpression,126 uint operationTimeout)127 {128 DebugHelper.WriteLogEx("queryDialect = '{0}'; queryExpression = '{1}'", 0, queryDialect, queryExpression);129 this.TargetComputerName = computerName;130 CimSessionProxy proxy = CreateSessionProxy(computerName, operationTimeout);131 proxy.SubscribeAsync(nameSpace, queryDialect, queryExpression);132 WaitForAckMessage();133 }134 135 /// <summary>136 /// Start an indication subscription through a given <see cref="CimSession"/>.137 /// </summary>138 /// <param name="cimSession">Cannot be null.</param>139 /// <param name="nameSpace"></param>140 /// <param name="queryDialect"></param>141 /// <param name="queryExpression"></param>142 /// <param name="operationTimeout"></param>143 /// <exception cref="ArgumentNullException">Throw if cimSession is null.</exception>144 public void RegisterCimIndication(145 CimSession cimSession,146 string nameSpace,147 string queryDialect,148 string queryExpression,149 uint operationTimeout)150 {151 DebugHelper.WriteLogEx("queryDialect = '{0}'; queryExpression = '{1}'", 0, queryDialect, queryExpression);152 153 ArgumentNullException.ThrowIfNull(cimSession, string.Format(CultureInfo.CurrentUICulture, CimCmdletStrings.NullArgument, nameof(cimSession)));154 155 this.TargetComputerName = cimSession.ComputerName;156 CimSessionProxy proxy = CreateSessionProxy(cimSession, operationTimeout);157 proxy.SubscribeAsync(nameSpace, queryDialect, queryExpression);158 WaitForAckMessage();159 }160 161 #region override methods162 163 /// <summary>164 /// <para>165 /// Subscribe to the events issued by <see cref="CimSessionProxy"/>.166 /// </para>167 /// </summary>168 /// <param name="proxy"></param>169 protected override void SubscribeToCimSessionProxyEvent(CimSessionProxy proxy)170 {171 DebugHelper.WriteLog("SubscribeToCimSessionProxyEvent", 4);172 // Raise event instead of write object to ps173 proxy.OnNewCmdletAction += this.CimIndicationHandler;174 proxy.OnOperationCreated += this.OperationCreatedHandler;175 proxy.OnOperationDeleted += this.OperationDeletedHandler;176 proxy.EnableMethodResultStreaming = false;177 }178 179 /// <summary>180 /// <para>181 /// Handler used to handle new action event from182 /// <seealso cref="CimSessionProxy"/> object.183 /// </para>184 /// </summary>185 /// <param name="cimSession">186 /// <seealso cref="CimSession"/> object raised the event187 /// </param>188 /// <param name="actionArgs">Event argument.</param>189 private void CimIndicationHandler(object cimSession, CmdletActionEventArgs actionArgs)190 {191 DebugHelper.WriteLogEx("action is {0}. Disposed {1}", 0, actionArgs.Action, this.Disposed);192 193 if (this.Disposed)194 {195 return;196 }197 198 // NOTES: should move after this.Disposed, but need to log the exception199 if (actionArgs.Action is CimWriteError cimWriteError)200 {201 this.Exception = cimWriteError.Exception;202 if (!this.ackedEvent.IsSet)203 {204 // an exception happened205 DebugHelper.WriteLogEx("an exception happened", 0);206 this.ackedEvent.Set();207 return;208 }209 210 EventHandler<CimSubscriptionEventArgs> temp = this.OnNewSubscriptionResult;211 if (temp != null)212 {213 DebugHelper.WriteLog("Raise an exception event", 2);214 215 temp(this, new CimSubscriptionExceptionEventArgs(this.Exception));216 }217 218 DebugHelper.WriteLog("Got an exception: {0}", 2, Exception);219 }220 221 if (actionArgs.Action is CimWriteResultObject cimWriteResultObject)222 {223 if (cimWriteResultObject.Result is CimSubscriptionResult result)224 {225 EventHandler<CimSubscriptionEventArgs> temp = this.OnNewSubscriptionResult;226 if (temp != null)227 {228 DebugHelper.WriteLog("Raise an result event", 2);229 temp(this, new CimSubscriptionResultEventArgs(result));230 }231 }232 else233 {234 if (!this.ackedEvent.IsSet)235 {236 // an ACK message returned237 DebugHelper.WriteLogEx("an ack message happened", 0);238 this.ackedEvent.Set();239 return;240 }241 else242 {243 DebugHelper.WriteLogEx("an ack message should not happen here", 0);244 }245 }246 }247 }248 249 /// <summary>250 /// Block the ps thread until ACK message or Error happened.251 /// </summary>252 private void WaitForAckMessage()253 {254 DebugHelper.WriteLogEx();255 this.ackedEvent.Wait();256 if (this.Exception != null)257 {258 DebugHelper.WriteLogEx("error happened", 0);259 if (this.Cmdlet != null)260 {261 DebugHelper.WriteLogEx("Throw Terminating error", 1);262 263 // throw terminating error264 ErrorRecord errorRecord = ErrorToErrorRecord.ErrorRecordFromAnyException(265 new InvocationContext(this.TargetComputerName, null), this.Exception, null);266 this.Cmdlet.ThrowTerminatingError(errorRecord);267 }268 else269 {270 DebugHelper.WriteLogEx("Throw exception", 1);271 // throw exception out272 throw this.Exception;273 }274 }275 276 DebugHelper.WriteLogEx("ACK happened", 0);277 }278 #endregion279 280 #region internal property281 /// <summary>282 /// The cmdlet object who issue this subscription,283 /// to throw ThrowTerminatingError284 /// in case there is a subscription failure.285 /// </summary>286 /// <param name="cmdlet"></param>287 internal Cmdlet Cmdlet288 {289 get;290 set;291 }292 293 /// <summary>294 /// Target computername.295 /// </summary>296 internal string TargetComputerName297 {298 get;299 set;300 }301 302 #endregion303 304 #region private methods305 /// <summary>306 /// <para>307 /// Create <see cref="CimSessionProxy"/> and set properties308 /// </para>309 /// </summary>310 /// <param name="computerName"></param>311 /// <param name="timeout"></param>312 /// <returns></returns>313 private CimSessionProxy CreateSessionProxy(314 string computerName,315 uint timeout)316 {317 CimSessionProxy proxy = CreateCimSessionProxy(computerName);318 proxy.OperationTimeout = timeout;319 return proxy;320 }321 322 /// <summary>323 /// Create <see cref="CimSessionProxy"/> and set properties.324 /// </summary>325 /// <param name="session"></param>326 /// <param name="timeout"></param>327 /// <returns></returns>328 private CimSessionProxy CreateSessionProxy(329 CimSession session,330 uint timeout)331 {332 CimSessionProxy proxy = CreateCimSessionProxy(session);333 proxy.OperationTimeout = timeout;334 return proxy;335 }336 #endregion337 338 #region private members339 340 /// <summary>341 /// Exception occurred while start the subscription.342 /// </summary>343 internal Exception Exception { get; private set; }344 345 #endregion346 347 }348}349 